18B20读出的温度在1602LCD上十位乱码。其他位正常,请教高手

2020-02-09 09:28发布

//#include <pic.h>        //调用头文件
#include <pic16f7x7.h>//使用内部晶振8MHZ。
#define NOP()                asm("nop")
#define uchar unsigned char
#define uint  unsigned int
///LCD1602接口定义
#define  LCD_DATA_PORT    PORTB        //定义LCD的D0-D7所在端口
#define  LCD_DATA_POUT    TRISB=0x00   //定义LCD数据端口为输出
#define  LCD_EN_1         RC7=1                        //LCD使能端
#define  LCD_EN_0         RC7=0                               
#define  LCD_RS_1         RC6=1                                //数据/指令选择端
#define  LCD_RS_0         RC6=0
#define  LCD_RSADD         TRISC6=0
#define  LCD_ENADD          TRISC7=0

/***********18B20接口***************/
#define DQ RA4
#define DQ_HIGH() TRISA4=1
#define DQ_LOW() TRISA4=0;DQ=0

//联接DS1302的端口定义
#define ds1302_rst  RA1//RC2                      //定义1302的RST接在PC4
#define ds1302_io   RA0//RC1                      //定义1302的IO接在PC3
#define ds1302_sclk RA6//RC0                      //定义1302的时钟接在PC2
#define set_ds1302_rst_ddr() TRISA1=0        //复位端置为输出
#define set_ds1302_rst() ds1302_rst=1        //复位端置1
#define clr_ds1302_rst() ds1302_rst=0        //复位端清0
#define set_ds1302_io_ddr() TRISA0=0         //数据端置为输出
#define set_ds1302_io() ds1302_io=1          //数据端置1
#define clr_ds1302_io() ds1302_io=0          //数据端清0
#define clr_ds1302_io_ddr() TRISA0=1         //数据端置为输入
#define in_ds1302_io() RA0=1          //数据端输入数据
#define set_ds1302_sclk_ddr() TRISA6=0       //时钟端置为输出
#define set_ds1302_sclk() ds1302_sclk=1      //时钟端置1
#define clr_ds1302_sclk() ds1302_sclk=0      //时钟端清0
#define ds1302_sec_add 0x80                  //秒数据地址
#define ds1302_min_add 0x82                  //分数据地址
#define ds1302_hr_add 0x84                   //时数据地址
#define ds1302_date_add 0x86                 //日数据地址
#define ds1302_month_add 0x88                //月数据地址
#define ds1302_day_add 0x8a                  //星期数据地址
#define ds1302_year_add 0x8c                 //年数据地址
#define ds1302_control_add 0x8e              //控制数据地址
#define ds1302_charger_add 0x90      
#define ds1302_clkburst_add 0xbe
#define sw PORTA                        //按钮定义
#define swin TRISA2=1; TRISA3=1
#define speak RC1
#define speakout TRISC1=0

/////全局数据定义
uchar timer[7];    //时钟数据
uchar nian,nian1,ye,ye1,ri,ri1,shi,shi1,fen,fen1,miao,miao1;
bank3 uchar START_DISPLAY2[]={"Hang Li Fang"};
bank3 uchar START_DISPLAY1[]={"I Love You"};
bank3 uchar gu[]={"2010-11-06"};
bank3 uchar gu1[]={"19:30:20 25.3'C"};
bank3 uchar s1[]={"Mon"};
bank3 uchar s2[]={"Tue"};
bank3 uchar s3[]={"Wed"};
bank3 uchar s4[]={"Thu"};
bank3 uchar s5[]={"Fri"};
bank3 uchar s6[]={"Sat"};
bank3 uchar s7[]={"Sun"};
uchar t1,t2,t3;
uchar po=0;
////函数声明
void delay(uint  x);//延时';:.
void delayus(uint x,uchar y);
void lcd_init(void);//LCD初使化
void LCD_en_write(void);//写使能LCD
void set_LCD_xy(uchar d, uchar c );//设定XY坐标
void LCD_write_onechar(uchar COMM,uchar DAT);                //写指令或数据
void LCD_write_string(uchar d,uchar c,bank3 uchar *string);      //字符串写
void LCD_write(uchar d,uchar c,uchar data);       //单个字串写
void mcu_inti();
void ds1302_write(uchar add,uchar data);//DS1301add为写入地址码,data为写入数据
uchar ds1302_read(uchar add);//从1302中读出数据:
void ds1302_write_time(void);//向1302中写入时钟数据
void ds1302_read_time(void);//从1302中读出当前时钟
void Process(void);//示数据转换函数
void reset();//18B20初始化
void write_byte(uchar date);//18B20写指令
uchar read_byte();//读操作
void get_tem();//温度转换
void didi(uchar data);
void saomiao();
/****************************************************
函数名称:main
功能描述:主函数
输 入: 无
输 出: 无
日期:2009-4-8
***********************************************************************************************************************************/
void main(void)
{
        mcu_inti();
        lcd_init();
/*        timer[0]=0x10;   //年
        timer[1]=0x11;   //月
        timer[2]=0x08;   //日
        timer[3]=0x01;   //周
        timer[4]=0x10;   //时
        timer[5]=0x31;   //分
        timer[6]=0x00;   //秒
        ds1302_write_time();    //写入初始时钟*/
        didi(1);
        LCD_write_string(3,0,START_DISPLAY1);
        LCD_write_string(2,1,START_DISPLAY2);
        delay(5000);
        didi(3);
        LCD_write_onechar(0x01,0);
//        set_LCD_xy(1,0);
//        LCD_write_onechar(0,"2");                //写指令或数据
//        LCD_write_onechar(0,"0");                //写指令或数据
//        set_LCD_xy(5,0);
//        LCD_write_onechar(0,"-");                //写指令或数据
//        set_LCD_xy(8,0);
//        LCD_write_onechar(0,"-");                //写指令或数据
//        set_LCD_xy(3,1);
//        LCD_write_onechar(0,":");                //写指令或数据
        LCD_write_string(1,0,gu);      //字符串写
        LCD_write_string(12,0,s6);      //字符串写
        LCD_write_string(1,1,gu1);      //字符串写
        while(1)
        {
                get_tem();
                saomiao();
                if(po==1)
                {       
                        po=0;
                        didi(10);
                }
                if(po==2)
                {
                        po=0;
                        didi(1);
                }
        //        didi(2);
        /*                NOP();
                        NOP();
                        delayus(140,66);
                        NOP();
                        delayus(10,8);
                        NOP();                       
                        delayus(100,26);
                        NOP();
                        delayus(2,1);
                        NOP();
                        delayus(6,4);
                        NOP();
                        delayus(4,3);
                        NOP();*/
        }                           
}
void mcu_inti()
{       
        OSCCON=0X70;///内部晶振设定8MHZ
        NOP();NOP();NOP();
        ADCON1=0x0f;//AD中的IO数定接口
        set_ds1302_rst_ddr();
        set_ds1302_sclk_ddr();
        LCD_RSADD;
        LCD_ENADD;
        LCD_DATA_POUT;   
        speak=0;
        swin;
        speakout;
}
//////蜂鸣器声
void didi(uchar data)
{
        uchar teme;
        for(teme=0;teme<data;teme++)
        {
                speak=1;
                delay(100);
                speak=0;
                delay(100);
        }       
}
//按健扫描
void saomiao()
{       
        uchar key;
        key=sw&0X0C;
        if(key!=0xc)
        {
                if(key==0x04)
                        po=2;
                else if(key==0x08) po=1;
                        else po=0;
        }
/*        if(sw1==0)
        {
                delay(8);
                if(sw1==0)
                        po=1;
        }
        if(sw2==0)
        {
                delay(8);
                if(sw2==0)
                        po=2;
        }
        po=0;*/
}
/****************************************************
函数名称:lcd_init
功能描述:LCD初始化
输 入: 无
输 出: 无
日期:2009-4-8
说明:注意初始化过程并加上适当延时
     后面LCD的显示方式可按实际需要修改
*****************************************************/
void lcd_init(void)
{
    LCD_write_onechar(0x38,0);
    LCD_write_onechar(0x0c,0);    /*显示关闭*/
    LCD_write_onechar(0x06,0);    /*显示清屏*/
        LCD_write_onechar(0x01,0);    /*显示光标移动设置*/
    LCD_write_onechar(0x80,0);    /*显示开及光标设置*/
}

/****************************************************
函数名称:LCD_en_write
功能描述:EN端产生一个脉冲,写LCD
输 入: 无
输 出: 无
日期:2009-4-8
*****************************************************/
void LCD_en_write(void)        
{
    LCD_EN_1;
    delay(5);  //E脉冲周期最小150ns
    LCD_EN_0;
}
/****************************************************
函数名称:LCD_write_onechar
功能描述:写一个字节到LCD
输 入: COMM(指令)   DAT(显示数据)
输 出: 无
日期:2009-4-8
*****************************************************/
void LCD_write_onechar(uchar COMM,uchar DAT)
{
         if(COMM==0)
         {
            LCD_RS_1;  //RS高电平向LCD写数据
                LCD_DATA_PORT=DAT;
         }
         else
         {
            LCD_RS_0;
        LCD_DATA_PORT=COMM;
         }
         LCD_en_write();
}

/****************************************************
函数名称:LCD_write_string
功能描述:LCD字符串显示函数
输 入: x/y(X与Y坐标)   *string(字符串首地址)
输 出: 无
日期:2009-4-8
*****************************************************/
void LCD_write_string(uchar d,uchar c,bank3 uchar *string)
{
    set_LCD_xy( d, c );                //设置LCD显示坐标
    while (*string)
    {
      LCD_write_onechar(0,*string );
          string ++;                       //指向下一显示字符地址
    }
}
/****************************************************
函数名称:LCD_write_string
功能描述:LCD字符串显示函数
输 入: x/y(X与Y坐标)   *string(字符串首地址)
输 出: 无
日期:2009-4-8
*****************************************************/
void LCD_write(uchar d,uchar c,uchar data)
{
    set_LCD_xy( d, c );                //设置LCD显示坐标
      LCD_write_onechar(0,data );
}

/****************************************************
函数名称:set_LCD_xy
功能描述:设置显示坐标
输 入: x/y(X与Y坐标)
输 出: 无
日期:2009-4-8
说明:  LMB1602第一行首地址为0x80
              第二行为0xC0
日期:2009-4-7
*****************************************************/
void set_LCD_xy(uchar d, uchar c )
{
    if (c==0)
        LCD_write_onechar(0x80+d,0);
    else
    LCD_write_onechar(0xc0+d,0);  //第二行X列
}

void delay(uint  x)                        //子函数(延时子程序)
{                                                                //主函数delay(实数)时间是实数,单位是为毫秒
        uint a,b;
        for(a=x;a>0;a--)
                for(b=213;b>0;b--);//213
}
/*************************************/
/*         DS1302操作函数组    *
*************************************/
//写入1302数据函数:
//入口:add为写入地址码,data为写入数据
//返回:无
void ds1302_write(uchar add,uchar data)
{
     uchar i=0;
     set_ds1302_io_ddr();     //配置IO为输出
     clr_ds1302_rst();        //清复位,停止所有操作
     clr_ds1302_sclk();       //清时钟,准备操作
     set_ds1302_rst();        //置复位,开始操作
     for(i=8;i>0;i--)         //此循环写入控制码
     {
         if(add&0x01)
         set_ds1302_io();     //当前位为1,置数据位
         else
         clr_ds1302_io();     //当前位为0,清数据位
         NOP();NOP();  
         set_ds1302_sclk();   //产生时钟脉冲,写入数据
         NOP();NOP();  
         clr_ds1302_sclk();
         NOP();NOP();  
         add>>=1;             //移位,准备写入下1位
      }
     for(i=8;i>0;i--)         //此循环写入数据码
     {
         if(data&0x01)
         set_ds1302_io();
         else
         clr_ds1302_io();
         NOP();NOP();
         set_ds1302_sclk();
         NOP();NOP();  
         clr_ds1302_sclk();
         NOP();NOP();  
         data>>=1;
     }
     clr_ds1302_rst();
     NOP();NOP();  
     clr_ds1302_io_ddr();      //清输出状态
}
//从1302中读出数据:
//入口:add为读数据所在地址
//返回:读出的数据data
uchar ds1302_read(uchar add)
{
      uchar data=0;
      uchar i=0;
      add+=1;                //读标志
      set_ds1302_io_ddr();   //端口输出
      clr_ds1302_rst();      //清复位
      clr_ds1302_sclk();     //清时钟
      set_ds1302_rst();      //置复位
      for(i=8;i>0;i--)       //此循环写入地址码
      {
          if(add&0x01)
          {set_ds1302_io();}
          else
          {clr_ds1302_io();}
  
          NOP();NOP();
          set_ds1302_sclk();
          NOP();NOP();  
          clr_ds1302_sclk();
          NOP();NOP();
          add>>=1;
       }
       clr_ds1302_io_ddr();    //端口输入
       NOP();NOP();
       for(i=8;i>0;i--)        //此循环读出1302的数据
       {
          data>>=1;
          if(in_ds1302_io())
          {data|=0x80;}
          NOP();NOP();
          set_ds1302_sclk();
          NOP();NOP();
          clr_ds1302_sclk();
          NOP();NOP();
       }
       clr_ds1302_rst();
       return(data);
}

//向1302中写入时钟数据
void ds1302_write_time(void)
{
     ds1302_write(ds1302_control_add,0x00);    //关闭写保护
     ds1302_write(ds1302_sec_add,0x80);        //暂停
     ds1302_write(ds1302_charger_add,0xa9);    //涓流充电
     ds1302_write(ds1302_year_add,timer[0]);   //年
     ds1302_write(ds1302_month_add,timer[1]);  //月
     ds1302_write(ds1302_date_add,timer[2]);   //日
     ds1302_write(ds1302_day_add,timer[3]);    //周
     ds1302_write(ds1302_hr_add,timer[4]);     //时
     ds1302_write(ds1302_min_add,timer[5]);    //分
     ds1302_write(ds1302_sec_add,timer[6]);    //秒
     ds1302_write(ds1302_control_add,0x80);    //打开写保护
}
//从1302中读出当前时钟
void ds1302_read_time(void)
{
        timer[0]=ds1302_read(ds1302_year_add);    //年
        timer[1]=ds1302_read(ds1302_month_add);   //月
        timer[2]=ds1302_read(ds1302_date_add);    //日
        timer[3]=ds1302_read(ds1302_day_add);     //周
        timer[4]=ds1302_read(ds1302_hr_add);      //时
        timer[5]=ds1302_read(ds1302_min_add);     //分
        timer[6]=ds1302_read(ds1302_sec_add);     //秒
}
void Process(void)//示数据转换函数
{
        nian=((timer[0]&0xF0)>>4)+0x30;
        nian1=(timer[0]&0x0F)+0x30;
        ye=((timer[1]&0xF0)>>4)+0x30;
        ye1=(timer[1]&0x0F)+0x30;
        ri=((timer[2]&0xF0)>>4)+0x30;
        ri1=(timer[2]&0x0F)+0x30;
        shi=((timer[4]&0xF0)>>4)+0x30;
        shi1=(timer[4]&0x0F)+0x30;
        fen=((timer[5]&0xF0)>>4)+0x30;
        fen1=(timer[5]&0x0F)+0x30;
        miao=((timer[6]&0xF0)>>4)+0x30;
        miao1=(timer[6]&0x0F)+0x30;
        set_LCD_xy(3,0);
        LCD_write_onechar(0,nian);                //写指令或数据
        LCD_write_onechar(0,nian1);                //写指令或数据
        set_LCD_xy(6,0);
        LCD_write_onechar(0,ye);                //写指令或数据
        LCD_write_onechar(0,ye1);                //写指令或数据
        set_LCD_xy(9,0);
        LCD_write_onechar(0,ri);                //写指令或数据
        LCD_write_onechar(0,ri1);                //写指令或数据       
        switch(timer[3])
        {       
                case 1:         LCD_write_string(12,0,s1);break;
                case 2:                 LCD_write_string(12,0,s2);break;
                case 3:         LCD_write_string(12,0,s3);break;
                case 4:                 LCD_write_string(12,0,s4);break;
                case 5:         LCD_write_string(12,0,s5);break;
                case 6:         LCD_write_string(12,0,s6);break;
                case 7:         LCD_write_string(12,0,s7);break;
        }
        set_LCD_xy(1,1);
        LCD_write_onechar(0,shi);                //写指令或数据
        LCD_write_onechar(0,shi1);                //写指令或数据
        set_LCD_xy(4,1);
        LCD_write_onechar(0,fen);                //写指令或数据
        LCD_write_onechar(0,fen1);                //写指令或数据
        set_LCD_xy(7,1);
        LCD_write_onechar(0,miao);                //写指令或数据
        LCD_write_onechar(0,miao1);                //写指令或数据
        set_LCD_xy(10,1);
        LCD_write_onechar(0,t1+0x30);                //写指令或数据
        LCD_write_onechar(0,t2+0x30);                //写指令或数据
        LCD_write_onechar(0,'.');                //写指令或数据
        LCD_write_onechar(0,t3+0x30);                //写指令或数据
}
//////////////////////////////////////////////////////////////////////////////////////////
/*************18B20操作***************/
void delayus(uint x,uchar y)
{
        uint i;
        uchar j;
        for(i=x;i>0;i--);
        for(j=y;j>0;j--);
}
void reset()
{
        uchar st=1;
        DQ_HIGH();
        NOP();NOP();NOP();NOP();///111
        while(st)
        {
                DQ_LOW();
                delayus(140,66);
                DQ_HIGH();
                delayus(10,8);
                if(DQ==1)
                        st=1;
                else
                        st=0;
                delayus(100,26);
        }
}
void write_byte(uchar date)
{
        uchar i,temp;
        DQ_HIGH();
        NOP();NOP();NOP();NOP();///111
        for(i=8;i>0;i--)
        {
                temp=date&0x01;
                DQ_LOW();
                delayus(2,1);
                if(temp==1)
                        DQ_HIGH();
                delayus(6,4);
                DQ_HIGH();
                date=date>>1;
        }
}
uchar read_byte()
{
        uchar i;
        uint date;
        static bit j;
        for(i=8;i>0;i--)
        {
                date=date>>1;
                DQ_HIGH();
                NOP();NOP();NOP();NOP();//11111111111
                DQ_LOW();
                NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();/////////////11111111
                DQ_HIGH();
                NOP();NOP();NOP();NOP();NOP();NOP();NOP();NOP();//1111111
                j=DQ;
                if(j==1)
                        date=date|0x8000;
                delayus(4,3);
        }
        return (date);
}
void get_tem()
{
        uint  temper;
        float aaa;
        uchar num,tem1,tem2;
        reset();  //复位
        write_byte(0xCC);//跳过ROM
        write_byte(0x44);//温度转换/750ms
        for(num=4;num>0;num--)
        {
                ds1302_read_time();     //读出当前时钟
             Process();              //显示数据转换
                  delay(10);             //每100MS读一次48
        }
        reset();
        write_byte(0xCC);
        write_byte(0xBE);
        tem1=read_byte();
        tem2=read_byte();
        aaa=(tem2*256+tem1)*6.25;
        temper=(int)aaa;
        t1=temper/1000;
        t2=temper%1000/100;
        t3=temper%100/10;
}
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
7条回答
hsztc
1楼-- · 2020-02-09 11:25
 精彩回答 2  元偷偷看……
hsztc
2楼-- · 2020-02-09 14:37
先判断正负,然后分别处理


试试这样

tem1=read_byte();   
tem2=read_byte();   
//aaa=(tem2*256+tem1)*6.25;   

temper=(tem2<<4)|(tem1>>4);  // unsgined char temper;

if(tem2&0xf0) {temper=~temper; if((tem1&0xf)==0) temper++;} //负数
   
t1=temper/100;   
t2=(temper%100)/10;   
t3=temper%10;
millwood0
3楼-- · 2020-02-09 17:16
your code isn't very modular so it is hard to follow.

however, I would try to bifurcate the issue and see if it is display related or it is rtc related. you can find out the answer by returning a known value from the rtc routine and see how your display module deal with it; hard code a value for the display unit.

once you know the result, you can further narrow it down.
hsztc
4楼-- · 2020-02-09 19:13
按3楼说的做

先试下看
t1=1;  
t2=2;  
t3=3;
这样的显示结果,如果正常,说明显示程序没问题

再往前

tem1=0xb0;
tem2=0x7;
看结果是不是123度等等确定错误的位置
boming
5楼-- · 2020-02-10 00:54
谢谢大家。我昨天做了测试,是TEM1和TEM2都没读出数据。乱码是随机的。可以时序不对。用内部晶振,时间上不好测,不知是否有偏差。不知有什么方法可以知道时间。芯片是PIC16F767,P2编程器。不能在线仿真。PIC16F877A就可以。不知怎么回事。
millwood0
6楼-- · 2020-02-10 03:06
 精彩回答 2  元偷偷看……

一周热门 更多>