//////////////////////////////ds18b20模块////////////////////////////////////////////////////DS18B20是美国DALLAS半导体公司生产的可组网的一线式数字温度传感器,由于DS18B20是在一根I/O线上读写数据,因此,对读写的数据位有着严格的时序要求。
DS18B20有严格的通信协议来保证各位数据传输的正确性和完整性。
该协议定义了几种信号的时序:初始化时序、读时序、写时序。
所有时序都是将主机作为主设备,单总线器件作为从设备。
而每一次命令和数据的传输都是从主机主动启动写时序开始,如果要求单总线器件回送数据,在进行写命令后,主机需启动读时序完成数据接收。
数据和命令的传输都是低位在先。
以下是常见的DS18B20的测温程序,其正确性笔者已经通过仿真实验和实际电路验证过。
在程序设计时,只要将ds18b20.c和主程序放在同一个工程中,且在主程序中包含头文件ds18b20.h即可。
DS18B20头文件:ds18b20.h#ifndef __DS18B20_H__#define __DS18B20_H__void delay_18B20(unsigned int i);Init_DS18B20(void) ;ReadOneChar(void);WriteOneChar(unsigned char dat);ReadTemperature(void);#endif测温C程序:ds18b20.c#include <AT89X52.H>sbit DQ = P1^0; //定义通信端口unsigned char sign;void delay_18B20(unsigned int i){while(i--);}//初始化函数Init_DS18B20(void){unsigned char x=0;DQ = 1; //DQ复位delay_18B20(8); //稍做延时DQ = 0; //单片机将DQ拉低delay_18B20(80); //精确延时大于480usDQ = 1; //拉高总线delay_18B20(14);x=DQ; //稍做延时后如果x=0则初始化成功x=1则初始化失败delay_18B20(20);}//读一个字节ReadOneChar(void){unsigned char i=0;unsigned char dat = 0;for (i=8;i>0;i--){DQ = 0; // 给脉冲信号dat>>=1;DQ = 1; // 给脉冲信号if(DQ)dat|=0x80;delay_18B20(4);}return(dat);}//写一个字节WriteOneChar(unsigned char dat){unsigned char i=0;for (i=8; i>0; i--){DQ = 0;DQ = dat&0x01;delay_18B20(5);DQ = 1;dat>>=1;}}//读取温度ReadTemperature(void){unsigned char a=0;unsigned char b=0;unsigned int t=0,temp=0;Init_DS18B20();WriteOneChar(0xCC); //跳过读序号列号的操作WriteOneChar(0xBE); //读取温度寄存器等(共可读9个寄存器)前两个就是温度 delay_18B20(100);a=ReadOneChar();b=ReadOneChar();Init_DS18B20();WriteOneChar(0xCC); // 跳过读序号列号的操作WriteOneChar(0x44); // 启动温度转换//传感器返回值除16得实际温度值//为了得到2位小数位,先乘100,再除16,考虑整型数据长度,//技巧处理后先乘25,再除4,除4用右移实现temp=b&0xf0;if(temp==0xf0){sign=0x40;a=~a;b=~b;}elsesign=0x3f;b=b&0x0f;t = (b*256+a)*25/4;return(sign,t);}/////////////////////////////////////////////////////////网上程序//////////////////////////////////////////////////就算是用软件的方式提高精度也只是虚拟的温度,18B20精度就是0.0625度,符合你的要求了,下面是我写的程序,有兴趣你可以参考一下。
带报警设置#include <AT89X51.H>#define uchar unsigned char#define uint unsigned intuchar code table[]={0xc0,0xf9,0xa4,0xb0, //"0","1","2","3"共阳0x99,0x92,0x82,0xf8, //"4","5","6","7"0x80,0x90,0x88,0x83, //"8","9","A","B"0xc6,0xa1,0x86,0x8e, //"C","D","E","F"0xbf,0xff,};sbit w1=P0^0;sbit w2=P0^1;sbit w3=P0^2;sbit w4=P0^3;sbit w5=P0^4;sbit w6=P0^5;sbit w7=P0^6;sbit w8=P0^7;sbit DQ=P3^7;//定义18B20数据线sbit beep=P3^6;//sbit beep=P3^0;bit sflag;//正负标志位uchar timecount;//中断次数变量uchar readdata[2];//保存温度数值数组uchar ROM[8];uchar ICROM[2][8];uchar temperature[2][2];//读两个18B20存放温度数组uchar test,test0,test1;//保存温度数值中间变量uchar yi,er,san,shi,wu,liu,qi,ba;//定义数码管显示数变量//************数码管扫描程序******************// delayms(uint t){uchar tt;for(;t>0;t--)for(tt=50;tt>0;tt--);}void display(uchar yi,uchar er,uchar san,uchar shi,uchar wu,uchar liu,uchar qi,uchar ba){w8=1;2=table[yi];delayms(5);w8=0;delayms(1);w7=1;2=table[er];delayms(5);w7=0;delayms(1);w6=1;2=table[san];delayms(5);w6=0;delayms(1);w5=1;2=table[shi];delayms(5);w5=0;delayms(1);w4=1;2=table[wu];delayms(5);w4=0;delayms(1);w3=1;2=table[liu];delayms(5);w3=0;delayms(1);w2=1;2=table[qi];delayms(5);w2=0;delayms(1);w1=1;2=table[ba];delayms(5);w1=0;delayms(1);}//*****************************************// //************18B20程序******************// void delay18b20(uint i){for(;i>0;i--);}reset (void)//复位18B20{uchar x=0;DQ=1;delay18b20(8);DQ=0;delay18b20(80);DQ=1;delay18b20(14);x=DQ;delay18b20(20);}void writebyte_18b20(uchar command)//写字节到18B20 {uchar i=0;for(i=8;i>0;i--){DQ=0;DQ=command&0x01;delay18b20(5);DQ=1;command=command>>1;}}uchar readbyte_18b20()//从18b20读出字节{uchar i=0;uchar temp=0;for(i=8;i>0;i--){DQ=0;temp>>=1;DQ=1;if(DQ)temp|=0x80;delay18b20(5);}return(temp);}//*****************************************//uchar readROM()//读18B20的ROM{uchar i;reset();writebyte_18b20(0x33);for(i=0;i<8;i++){ROM=readbyte_18b20();}return(ROM);}uchar writeROM()//匹配ROM并读出温度存到temperature[2][2]数组{uchar i,j;for(j=0;j<2;j++){reset();writebyte_18b20(0x55);for(i=0;i<8;i++){writebyte_18b20(ICROM[j]);}writebyte_18b20(0xbe);temperature[j][0]=readbyte_18b20();temperature[j][1]=readbyte_18b20();}}//**************************************//void main(){TMOD=0X11;TH0=(65536-3000)/256;TL0=(65536-3000)%256;TH1=(65536-500)/256;TL1=(65536-500)%256;TR0=1;ET0=1;ET1=1;EA=1;while(1){wu=16;ba=17;if(sflag==1){yi=15;}else yi=14;}}void timer0() interrupt 1 using 0 {uchar result;TH0=(65536-3000)/256;TL0=(65536-3000)%256;timecount++;display(yi,er,san,shi,wu,liu,qi,ba); if(timecount==5){timecount=0;reset();writebyte_18b20(0xcc);writebyte_18b20(0xbe);readdata[0]=readbyte_18b20();readdata[1]=readbyte_18b20();sflag=0;if((readdata[1]&0xf8)!=0x00)//如果是负温,将补码转为原码{sflag=1;readdata[1]=~readdata[1];//负数的补码等于真值按位取反后末位加1 readdata[0]=~readdata[0];result=readdata[0]+1;readdata[0]=result;if(result>255)//如果低八位的值转为原码后大于11111111(255),向高八位进1 { readdata[1]++;}}test0=readdata[0];test1=readdata[1];test=((readdata[1]*256)+readdata[0])/16;//把高位与低位的值转成10进制test0=(test0&0x0f);//取小数位,低四位switch (test0)//判断小数位的值,也可以用取表方式,精确度为0.0625度{case 0x00:liu=0;qi=6;break;case 0x01:liu=1;qi=2;break;case 0x02:liu=1;qi=8;break;case 0x03:liu=2;qi=5;break;case 0x04:liu=3;qi=1;break;liu=3;qi=7;break;case 0x06:liu=4;qi=3;break;case 0x07:liu=5;qi=0;break;case 0x08:liu=5;qi=6;break;case 0x09:liu=6;qi=2;break;case 0x0a:liu=6;qi=8;break;case 0x0b:liu=7;qi=5;break;case 0x0c:liu=8;qi=1;break; case 0x0d:liu=8;qi=7;break;case 0x0e:liu=9;qi=3;break;case 0x0f:liu=9;qi=9;break; }er=test/100;san=test%100/10;shi=test%10;if(test>28){TR1=1;}reset();writebyte_18b20(0xcc); writebyte_18b20(0x44); }}void timer1() interrupt 3 {uchar tt;TH1=(65536-500)/256;TL1=(65536-500)%256; tt++;if(tt==2){tt=0;beep=~beep;}}。