1.首先我们知道DS18B20是单总线协议,只有一根数据线。所以Data数据线即使发送端又是接收端,同时DS18B20内部接了弱上拉电阻(如图一所示),数据线默认为高电平。有了这些概念,我们就能进行下一步。
图一(截取DS18B20芯片手册)
2.初始化DS18B20
看图二可知,首先我们将总线从高拉低,保持480us左右,然后释放总线(没人拉低,默认高电平),此时总线上为高电平。然后等待15-60us,等待DS18B20模块将总线拉低。(如果拉低则说明DS18B20响应成功),DS18B20拉低60-240us后,释放总线。初始化完成。
图二
3.向DS18B20写入数据。
3.1 向DS18B20写0。
首先将总线由高拉低,低电平保持15us到60us,然后释放总线。写入0完成。
3.2 向DS18B20写1。
将总线由高拉低,低电平保持1-15us(看图三可知,低电平时间要低于15us),再释放总线。
图三
4.读取DS18B20寄存器中数据
4.1 读数据0
将总线由高拉低,保持1-15us。如果DS18B20中数据是0,则会将总线拉低。此时,总线上为低电平。我们要在60us以内读取数据(图四可知,60us以内DS18B20会释放总线)。否则可能会读到错误数据。
4.2 读数据1
将总线由高拉低,保持1-15us,如果数据是1,DS18B20会释放总线,总线上为高电平。然后在15us以后读取数据。
图四
5.DS18B20一些命令
5.1 0xCC→跳过ROM
5.2 其他命令
0x44→开始温度转换指令 ,0xBE→读取数据寄存器指令
图五
6.DS18B20数据寄存器
这里也比较关键,所以拎出来讲一下。
首先DS18B20的数据寄存器是16位,其中寄存器高字节的高5位的S表示符号位,其余3位才是表示数据。这里就浅讲一下,后面结合代码来解析一下。
图六
7.代码实例
声明:首先这里面的延时都是按照经验值,就是通过实践,得出比较准确的延时。
注:这里使用的是12M频率的单片机,如果是1M可以把for循环去掉
延时函数如下:
1. sbit DQ=P1^4; 2. //我这里是P1^4连接了DS18B20的数据线。 3. //你们根据自己的单片机原理图查询 4. void Delay_OneWire(unsigned int t) 5. { 6. unsigned char i; 7. while(t--){ 8. for(i=0;i<12;i++); 9. } 10. }
7.1 DS18B20初始化
1. bit init_ds18b20(void) 2. { 3. bit initflag = 0; 4. 5. DQ = 1; 6. Delay_OneWire(12); 7. DQ = 0; //拉低总线 8. Delay_OneWire(80); 9. DQ = 1; 10. Delay_OneWire(10); //等待DS18B20拉低 11. initflag = DQ; //获取总线数据 12. Delay_OneWire(5); 13. return initflag; 14. }
7.2 向DS18B20写入一字节数据
1. void Write_DS18B20(unsigned char dat) 2. { 3. unsigned char i; 4. for(i=0;i<8;i++) 5. { 6. DQ = 0; //拉低 7. DQ = dat&0x01; //获取dat最后一位数据 8. Delay_OneWire(5);//写入数据 9. DQ = 1; //释放总线 10. dat >>= 1; //dat右移一位 11. } 12. Delay_OneWire(5); 13. }
7.3 读取DS18B20数据寄存器的值
1. unsigned char Read_DS18B20(void) 2. { 3. unsigned char i; 4. unsigned char dat; 5. //循环8次,读一个字节 6. for(i=0;i<8;i++) 7. { 8. DQ = 0; //拉低 9. dat >>= 1; 10. DQ = 1; //释放总线 11. if(DQ) // 因为dat>>1位默认是0 ,如果DQ为0,就不需要赋0了 12. { 13. dat |= 0x80; //给dat赋1 14. } 15. Delay_OneWire(5); 16. } 17. return dat; 18. }
7.4 读取温度
1. unsigned int get_temp() 2. { 3. unsigned int result; 4. float i; 5. unsigned char low,high; 6. init_ds18b20(); 7. Write_DS18B20(0xcc);//跳过rom 8. Write_DS18B20(0x44);//开始转换 9. 10. init_ds18b20(); 11. Write_DS18B20(0xcc);//跳过rom 12. Write_DS18B20(0xbe);//开始转换 13. 14. low=Read_DS18B20(); //先读取低字节 15. high=Read_DS18B20();//再读取高字节 16. result =high&0x0f; //获取高字节低4位数据(1位符号位,3位数据位) 17. result<<=8; //左移8位 18. result=result|low; //或上低字节,拼成16位数据。 19. i=result*0.0625; //为什么乘0.0625,下面讲 20. result=i*100; //温度值扩大100倍,方便数码管显示 21. return result; //返回温度值 22. }
这里为什么最后的结果result需要乘以*0.0625。我们上面讲过DS18B20的数据寄存器,其实高字节的低3位才是数据位。 如高字节的最后一位本来是 2^4,假如有这个数据。则数据寄存器这个位为1,因为我们已经左移了8位,则变成了2^8.则实际上扩大了2^8/2^4=2^4=16,比实际结果扩大了16倍,所以我们需要乘以0.0625,缩小16倍。这样才能得到真实值。
所以整体原因是因为result左移8位,导致数据扩大了16倍,所以result需要乘以0.0625缩小16倍!
8.结语
这次也是通过DS18B20的芯片手册来讲解如何读取DS18B20的数据,以及最后转化为真实温度。 最后也是用代码实例来巩固理论,以及验证理论。