目录
一、原理
单总线数字温度传感器DS18B20,基本是蓝桥杯比赛必考模块,所以它的原理是必须要清楚的。
工作电压:3.0V~5.5V。
测量范围:-55摄氏度~+125摄氏度。
通信方式:单总线,数据线接上拉电阻,使总线空闲时处于高电平。
转换精度:9~12位分辨率可调,默认为12位,即分辨率是0.0625。
转换时间:典型值200ms。
DS18B20的内部有64位的ROM单元和9字节的高速暂存器。64位ROM单元包含了DS18B20唯一的序列号。
第0字节:温度数据的低8位。
第1字节:温度数据的高8位。
第3字节:TH用户字节,设置报警温度最高值。
第4字节:TL用户字节,设置报警温度最低值。
第5字节:配置寄存器,设置转换精度,默认12位。
第6字节和第7字节:保留,不用管。
第8字节:CRC码。
注:上电后,第2字节、第3字节和第4字节的状态值为EEPROM中的数据。
DS18B20以16位带符号位扩展的二进制补码形式读出。
低4位为小数部分,中间7位为整数部分。
高5位为扩展符号位,即BIT15~BIT11为00000,读出的数据为正温度,若为11111,则为负温度。在应用开发中,首先要对读出的温度数据的符号位进行判断,再根据正负温度的不同,进行相应的处理。
DS18B20的分辨率为0.0625。
读出数据为正温度时,将LSB和MSB整合成的16位整数,直接乘以0.0625即可。
读出数据为负温度时,则需要将LSB和MSB整合成的16位整数,取反加1后,再乘以0.0625,因为温度数据是以补码形式表示的。
例如:
读出结果为00A2H,温度值 = 162×0.0625 = 10.125 摄氏度。
读出结果为FF5EH,取反加1就是00A2H,温度值则为 -10.125 摄氏度。
【注】1.将官方提供的底层代码拷贝进自己新建的工程后,检查一下所提供的头文件onewire.h里是否已经调用onewire.c的函数,丢失函数声明(2019年官方提供文件故意挖坑)
2.当显示出现错误时,可能是底层代码函数提供的频率为12MHZ,而开发板的频率为1MHZ,所以把底层驱动代码所有延时函数时间扩大10倍或者12倍
二、操作步骤
DS18B20单线通信功能是分时完成的,它有严格的时隙概念,如果出现序列混乱,器件将不响应主机,因此读写时序很重要。
通过单线总线端口访问DS18B20的协议如下:
步骤1: 复位初始化
步骤2: ROM操作指令
步骤3: DS18B20功能指令
DS18B20的高速暂存存储器由9个字节组成,当温度转换命令发布后,经转换所得的温度值以二字节补码形式存放在高速暂存存储器的第0和第1个字节。在上电状态下,DS18B20默认的精度为12位。启动后它保持低功耗等待状态。当需要执行温度测量和AD转换时,总线控制器必须发出温度转换命令。在那之后,产生的温度数据以两个字节的形式被存储到高速暂存器的温度寄存器中,DS18B20继续保持等待状态。单片机可通过单线接口可以读到该数据,读取时低位在前,高位在后。
三个重要的DS18B20指令
<1> CCH:跳过ROM指令,忽略64位ROM地址,直接向DS18B20发起各种温度转换指令。
<2> 44H:温度转换指令,启动DS18B20进行温度转换,转换时间最长为500ms(典型值为200ms),结果保存在高速RAM中。
<3> BEH:读暂存器指令,读取高速暂存存储器9个字节的内容。
读取一次DS18B20温度的基本操作
<1> 主机对DS18B20进行复位初始化。
<2> 主机向DS18B20写0xCC命令,跳过ROM。
<3> 主机向DS18B20写0x44命令,开始进行温度转换。 <4> 等待温度转换完成。
<5> 主机对DS18B20进行复位初始化。
<6> 主机向DS18B20写0xCC命令,跳过ROM。
<7> 主机向DS18B20写0xBE命令,依次读取DS18B20发出的从第0一第8,共九个字节的数据。如果只想读取温度数据,那在读完第0和第1个数据后就不再理会后面DS18B20发出的数据即可,或者通过DS18B20复位,停止数据的输出。
具体的代码实现,可以参考一下框架:
三、解题思路
<1> 先将 onewire.c文件和onewire.h文件拷贝到当前工程下。
<2> 打开 onewire.h文件,检查文件代码是否完整,并确认总线引脚定义是否和CT107D的硬件对应,即P1^4。如果不对应,则将其修改过来。
<3> 打开 onewire.c文件, 研读各个底层驱动代码的具体实现,初步判断是时序的延时是否合理,如有明显错误,则将其修改过来。
<4> 根据DS18B20的工作原理和操作流程,编写读取温度结果和处理温度数据的函数,这是进行DS18B20应用开发中最重要的一个环节。
<5> 根据得到的温度结果,刷新数码管显示。这个部分,可以用MM模式来实现,可以用IO模式来实现(MM模式更方便)。
四、数据处理
参考小蜜蜂老师的思路:
五、实训代码(检测环境温度)
#include"reg52.h" #include"absacc.h" #include"onewire.h" unsigned char SMGNoDot_CA[10] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90}; unsigned char SMGDot_CA[10] = {0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10};//带小数点 unsigned int temp = 0; void DelaySMG(unsigned int t) { while(t--); } void DisPlaySMG_Bit(unsigned char pos , unsigned char dat) //单个数码管显示 { XBYTE[0xE000] = 0xff; //消影 XBYTE[0xC000] = 0x01 << pos; XBYTE[0xE000] = dat; } void DisPlay_All(unsigned char dat) { XBYTE[0xC000] = 0xff; XBYTE[0xE000] = dat; } // 拆分数据567 ,个十百位 // 567 / 100 = 5 // 567 % 100 = 67 67 / 10 = 6 // 567 % 10 = 7 void DisPlaySMG_Temp() //8个数码管同时显示 { /* DisPlaySMG_Bit(7,SMGNoDot_CA[temp % 10]); DelaySMG(100); DisPlaySMG_Bit(6,SMGDot_CA[(temp % 10) / 10]); DelaySMG(100); DisPlaySMG_Bit(5,SMGNoDot_CA[temp / 100]); DelaySMG(100); */ DisPlaySMG_Bit(7,SMGNoDot_CA[temp % 10]); DelaySMG(100); DisPlaySMG_Bit(6,SMGNoDot_CA[temp / 10]); DelaySMG(100); DisPlaySMG_Bit(5,0xff); DelaySMG(100); DisPlaySMG_Bit(4,0xff); DelaySMG(100); DisPlaySMG_Bit(3,0xff); DelaySMG(100); DisPlaySMG_Bit(2,0xff); DelaySMG(100); DisPlaySMG_Bit(1,0xff); DelaySMG(100); DisPlaySMG_Bit(0, 0xff); DelaySMG(100); DisPlay_All(0xff); //关闭所有数码管 } void Delay(unsigned int t) { while(t--) { DisPlaySMG_Temp() ; //延时期间仍要执行显示指令 } } void Read_DS18B20_temp() { unsigned char LSB,MSB; init_ds18b20(); //初始化操作 Write_DS18B20(0xcc); //跳过ROM操作 Write_DS18B20(0x44); //转换温度 Delay(1000); init_ds18b20(); //初始化操作 Write_DS18B20(0xcc); //跳过ROM操作 Write_DS18B20(0xbe); //开始读取暂存器中的温度 LSB = Read_DS18B20(); MSB = Read_DS18B20(); temp = MSB; temp = (temp <<= 8) | LSB; temp >>= 4; //右移四位相当于去掉了小数部分 /* if((temp & 0xf800) == 0x0000) //判断温度正负,高五位为符号位 { temp >>= 4; //相当于*0.0625 temp = temp *10; temp = temp +(LSB & 0x0f) * 0.625; } */ } void main() { XBYTE[0x8000] = 0x00; while(1) { Read_DS18B20_temp(); DisPlaySMG_Temp(); } }