Thermometer
1> 实验目的
实现51单片机,读写单个DS18B20,并将温度值,通过串口输出到电脑;
2> DS18B20-灵魂4问?
2.1> 长啥样?
2.2> 能干哈?
DS18B20 数字温度计,测量范围-55°C ~ +125°C
2.3> 咋干的?
DS18B20 内部自带温度传感器,能将温度值转为2Byte的数据,提供单总线接口(1-Wire);
主控制器可以通过简单命令进行读写,从而获取温度值;
自己理解:类似于DS18B20的这种功能模块,
他们如同大学食堂的每个窗口,你不需要太了解内部加工过程,只需简单的,说“老板,刀削面来一碗”这样的命令;
2.4> 咋用他?
2个方面:硬件设计和程序设计;
2.4.1> 硬件设计
DQ引脚必须有上拉电阻;
2.4.2> 读1个DS18B20流程图
2.4.3> 控制命令
命令或数据,都是从最低有效位开始发送;
All data and commands are transmitted least significant bit(LSB) first over the 1-Wire bus.
2.4.4> 数据格式
温度分辨率:9~12位可选, 默认12位(0.0625°);
温度测量范围:-55°~+125°;
0b’11111010000 = 2000;
2000 * 0.0625 = 125°
负温度:是以二进制【补码】形式存放,正好符合C与语言有符号类型;
3> 单总线(1-Wire)通信协议
3.1> 读1个DS18B20的温度值
流程图:
字节流-时序图:
3.2> 复位脉冲/ 存在脉冲
初始化DS18B20, 确定DS18B20准备好;
空闲态: DQ保持高电平;
复位脉冲:主控制器将DQ拉低>=480us后,释放;
延时:DQ保持高电平,15~60us;
存在脉冲:DS18B20将DQ拉低60~240us,释放; // 表示准备好;
3.3> 写1-bit数据
主控制器对DS18B20 : 写‘0’
写0:将总线DQ拉低60~120us;
主控制器对DS18B20 : 写‘1’
第1步:将DQ拉低0~15us; // 最多15us,一般设置成5-10us;
第2步:将DQ拉高,释放总线;
!注意:写0与写1之间,需要间隔1us;
3.4> 读1-bit数据
读‘0’
第1步:主控制器将DQ拉低>=1us;
第2步:主控制器将DQ拉高,释放总线;
第3步:DS18B20将DQ拉低,14us内释放总线;完成写0;
注意: 主控制器要读,只能在DS18B20拉低期间去采样;
读‘1’
第1步:主控制器将DQ拉低>=1us;
第2步:主控制器将DQ拉高,释放总线;
第3步:DS18B20将DQ拉高,14us内释放总线;完成写1;
注意: 主控制器要读,只能在DS18B20拉高期间去采样;
!注意:读DS18B20,采样时间段都是在前15us;
为什么后45us无效呢,DS18B20这么设计,可能是为了降低功耗;
4> 程序设计
4.1> 编程思路
4.2> 代码实现
底层时序相关:
#include "bsp.h"
/**
* @brief:Initiallization Timing
*/
void DS18B20_Init(void)
{
DS18B20_DQ = 1;
DS18B20_DQ = 0; // Reset Pulse
Delay500us();
DS18B20_DQ = 1;
/* 判断DS18B20是否发送存在脉冲 */
Delay500us();
}
/**
* @brief:MCU Write 1bit 0 to DS18B20
*/
void DS18B20_Write_0(void)
{
DS18B20_DQ = 0;
Delay60us(); //写0
DS18B20_DQ = 1; //释放DQ
}
/**
* @brief:MCU Write 1bit 1 to DS18B20
*/
void DS18B20_Write_1(void)
{
DS18B20_DQ = 0;
Delay10us(); //0~15us;
DS18B20_DQ = 1;
Delay60us(); //写1
}
/**
* @brief : MCU Write 1Byte command
* @cmd : 1Byte DS18B20 ROM command or function command
*/
void DS18B20_Write_Byte(uchar8_t cmd)
{
uchar8_t i = 0;
for (i = 0; i < 8; i++) {
if ((cmd & 0x01) == 1) {
DS18B20_Write_1();
} else {
DS18B20_Write_0();
}
_nop_(); //位与位间隔>=1us
cmd = cmd >> 1;
}
}
/**
* @brief : MCU Read 1Byte dat from DS18B20
* @retval : 1Byte dat from DS18B20
*/
uchar8_t DS18B20_Read_Byte(void)
{
uchar8_t i = 0;
uchar8_t dat = 0;
uchar8_t temp = 0;
for (i = 0; i < 8; i++) {
DS18B20_DQ = 0;
_nop_();
DS18B20_DQ = 1;
Delay10us();
temp = DS18B20_DQ; // 采样
dat = (temp << 7) | (dat >> 1); // 低位先发送
Delay60us();
}
return dat;
}
BSP级函数相关:
/**
* @brief : MCU Read 2Byte Temperature data from DS18B20
* @retval : Celseius temperature
*/
float DS18B20_Read(void)
{
float c_val = 0; // 存放摄氏度℃
short16_t c_Hex = 0x0; // 存放2Byte二进制数据
uchar8_t temp_L = 0x0;
// 阶段1
DS18B20_Init();
DS18B20_Write_Byte(0xCC);
DS18B20_Write_Byte(0x44);
// 阶段2
DS18B20_Init();
DS18B20_Write_Byte(0xCC);
DS18B20_Write_Byte(0xBE);
temp_L = DS18B20_Read_Byte(); // Byte 0:LSB
c_Hex = DS18B20_Read_Byte(); // Byte 1:MSB
// 转换温度
c_Hex = temp_L | (c_Hex << 8);
c_val = c_Hex * 0.0625;
printf("temp = %g 度\n\r", c_val); // Debug
return c_val;
}
5> 逻辑分析仪-测试波形
5.1> 复位脉冲 和 存在脉冲
复位脉冲 = 500us;
DS18B20延时 = 29us;
存在脉冲 = 113.4us;
5.2> 写1字节
写“1”拉低时间设置为10us,不要超过15us;
5.3> 读2字节
2Byte数据:
低位先发,所以DS18B20发送顺序是:1010 0101 1000 0000
低字节数据(Byte0):
观察波形,可以算出
DS18B20输出1bit数据的时长为:28.9-1.1 = 27.8us;
所以51单片机要在这段时间采样,数据手册给出的是15us;