Thermometer
- 1> 实验概述
- 2> 硬件设计
- 3> DS18B20
- 3.1> 原理框图
- 3.2> 数据格式
- 4> 单总线(1-Wire)通讯协议
- 4.1> 初始化(复位)时序
- 4.2> 写-DS18B20时序
- 4.3> 读-DS18B20时序
- 4.4> 命令
- 5> 程序设计
- 5.1> 编程思路
- 5.2> 代码实现
- 6> 联调测试
1> 实验概述
实现51单片机,读写单个DS18B20,并将温度值通过串口输出;
2> 硬件设计
DQ引脚必须有上拉电阻;
3> DS18B20
3.1> 原理框图
DS18B20 内部自带温度传感器,能将温度值转为2Byte的数据,提供单总线接口(1-Wire);
主控制器可以通过简单命令进行读写,从而获取温度值;
自己理解:类似于DS18B20的这种功能模块,
他们如同大学食堂的每个窗口,你不需要了内部加工过程,只需简单的,说“老板,刀削面来一碗”这样的命令;
3.2> 数据格式
温度分辨率:9~12位可选, 默认12位(0.0625°);
温度测量范围:-55°~+125°;
0b’11111010000 = 2000;
2000 * 0.0625 = 125°
负温度:是以二进制【补码】形式存放,正好符合C与语言有符号类型;
4> 单总线(1-Wire)通讯协议
读DS18B20步骤:
Step 1: 初始化;
Step 2:发送ROM指令; // 确定主控制器与总线DQ上,挂的哪个DS18B20通讯;
Step 3:发送功能指令; // 具体执行动作;
4.1> 初始化(复位)时序
初始化DS18B20, 确定DS18B20准备好;
空闲态: DQ保持高电平;
复位脉冲:主控制器将DQ拉低>=480us后,释放;
延时:DQ保持高电平,15~60us;
存在脉冲:DS18B20将DQ拉低60~240us,释放; // 表示准备好;
4.2> 写-DS18B20时序
主控制器对DS18B20 : 写‘0’
写0:将总线DQ拉低60~120us;
主控制器对DS18B20 : 写‘1’
第1步:将DQ拉低0~15us;
第2步:将DQ拉高,释放总线;
!注意:写0与写1之间,需要间隔1us;
4.3> 读-DS18B20时序
读‘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> 命令
命令或数据,都是从最低有效位开始发送;
All data and commands are transmitted least significant bit(LSB) first over the 1-Wire bus.
5> 程序设计
5.1> 编程思路
5.2> 代码实现
#include "bsp.h"//----------------------------------------------------------------------------//
// Hardware timing Level function //
//----------------------------------------------------------------------------///*** @brief DS18B20 initialization sequence* @param None* @retval state*/
uchar8_t DS18B20_Init(void)
{uchar8_t i = 0;TEMP_DQ = 1; // Keep DQ idle stateTEMP_DQ = 0; Delay_10us(90); // >=480us TEMP_DQ = 1; // Release the TEMP_DQ /* Detect DS18B20*/while (TEMP_DQ) {i++;if (i > 5) {return 1; // failed}Delay_10us(2); }return 0; // successful
}/*** @brief MCU write 1Byte data to DS18B20 * @param dat 1byte data* @retval*/
void DS18B20_WriteByte(uchar8_t DataByte)
{uchar8_t i = 0;for (i = 0; i < 8; i++) {TEMP_DQ = 0; Delay_10us(1); // 1~15usTEMP_DQ = DataByte & 0x01; // LSB first over the TEMP_DQ bus;Delay_10us(8); // 60~120USTEMP_DQ = 1; // Relase TEMP_DQ bus;DataByte >>= 1; // _nop_();}
}/*** @brief MCU Read 1Byte data from DS18B20* @param None* @retval*/
uchar8_t DS18B20_ReadByte(void)
{uchar8_t val = 0;uchar8_t temp = 0;uchar8_t i = 0;for (i= 0; i < 8; i++) {TEMP_DQ = 0; // pulling the TEMP_DQ bus low for 1us; _nop_();TEMP_DQ = 1; // Relase TEMP_DQ bus;_nop_();_nop_(); temp = TEMP_DQ; // LSB first over the TEMP_DQ bus; 1001 1101val = (val >> 1) | (temp << 7); Delay_10us(6); // 45us} return val;
}void DS18B20_ChangTemp(void)
{DS18B20_Init();Delay_ms(1);DS18B20_WriteByte(0xcc); // SKIP ROM DS18B20_WriteByte(0x44); // CONVERT TDelay_ms(800);
}void DS18B20_ReadTemp(void)
{ DS18B20_Init();Delay_ms(1);DS18B20_WriteByte(0xcc); // SKIP ROM DS18B20_WriteByte(0xbe); // READ SCRATCHPAD
}//----------------------------------------------------------------------------//
// BSP Level function //
//----------------------------------------------------------------------------//
float TEMP_Read(void)
{uchar8_t temp_H = 0;uchar8_t temp_L = 0;short temp = 0; // 有符号16bit;float t = 0;DS18B20_ChangTemp(); DS18B20_ReadTemp(); temp_L = DS18B20_ReadByte(); temp_H = DS18B20_ReadByte(); temp = temp_L | (temp_H << 8);t = temp * 0.0625; printf("temp = %g °C\n\r", t); // Debugreturn t;
}
6> 联调测试
设计一个,随时可以调用,并准确的定时器,思考这个问题;
目前程序的延时都是,估算;
测量波形时,捕捉us级别脉冲边沿时,可以先把示波器时间轴设置大,方便测量;