找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2236|回复: 4
打印 上一主题 下一主题
收起左侧

单片机LCD12864全是翱,拿手碰一下才会正常显示

[复制链接]
跳转到指定楼层
楼主
ID:658517 发表于 2019-12-18 17:50 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
写的程序前几天运行都是正确的,今天运行就全是翱字,拿手碰一下才会正常显示
#include "msp430f149.h"
typedef unsigned char uchar;   //给个新名字代替,这里不涉及struct
typedef unsigned int  uint;    //在有指针的场合,typedef要比#define好,无符号类型能保存2倍于有符号类型的正整数数据
//DS18B20端口设置
#define DQ1    P2OUT|=BIT4        //DQ置位
#define DQ0    P2OUT&=~BIT4       //DQ复位
#define DQ_in  P2DIR&=~BIT4       //设DQ为输入
#define DQ_out P2DIR|=BIT4        //设DQ为输出
#define DQ_val (P2IN&BIT4)        //读DQ电平
//通过定时器A实现精确的N个微秒的延时,因为DS18B20是one-wire类型,对时间的要求非常严格
void DelayNus(uint n)
{
    TACTL|=TASSEL_2+ID_3+MC_1;    //SMCLK,8分频,增计数模式
    //CCTL0|=CCIE;                //中断允许
    CCR0=n;                       //CCR0=1时捕捉的是1us(n/1M)
    while(!(TACTL&BIT0));         //等待定时Nus后置位中断标志TAIFG  while(!TAIFG) 1即有中断发生
    TACTL=TACLR;                  //停止计数,在于清除了计数器设置,TACLR=1
    TACTL&=~BIT0;                 //清除中断标志TAIFG
}
//初始化DS18B20,等待DS18B20回复一个presence pulse,若在60-240us内读到回复的脉冲信号,表示DS18B20存在
uchar Init_18B20(void)
{
            uchar flag;           //定义一标志信号,1失败,0成功,
            DQ_out;               //设置DQ为输出,可不要
            DQ0;                  //拉低总线
            DelayNus(500);        //延时500us,产生复位脉冲(480-960)
            DQ1;                  //释放总线
            DelayNus(65);         //等待15-60us,且要在60-240us内读到返回的脉冲信号,计算后得到延时时间最好要在60-75us
            DQ_in;                //DQ设置为输入状态,以读取DS18B20存在状态,必须要有
            DelayNus(5);          //短暂延时一下确保读取成功
            if(DQ_val)            //若读到高电平则无DS18b20
            {
              flag=1;             //初始化失败
            }
            else
            {
              flag=0;             //初始化成功
            }
            DQ_out;               //设置DQ为输出,必须要有
            DQ1;                  //释放总线
            DelayNus(400);        //>=480us
            return flag;          //返回标志信号
}
//单片机向DS18B20写入一个字节的数据,内部具体包括写0、1
void Write_18B20(uchar wdata)
{
    uchar i;
    for(i=0x01;i!=0;i<<=1)     //一个字共有8位,读写都从低位开始
    {
        DQ0;                   //拉低总线,
        DelayNus(5);           //延时5us,至少1us
        if((wdata&i)==0)       //满足则末尾是0,即写入的是0
           DQ0;                //写0单片机输出低电平
        else                   //不满足就是末尾为1,即写入1
           DQ1;                //写1单片机输出高电平
        DelayNus(50);          //15-60us
        DQ1;                   //释放总线,等待总线恢复
        DelayNus(10);          //延时10us
    }
}
//单片机从DS18B20读取一个字节(8bit)的数据
uchar Read_18B20(void)
{
    uchar i;                  //当作检测信号
    uchar temp;               //temp用于存储从DS18B20读取出来的8位数据
    for(i=0x01;i!=0;i<<=1)
    {
        DQ0;                   //拉低总线,产生读信号
        DelayNus(5);           //延时5us,至少1us
        DQ1;                   //释放总线,准备读数据
        DelayNus(5);           //延时5us
        DQ_in;                 //设置为输入状态,以读取数据
        _NOP();                //必须在15us内读取DS18B20发送的数据位
        if(DQ_val)
        {
                temp=temp|i;       //读1就写1
        }
        else
        {
                temp=temp&(~i);    //读0就写0
        }
        DelayNus(45);          //延时45us
        DQ_out;                //设置端口为输出
        DQ1;                   //释放总线
        DelayNus(10);
    }
    return temp;               //返回从DS18B20读出的8位数据
}
//让DS18B20开始转换温度
void ChangeTemp(void)
{
    uchar i;
        Init_18B20();
        Write_18B20(0xcc);     //跳过ROM配置(skip rom),单线直接这样设置
        Write_18B20(0x44);     //启动温度转换(默认值+85),有了这句话才会开始测量温度
    for(i=20;i>0;i--)
    DelayNus(60000);       //延时800ms以上,若是一直刷着,就不用这个延时
                           //一分钟延时就可以一分钟检测一次
}
//发送读取温度命令
void ReadTempCom(void)
{
        Init_18B20();
    Write_18B20(0xcc);     //都需要3步(1.初始化2.rom设置3.写字节)
    Write_18B20(0xbe);     //发送读ScratchPad命令
}
//从DS18B20的ScratchPad读取温度转换结果
uint Do1Convert(void)
{
    uchar i;
    uchar temp_l;               //char是8bit,先存放低位
    uint realtemp;              //int是16bit
    do
    {
       i=Init_18B20();          //把flag的值赋给I,判断是否初始换成功
    }
    while(i);                   //0成功跳出
        ChangeTemp();                   //先写转换命令
        ReadTempCom();                  //然后等待转换完后发送读取温度命令
        temp_l=Read_18B20();            //读取温度值共16位,必须先读低字节
        realtemp=Read_18B20();          //读高位
        realtemp=(realtemp<<8)|temp_l;  //高8位先左移8位后再与低位相或得16位的温度值
        return realtemp;                //返回读取的温度值
}


#include "msp430f149.h"
typedef unsigned char uchar;
typedef unsigned int  uint;
//LCD12864端口配置
#define LCD_RS_H      P3OUT|=BIT0      //数据
#define LCD_RS_L      P3OUT&=~BIT0     //指令
#define LCD_RW_H      P3OUT|=BIT1      //读
#define LCD_RW_L      P3OUT&=~BIT1     //写
#define LCD_EN_H      P3OUT|=BIT2      //使能开
#define LCD_EN_L      P3OUT&=~BIT2     //使能关
#define LCD_DataIn    P4DIR=0x00       //数据口方向设置为输入
#define LCD_DataOut   P4DIR=0xff       //数据口方向设置为输出
#define LCD2MCU_Data  P4IN             //LCD向单片机输入数据
#define MCU2LCD_Data  P4OUT            //单片机向LCD输出数据
#define LCD_CMDOut    P3DIR|=0x07      //P3口的低三位(RS,RW,EN)设置为输出
#define LCD_PSB_H     P3OUT|=BIT3      //并行
#define LCD_PSB_L     P3OUT&=~BIT3     //串行
#define LCD_RST_L     P3OUT&=~BIT4     //复位  低电平有效
//延时约1ms程序
void Delay_1ms(void)
{
        uchar i;
        for(i=150;i>0;i--);
    _NOP();               //延时几us,自带函数,用于短暂延时
}
//延时N个1ms的时间
void Delay_Nms(uint n)
{
    uint i;
    for(i=n;i>0;i--)
    Delay_1ms();
}
//判忙
void Check_Busy(void)
{
    uchar lcdtemp = 0;
    LCD_CMDOut;             //P3口的低三位设置为输出
    LCD_RS_L;               //命令
    LCD_RW_H;               //读
    LCD_DataIn;             //P4端口设置为输出
    do                      //判忙判断的是最高位数据
    {
       LCD_EN_H;
       _NOP();
       lcdtemp = LCD2MCU_Data;  //读取LCD忙碌状态
       LCD_EN_L;
    }
    while(lcdtemp&0x80);        //若为0表示不忙,一直等到LCD不忙(即最高位是0)才跳出函数
}
//写命令
void Write_Cmd(uchar cmd)
{
    Check_Busy();           //判忙
    LCD_DataOut;
    LCD_RS_L;               //命令
    LCD_RW_L;               //写
    MCU2LCD_Data=cmd;       //将命令写入端口
    LCD_EN_H;
    _NOP();
    LCD_EN_L;
}
//写数据
void  Write_Data(uchar dat)
{
    Check_Busy();
    LCD_DataOut;
    LCD_RS_H;
    LCD_RW_L;
    MCU2LCD_Data=dat;
    LCD_EN_H;
    _NOP();
    LCD_EN_L;
}
void Disp_HZ(uchar addr,const uchar * pt,uchar num)
{
    uchar i;

    Write_Cmd(addr);
           for(i = 0;i < (num*2);i++)
        Write_Data(*(pt++));
}
/*****读数据
uchar Read_Data(void)
{
  uchar RData;
  LCD_DataIn;
  Check_Busy();
  LCD_RS_H;
  LCD_RW_H;
  LCD_EN_L;
  LCD_EN_H;
  RData=LCD2MCU_Data;    //寄存数据
  LCD_EN_L;
  return RData;          //返回读到的数据
}
*****/
//初始化液晶显示屏
void Init_Lcd(void)
{
        //LCD_RST_L;          //复位
        LCD_PSB_H;          //并行
    LCD_CMDOut;         //液晶控制端口设置为输出
    Delay_Nms(500);
    Write_Cmd(0x30);    //基本指令集
    Delay_1ms();
    Write_Cmd(0x02);    // 地址归位
    Delay_1ms();
        Write_Cmd(0x0c);    //整体显示打开,游标关闭
    Delay_1ms();
        Write_Cmd(0x01);    //清除显示
    Delay_1ms();
        Write_Cmd(0x06);    //游标右移
    Delay_1ms();
        Write_Cmd(0x80);    //设定显示的起始地址
}
/*****
//在坐标(x,y)处连续显示一个字符串,共x*y=8*4=32处位置。
void Lcd_Print(uchar x,uchar y,uchar *adata)
{
      uchar address;
      uchar i=0;
          if(0==y)      //y=0表示第一行,x表示第几列,共8列
          {
             address=0x80+x;       //一行x列
          }
          else if(1==y)
          {
                  address=0x90+x;
          }
          else if(2==y)
          {
                  address=0x88+x;
          }
          else if(3==y)
          {
                  address=0x98+x;
          }
          else
          {
                  return;
          }
      Write_Cmd(address);       //先写地址
      while(*(adata+i))        //字符串数组末尾有一个'/0',用i自加让他每位都取到并判断是否自加到末尾
      {
        Write_Data(*(adata+i));
        i++;
      }
}
*****/


#include <msp430f149.h>
#include "LCD12864.h"                 //声明所有调用函数库
#include "DS18B20.h"
uchar line1[]={"检测的温度值为:"};       //先定义要显示的汉字
uchar *str1=line1;                    //str表示指针,可以存放地址,这句话的意思就是把"检"的地址赋给指针变量str1,所以*str1的值就是"检"
uchar dN[6];                          //存放转换完成的温度
void Disp_Numb(uint realtemp);        //先声明后面要用到的函数
void main(void)
{
    uchar i;
    WDTCTL=0x5A80;
    //430中,一个时钟周期=MCLK晶振的倒数,如MCLK是8M,则时钟周期为1/8us
    BCSCTL1&=~XT2OFF;          //打开XT2高频晶体振荡器,选择系统主时钟为8MHz
    do
    {
       IFG1&=~OFIFG;           //清除晶振失败标志
       for(i=0xFF;i>0;i--);    //等待8MHz晶体起振,稳定时间
    }
    while((IFG1&OFIFG));       //若晶振失效标志仍存在
    BCSCTL2|=SELM_2+SELS;      //选择MCLK和SMCLK为XT2
    TACTL|=TASSEL_2+ID_3;      //计数时钟选择SMLK=8MHz,8分频
    Init_Lcd();                //液晶初始化
    while(1)                   //循环进行温度数值转换
    {
      Disp_Numb(Do1Convert());     //将十一位的温度值转换成六位整数
      Disp_HZ(0x80,line1,8);
      //在12864显示温度值
      //0x30 表示字符‘0’,所有数字都加‘0’表示将十进制的数转换成相应数字的字符对应的ASCII值
      Write_Cmd(0x90);             //第二行
      Write_Data(dN[5]+0x30);      //十位
      Write_Data(dN[4]+0x30);      //个位
      Write_Data('.');             //小数点
      Write_Data(dN[3]+0x30);      //十分位
      Write_Data(dN[2]+0x30);      //百分位
      Write_Data(dN[1]+0x30);      //千分位
      Write_Data(dN[0]+0x30);      //万分位
    }
}
//将从DS18B20读取的温度数据转换成六位整数,并存储在字符数组dN【6】中
//顺序是 5 4 . 3 2 1 0,依次是十位,个位,十分位···
//因为是数字体温计,常理来说不存在负温度,若是负温度,则需要取反加1
void Disp_Numb(uint realtemp)
{
    uchar i;
    for(i=6;i>0;i--)    //6次
    dN=0;            //先置0
    //数值转换算法,将十一位二进制温度值转换成六位整型数据
    if(realtemp&BIT0)      //满足就是最低位(2的-4次方)为1
    {
        dN[0]=5;           //1/(2*2*2*2)=0.0625
        dN[1]=2;
        dN[2]=6;
    }
    if(realtemp&BIT1)      //2的-3次方
    {
        dN[1]+=5;          //1/2*2*2=0.125
        dN[2]+=2;
        dN[3]+=1;
    }
    if(realtemp&BIT2)      //2的-2次方
    {
        dN[2]+=5;          //1/2*2=0.25
        dN[3]+=2;
        if(dN[2]>=10)      //判断是否需要进位
        {                  //百分位是6+2+5级满足条件
           dN[2]-=10;      //百分位-1
           dN[3]+=1;       //十分位+1
        }
    }
    if(realtemp&BIT3)      //后面的都是如此
    {
        dN[3]+=5;
    }
    if(realtemp&BIT4)
    {
        dN[4]+=1;
    }
    if(realtemp&BIT5)
    {
        dN[4]+=2;
    }
    if(realtemp&BIT6)
    {
        dN[4]+=4;
    }
    if(realtemp&BIT7)
    {
        dN[4]+=8;
        if(dN[4]>=10)
        {
           dN[4]-=10;
           dN[5]+=1;
        }
    }
    if(realtemp&BIT8)
    {
        dN[4]+=6;
        dN[5]+=1;
        if(dN[4]>=10)
        {
           dN[4]-=10;
           dN[5]+=1;
        }
    }
    if(realtemp&BIT9)
    {
        dN[4]+=2;
        dN[5]+=3;
        if(dN[4]>=10)
        {
           dN[4]-=10;
           dN[5]+=1;
        }
    }
    if(realtemp&BITA)
    {
        dN[4]+=4;
        dN[5]+=6;
        if(dN[4]>=10)
        {
           dN[4]-=10;
           dN[5]+=1;
        }
        if(dN[5]>=10)
        {
           dN[5]-=10;
        }
    }
}




分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:667739 发表于 2019-12-18 20:26 | 只看该作者
延时出错了
回复

使用道具 举报

板凳
ID:631951 发表于 2019-12-19 08:06 | 只看该作者
我也有过这样的经历,就是前几天,但是12864带汉字库的,也是整个屏幕都是翔,我当时xy坐标的事,调了调xy坐标就好了
回复

使用道具 举报

地板
ID:524818 发表于 2019-12-19 12:14 | 只看该作者
既然之前程序运行正常,并且用手碰一下就正常,是不是考虑一下硬件电路或者电源供电及静电引起的?
回复

使用道具 举报

5#
ID:662518 发表于 2019-12-19 14:14 | 只看该作者
手碰一下就成了!嗯。。。。查硬件
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表