(二)、温度传感器
1、One-Wire总线
One-Wire总线利用一根线实现双向通信 。因此其协议对时序的要求较严格,如应答等时序都有明确的时间要求。基本的时序包括复位及应答时序、写一位时序读一位时序。单总线即只有一根数据线,系统中的数据交换、控制都由这根线完成。设备(主机或从机)通过一个漏极开路或三态端口连至该数据线,以允许设备在不发送数据时能够释放总线,而让其他设备使用总线。由于它们是主从结构,只有主机呼叫从机时,从机才能应答,因此主机访问One-Wire器件都必须严格遵循单总线命令序列,即初始化、ROM命令、功能命令。
对于蓝桥杯的同学,One-Wire协议官方会提供,不需要大家自己写。DS18B20的通信过程较为简单。图 五为蓝桥杯DS18B20原理图,DQ即用于通信的单总线,需要在函数开始定义该引脚sbit DQ = P1^4;
DS18B20的通信过程:初始化总线---写ROM指令(跳过ROM指令0xcc)---写RAM指令(开始温度转换0x44)---重新初始化---ROM指令(跳过ROM指令0xcc)---写RAM指令(开始温度读取0xbe)---接收数据(先低位再高位)---分析处理数据。(如 图 六**)**

图 五DS18B20 原理图

图 六 DS18B20 通信过程
2、代码解读(图 七)(数据处理分析)
数据处理: High<<8 高八位数据以二进制的形式左移八位就变成了unsigned int 类型数据,后八位数据全为0,此时用 | Low 运算符来获取后八位数据,则((High<<8)|Low)就是获取到了初步的温度数据,float(对象)就是强制转换括号中数据为float数据类型,但温度高五位是符号位(图 八),当这五个全是0时温度为正值,全为1则为负值。后四位是小数位,此时要*0.0625或者/16.0来获取到适合的温度区间,例如0000 0000 0000 0011表示十进制数据3,最后一位精度为0.0625,3*0.0625即为温度数据。

图 七 DS18B20 代码解读

图 八 DS18B20 数据存储位
附相关代码(注意蓝桥杯官方会给初始化、写入、读取等底层)
cs
#include <STC15F2K60S2.H>
#include <INTRINS.h>
sbit DQ = P1^4;
void Delay_OneWire(unsigned int t)
{
unsigned char i;
while(t--){
for(i=0;i<12;i++);
}
}
//仿真用这个延时
//void Delay_OneWire(unsigned int t)
//{
// while(t--);
//}
//
void Write_DS18B20(unsigned char dat)
{
unsigned char i;
for(i=0;i<8;i++)
{
DQ = 0;
DQ = dat&0x01;
Delay_OneWire(5);
DQ = 1;
dat >>= 1;
}
Delay_OneWire(5);
}
//
unsigned char Read_DS18B20(void)
{
unsigned char i;
unsigned char dat;
for(i=0;i<8;i++)
{
DQ = 0;
dat >>= 1;
DQ = 1;
if(DQ)
{
dat |= 0x80;
}
Delay_OneWire(5);
}
return dat;
}
//
bit init_ds18b20(void)
{
bit initflag = 0;
DQ = 1;
Delay_OneWire(12);
DQ = 0;
Delay_OneWire(80);
DQ = 1;
Delay_OneWire(10);
initflag = DQ;
Delay_OneWire(5);
return initflag;
}
/*
DS18B20的通信过程:
初始化总线
写ROM指令(跳过ROM指令0xcc)
写RAM指令(开始温度转换0x44)
重新初始化
ROM指令(跳过ROM指令0xcc)
写RAM指令(开始温度读取0xbe)
接收数据(先低位再高位)
分析处理数据
*/
float Temperature_Read(void)
{
unsigned char Low,High;
init_ds18b20(); //初始化总线
Write_DS18B20(0xcc); //跳过ROM指令
Write_DS18B20(0x44); //开始温度转换
Delay_OneWire(200);
init_ds18b20(); //重新初始化
Write_DS18B20(0xcc); //跳过ROM指令
Write_DS18B20(0xbe); //开始读取温度(低位优先)
Low = Read_DS18B20(); //接收数据(先低位再高位)
High = Read_DS18B20();
return (float)((High<<8)|Low)/16.0; //分析处理数据
}