楼主的程序基本没有问题,关键是参考的程序MCU时钟与楼主选用的不同导致时序误差而产生读取错误。
- #include<reg51.h>
- #include<intrins.h>
- #define uchar unsigned char
- #define uint unsigned int
- #define delayNop(); {_nop_();_nop_();_nop_();_nop_();};
- uchar code table[]=" ERROR!!! ";
- uchar code table1[]="xianzaiwendu ";
- uchar code table2[]="Temp= . Cent";
- uchar code table3[10]="0123456789";
- sbit lcd_rs=P1^0;
- //sbit lcd_rw=P1^1;
- sbit lcd_en=P2^5;
- sbit DQ=P2^2;
- uchar num,time;
- void DelayUs2x(uchar t)
- {
- while(--t);
- }
- void delay(uint t)
- {
- unsigned char n;
- while(t--)
- {
- for(n = 0; n<250; n++)
- {
- _nop_();
- _nop_();
- _nop_();
- _nop_();
- }
- }
- }
- void write_com(uchar com) //写命令
- {
- //lcd_rw=0;
- //delay(5);
- lcd_rs=0;
- lcd_en=0;
- _nop_();
- _nop_();
- P0=com;
- delayNop();
- lcd_en=1;
- delay(1);
- lcd_en=0;
- }
- void write_date(uchar date) //写数据
- {
- //lcd_rw=0;
- // delay(5);
- lcd_rs=1;
- lcd_en=0;
- _nop_();
- _nop_();
-
- P0=date;
- delayNop();
- lcd_en=1;
- delay(1);
- lcd_en=0;
- }
- void init() //初始化函数
- {
- // dula=0;
- // wela=0;
- lcd_en=0; //可以试试不加这一句看结果怎样
- write_com(0x38);
- write_com(0x0c);
- write_com(0x06);
- write_com(0x01);
- }
- uchar init_DS18bB20()
- {
- bit flag;
- DQ=1; //人为拉高
- DelayUs2x(5); //稍做延时 //稍微延时6US;
- DQ=0; //认为拉低
- DelayUs2x(200); //精确延时 大于 480us 小于960us
- DelayUs2x(200);
- DQ=1; //被上拉电阻拉高 (仿真里面没有上拉,有没有都需要人为拉高)
- DelayUs2x(50); //15~60us 后 接收60-240us的存在脉冲 // 延时60US检测
- flag=DQ; //这时又被DS18B20拉低,
- DelayUs2x(25); //稍作延时返回 //延时600US检测时间
- return flag; //返回0表示存在
- }
- void Write_Byte(uchar dat) //写一个字节,单片机向DS18B20写命令,确定DS18B20的工作方法之类的
- {
- unsigned char i=0;
- for (i=0; i<8; i++)
- {
- DQ =1; // 先将数据线拉高
- _nop_(); //等待一个机器周期
- DQ=0; //将数据线从高拉低时即启动写时序
- DQ=dat&0x01; //利用与运算取出要写的某位二进制数据,
- //并将其送到数据线上等待DS18B20采样
- DelayUs2x(25);
- //延时约30us,DS18B20在拉低后的约15~60us期间从数据线上采样
- DQ=1; //释放数据线,也就是被上拉电阻拉高,反正就是要把这个口释放,然后来执行下一个命令
- // for(time=0;time<1;time++)
- // ;//延时3us,两个写时序间至少需要1us的恢复期
- dat>>=1; //将dat中的各二进制位数据右移1位
- }
- DelayUs2x(25);
- //稍作延时,给硬件一点反应时间
- }
- uchar Read_Byte()
- {
- uchar i=0;
- uchar dat;//用来储存读出的一个字节,默认为0
- for(i=0;i<8;i++)
- {
- DQ=1;
- _nop_();
- DQ=0; //读命令一定得是低电平
- dat>>=1; //读取数据是从高位开始读,dat默认是0,也就是0000 0000,
- // 这是下标是指向最高位的,所以得先右移一位让出一个位置
- _nop_(); //需要>1US;
- DQ=1; //又被上拉电阻拉高
- // for(time=0;time<2;time++);
- if(DQ==1) //由DQ发送的信号来决定,发送的是高电平还是低电平
- dat|=0x80; //高电平就或0x80,1000 0000
- else
- dat|=0x00; //低电平就或,0x00
- DelayUs2x(25);//延时10US左右,因为需要在15US内完成读取
- }
- return dat;
- }
- void Readyread()//做好读温度准备。。。。可以加在主函数里面,但是分出来比较清晰明了
- {
- init_DS18bB20();
- Write_Byte(0xcc); //跳过读序号
- Write_Byte(0x44); //启动温度转换
- for(time=0;time<100;time++);
- init_DS18bB20(); //再初始化一下
- Write_Byte(0xcc); //跳过读序号
- Write_Byte(0xbe); //都温度寄存器,前两个分别是温度的,低,高位
- }
- void display() //显示第一行说明
- {
- write_com(0x80);
- for(num=0;num<16;num++)
- {
- write_date(table[num]);
- // delay(1);
- }
- while(1);
- }
- void display1() //显示第二行说明
- {
- write_com(0x80);
- for(num=0;num<16;num++)
- {
- write_date(table1[num]);
- // delay(1);
- }
- }
- void display2()
- {
- write_com(0x80+0x40);
- for(num=0;num<16;num++)
- {
- write_date(table2[num]);
- //delay(1);
- }
- }
-
- void display_temp(uchar x) //显示温度整数部分
- {
- uchar bai,shi,ge;
- bai=x/100;
- shi=(x%100)/10;
- ge=x%10;
- write_com(0x80+0x46);
- write_date(table3[bai]);
- write_date(table3[shi]);
- write_date(table3[ge]);
- }
- void display1_temp(uchar x) //显示温度小数部分
- {
- write_com(0x80+0x4a);
- write_date(table3[x]);
- }
- void main()
- {
- uchar TL;//储存暂存器的温度最高位
- uchar TH;//储存暂存器的温度最低位
- uchar TN; //储存温度整数部分
- uchar TD; //储存温度小数部分
- init();
- if(init_DS18bB20()==1)
- display();
- display1();
- display2();
- while(1)
- {
- Readyread();
- TL=Read_Byte();
- TH=Read_Byte();
- TN=TH*16+TL/16; //实际温度值=(TH*256+TL)/16,即:TH*16+TL/16
- //这样得出的是温度的整数部分,小数部分被丢弃了
- TD=(TL%16)*10/16; //计算温度的小数部分,将余数乘以10再除以16取整,
- //这样得到的是温度小数部分的第一位数字(保留1位小数)
-
- display_temp(TN);
- display1_temp(TD);
- _nop_(); _nop_();
- }
- }
复制代码
|