DS18B20是一款常用的高精度的单总线数字温度测量芯片。具有体积小,硬件开销低,抗干扰能力强,精度高的特点,因此能得到广泛地运用。本次主要分享基于DS18B20的温度精准采集,我们知道DS18B20是美国DSLIAS公司推出的单总线数字温度传感器,具有微型化、低功耗、高性能、抗干扰能力强、易匹配处理器等优点。处理器与DS18B20通信只需要一根数据线即可,同时该数据线还可以向挂接的DS18B20供电。DS18B20内部自带A/D转换器,通过内部的温度采集、A/D转换等一系列过程,将温度值以规定的格式转换为数据并输出,用户可以通过一些简单的算法,将数据还原为温度值。其分辨率可以达到12位,满足一般情况下对温度采集的需要。与模拟温度传感器相比,DS18B20省去了信号调理、A/D转换等通道处理电路,从而使得系统线路简单,成本低廉。
测温范围为-55℃到+125℃,在-10℃到+85℃范围内误差为±0.4°。返回16位二进制温度数值,主机和从机通信使用单总线,即使用单线进行数据的发送和接收。在使用中不需要任何外围元件,独立芯片即可完成工作。掉电保护功能 DS18B20 内部含有 EEPROM ,通过配置寄存器可以设定数字转换精度和报警温度,在系统掉电以后,它仍可保存分辨率及报警温度的设定值。每个DS18B20都有独立唯一的64位-ID,此特性决定了它可以将任意多的DS18b20挂载到一根总线上,通过ROM搜索读取相应DS18B20的温度值。宽电压供电,电压2.5V~5.5V。
DS18B20返回的16位二进制数代表此刻探测的温度值,其高五位代表正负。如果高五位全部为1,则代表返回的温度值为负值。如果高五位全部为0,则代表返回的温度值为正值。后面的11位数据代表温度的绝对值,将其转换为十进制数值之后,再乘以0.0625即可获得此时的温度值。
精英板上针对温湿度传感接入已经设计专门接口,即板上U4位置。

这里采用一个自购的小模块接入,借助其它废弃的元器件管脚,插入圆形的插座上,然后杜邦线引入。如果有单独的DS18B20元器件,则无需转接。我们知道DS18B20是一款l-wire总线接口的器件,即与外部的处理器通信只有一根线,因此,通信流程就显得稍微复杂,需要用MCU的I/O口软件模拟l-wire的时序。
一线式通讯部分代参考如下:
static uint8_t ds18b20_read_bit(void)
{
uint8_t data = 0;
DS18B20_DQ_OUT(0);
delay_us(2);
DS18B20_DQ_OUT(1);
delay_us(12);
if (DS18B20_DQ_IN)
{
data = 1;
}
delay_us(50);
return data;
}
/**
* @brief 从DS18B20读取一个字节
* @param 无
* @retval 读到的数据
*/
static uint8_t ds18b20_read_byte(void)
{
uint8_t i, b, data = 0;
for (i = 0; i < 8; i++)
{
b = ds18b20_read_bit(); /* DS18B20先输出低位数据 ,高位数据后输出 */
data |= b << i; /* 填充data的每一位 */
}
return data;
}
/**
* @brief 写一个字节到DS18B20
* @param data: 要写入的字节
* @retval 无
*/
static void ds18b20_write_byte(uint8_t data)
{
uint8_t j;
for (j = 1; j <= 8; j++)
{
if (data & 0x01)
{
DS18B20_DQ_OUT(0); /* Write 1 */
delay_us(2);
DS18B20_DQ_OUT(1);
delay_us(60);
}
else
{
DS18B20_DQ_OUT(0); /* Write 0 */
delay_us(60);
DS18B20_DQ_OUT(1);
delay_us(2);
}
data >>= 1; /* 右移,获取高一位数据 */
}
}
/**
* @brief 开始温度转换
* @param 无
* @retval 无
*/
static void ds18b20_start(void)
{
ds18b20_reset();
ds18b20_check();
ds18b20_write_byte(0xcc); /* skip rom */
ds18b20_write_byte(0x44); /* convert */
}
/**
* @brief 初始化DS18B20的IO口 DQ 同时检测DS18B20的存在
* @param 无
* @retval 0, 正常
* 1, 不存在/不正常
*/
uint8_t ds18b20_init(void)
{
GPIO_InitTypeDef gpio_init_struct;
DS18B20_DQ_GPIO_CLK_ENABLE(); /* 开启DQ引脚时钟 */
gpio_init_struct.Pin = DS18B20_DQ_GPIO_PIN;
gpio_init_struct.Mode = GPIO_MODE_OUTPUT_OD; /* 开漏输出 */
gpio_init_struct.Pull = GPIO_PULLUP; /* 上拉 */
gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; /* 高速 */
HAL_GPIO_Init(DS18B20_DQ_GPIO_PORT, &gpio_init_struct); /* 初始化DS18B20_DQ引脚 */
/* DS18B20_DQ引脚模式设置,开漏输出,上拉, 这样就不用再设置IO方向了, 开漏输出的时候(=1), 也可以读取外部信号的高低电平 */
ds18b20_reset();
return ds18b20_check();
}
/**
* @brief 从ds18b20得到温度值(精度:0.1C)
* @param 无
* @retval 温度值 (-550~1250)
* [url=home.php?mod=space&uid=1902110]@NOTE[/url] 返回的温度值放大了10倍.
* 实际使用的时候,要除以10才是实际温度.
*/
short ds18b20_get_temperature(void)
{
uint8_t flag = 1; /* 默认温度为正数 */
uint8_t TL, TH;
short temp;
ds18b20_start(); /* ds1820 start convert */
ds18b20_reset();
ds18b20_check();
ds18b20_write_byte(0xcc); /* skip rom */
ds18b20_write_byte(0xbe); /* convert */
TL = ds18b20_read_byte(); /* LSB */
TH = ds18b20_read_byte(); /* MSB */
if (TH > 7)
{/* 温度为负,查看DS18B20的温度表示法与计算机存储正负数据的原理一致:
正数补码为寄存器存储的数据自身,负数补码为寄存器存储值按位取反后+1
所以我们直接取它实际的负数部分,但负数的补码为取反后加一,但考虑到低位可能+1后有进位和代码冗余,
我们这里先暂时没有作+1的处理,这里需要留意 */
TH = ~TH;
TL = ~TL;
flag = 0; /* 温度为负 */
}
temp = TH; /* 获得高八位 */
temp <<= 8;
temp += TL; /* 获得底八位 */
/* 转换成实际温度 */
if (flag == 0)
{ /* 将温度转换成负温度,这里的+1参考前面的说明 */
temp = (double)(temp+1) * 0.625;
temp = -temp;
}
else
{
temp = (double)temp * 0.625;
}
return temp;
}int main(void)
{
uint8_t t = 0;
float temp,float_num;
short temperature;
HAL_Init(); /* 初始化HAL库 */
sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
delay_init(72); /* 延时初始化 */
usart_init(115200); /* 串口初始化为115200 */
led_init(); /* 初始化LED */
while (ds18b20_init()) /* DS18B20初始化 */
{
printf("DS18B20 Init Error\\r\\n");
delay_ms(200);
}
printf("DS18B20 OK\\r\\n");
while (1)
{
if (t % 50 == 0) /* 每200ms读取一次 */
{
temperature = ds18b20_get_temperature();
temp = (float)temperature * 0.0625;
if (temperature < 0)
{
printf("采集的温度为:-%.2f\\r\\n",temp);
}
printf("采集的温度为:%.2f\\r\\n",temp);
}
delay_ms(4);
t++;
if (t == 100)
{
t = 0;
LED0_TOGGLE(); /* LED0闪烁 */
}
}
}编译完成后,接入JLink调试器,选择JLink调试下载方式,并勾选下载完成后自动重启复位,检查下载算法是否ok。

板上实物接线如下图所示:
连接DS18B20时千万要注意电源的正负极方向,连接后小模块的红色指示灯会被点亮,然后打开串口调试助手,波特率设置115200,打开串口,然后将手指紧贴DS18B20的元器件上,串口打印出的采集温度值则会随之改变。实测采集的温度比较稳定,干扰少,很精准。效果如下视频文件所示:
我要赚赏金
