DS18B20温度传感器工作原理
DS18B20技术性能特征
①、独特的单总线接口方式,DS18B20在与微处理器连接时仅需要一条口线即可实现微处理器与DS18B20的双向通讯。大大提高了系统的抗干扰性。
② 、测温范围 -55℃~+125℃,精度为±0.5℃。
③、支持多点组网功能,多个DS18B20可以并联在唯一的三线上,最多只能并联8个,实现多点测温,如果数量过多,会使供电电源电压过低,从而造成信号传输的不稳定。
④、工作电源: 3.0~5.5V/DC(可以数据线寄生电源)。
⑤ 、在使用中不需要任何外围元件。
⑥、测量结果以9~12位数字量方式串行传送。
DS18B20硬件连接
DS18B20通信类型
单总线是一种半双工通信方式
DS18B20共有6种信号类型:复位脉冲、应答脉冲、写0、写1、读0和读1。
所有这些信号,除了应答脉冲以外,都由主机发出同步信号。并且发送所有的命令和数据都是字节的低位在前。
复位脉冲
单总线上的所有通信都是以初始化序列开始。主机输出低电平,保持低电平时间至少480us,,以产生复位脉冲。接着主机释放总线,4.7K的上拉电阻将单总线拉高,延时15~60us,并进入接收模式(Rx)。接着DS18B20拉低总线60~240 us,以产生低电平应答脉冲。
写时序
写时序包括写0时序和写1时序。所有写时序至少需要60us,且在2次独立的写时序之间至少需要1us的恢复时间,两种写时序均起始于主机拉低总线。
写0时序:主机输出低电平,延时60us,然后释放总线,延时2us。
写1时序:主机输出低电平,延时2us,然后释放总线,延时60us。
读时序
单总线器件仅在主机发出读时序时,才向主机传输数据,所以,在主机发出读数据命令后,必须马上产生读时序,以便从机能够传输数据。所有读时序至少需要60us,且在2次独立的读时序之间至少需要1us的恢复时间。每个读时序都由主机发起,至少拉低总线1us。主机在读时序期间必须释放总线,并且在时序起始后的15us之内采样总线状态。
典型的读时序过程为:主机输出低电平延时2us,然后主机转入输入模式延时12us,然后读取单总线当前的电平,然后延时50us。
温度读取过程
DS18B20的典型温度读取过程为:
①复位
②发SKIPROM命令(0XCC)
③发开始转换命令(0X44)
④复位
⑤发送SKIPROM命令(0XCC)
⑥发读存储器命令(0XBE)
⑦连续读出两个字节数据(即温度)
⑧结束。
温度数据的存储
转化后得到的11位数据,存储在18B20的两个8比特的RAM中, MSB的前面5位是符号位,如果测得的温度大于0,这5位为0,只要将测到的数值乘于0.0625即可得到实际温度;如果温度小于0,这5位为1,测到的数值需要取反再乘于0.0625即可得到实际温度。
例如+125℃的数字输出为07D0H,,-25.0625℃的数字输出为FE6FH
实例分析
测量温度,并串口打印
cubemx配置
只需要将连接传感器的信号线的管脚配置为输出模式即可
代码实操
ds18b20.h
#ifndef __DS18B20_H #define __DS18B20_H #include "stm32f4xx_hal.h" //IO方向设置 #define DS18B20_IO_IN() {GPIOG->MODER&=~(3<<(6*2));GPIOG->MODER|=0<<(6*2);} //PG6输入模式 #define DS18B20_IO_OUT() {GPIOG->MODER&=~(3<<(6*2));GPIOG->MODER|=1<<(6*2);} //PG6输出模式 IO操作函数 #define DS18B20_OUT_LOW HAL_GPIO_WritePin(GPIOG, GPIO_PIN_6, GPIO_PIN_RESET) //数据端口 PG6 #define DS18B20_OUT_HIGH HAL_GPIO_WritePin(GPIOG, GPIO_PIN_6, GPIO_PIN_SET) //数据端口 PG6 #define DS18B20_DQ_IN HAL_GPIO_ReadPin(GPIOG, GPIO_PIN_6) //数据端口 PG6 uint8_t DS18B20_Init(void); //初始化DS18B20 short DS18B20_Get_Temp(void); //获取温度 void DS18B20_Start(void); //开始温度转换 void DS18B20_Write_Byte(uint8_t dat);//写入一个字节 uint8_t DS18B20_Read_Byte(void); //读出一个字节 uint8_t DS18B20_Read_Bit(void); //读出一个位 uint8_t DS18B20_Check(void); //检测是否存在DS18B20 void DS18B20_Reset(void); //复位DS18B20 #endif
ds18b20.c
#include "ds18b20.h" uint32_t usctick = 0; uint32_t time_delay = 0; extern TIM_HandleTypeDef htim6; //延时nus //nus为要延时的us数. //nus:0~190887435(最大值即2^32/fac_us@fac_us=168) static uint8_t fac_us = 168; //这里主时钟为168M, 所以在1us内ticks会减168次 void delay_us(uint32_t nus) { uint32_t ticks; uint32_t told,tnow,tcnt=0; uint32_t reload=SysTick->LOAD; //LOAD的值 ticks=nus*fac_us; //1us需要的节拍数 told=SysTick->VAL; //刚进入时的计数器值 while(1) { tnow=SysTick->VAL; if(tnow!=told) { if(tnow<told)tcnt+=told-tnow; //这里注意一下SYSTICK是一个递减的计数器就可以了. else tcnt+=reload-tnow+told; told=tnow; if(tcnt>=ticks)break; //时间超过/等于要延迟的时间,则退出. } }; } //复位DS18B20 void DS18B20_Reset(void) { DS18B20_IO_OUT(); //设置为输出 DS18B20_OUT_LOW ; //拉低DQ delay_us(650); //拉低650us DS18B20_OUT_HIGH ; //拉高DQ delay_us(20); //20US } //等待DS18B20的回应 //返回1:未检测到DS18B20的存在 //返回0:存在 uint8_t DS18B20_Check(void) { uint8_t retry=0; DS18B20_IO_IN(); //设置为输入 //等待DS18B20拉低总线回应,如果超过200us未拉低,则认为未回应 while ((DS18B20_DQ_IN == 1) && (retry<200)) { retry++; delay_us(1); }; if(retry>=200)return 1; //DS18B20超时未拉低总线 else retry=0; //DS18B20拉低总线 while ( (DS18B20_DQ_IN == 0 ) && ( retry < 240) ) //测试拉低总线的时间是否在240us内 { retry++; delay_us(1); }; if(retry>=240)return 1; //超过240us错误 return 0; //正确回应 } //从DS18B20读取一个位 //返回值:1/0 uint8_t DS18B20_Read_Bit(void) { uint8_t data; DS18B20_IO_OUT(); //设置为输出 DS18B20_OUT_LOW ; //拉低DQ delay_us(3); DS18B20_OUT_HIGH ; //拉高DQ DS18B20_IO_IN(); //设置为输入 delay_us(12); if(DS18B20_DQ_IN) data=1; else data=0; delay_us(50); return data; } //从DS18B20读取一个字节 //返回值:读到的数据,先读数据的低位 uint8_t DS18B20_Read_Byte(void) { uint8_t i,j,dat; dat=0; for (i=0;i<8;i++) { j=DS18B20_Read_Bit(); dat=(j<<i)|dat; } return dat; } //写一个字节到DS18B20 //dat:要写入的字节 void DS18B20_Write_Byte(uint8_t dat) { uint8_t j; uint8_t testb; DS18B20_IO_OUT(); //设置为输出 for (j=1;j<=8;j++) { testb=dat&0x01; dat=dat>>1; if(testb) // 写1 { DS18B20_OUT_LOW ; //拉低DQ delay_us(2); DS18B20_OUT_HIGH ; //拉高DQ delay_us(60); } else //写0 { DS18B20_OUT_LOW ; //拉低DQ delay_us(60); DS18B20_OUT_HIGH ; //拉高DQ delay_us(2); } } } void DS18B20_Start(void) { //开始温度转换 DS18B20_Reset(); DS18B20_Check(); DS18B20_Write_Byte(0xcc); // skip rom DS18B20_Write_Byte(0x44); // convert //开始读取温度 DS18B20_Reset(); DS18B20_Check(); DS18B20_Write_Byte(0xcc); // skip rom DS18B20_Write_Byte(0xbe); // convert } //初始化DS18B20的IO口 DQ 同时检测DS的存在 //返回1:不存在 //返回0:存在 uint8_t DS18B20_Init(void) { DS18B20_Reset(); return DS18B20_Check(); } //从ds18b20得到温度值 //精度:0.1C //返回值:温度值 (-550~1250) short DS18B20_Get_Temp(void) { uint8_t temp; uint8_t TL,TH; short tem; DS18B20_Start (); //开始转换读取 TL=DS18B20_Read_Byte(); // LSB TH=DS18B20_Read_Byte(); // MSB if(TH>7) //温度为负 { TH=~TH; TL=~TL; temp=0; //温度为负 }else temp=1; //温度为正 tem=TH; //获得高八位 tem<<=8; tem+=TL;//获得底八位 tem=(double)tem*0.625;//转换 获得不带符号位的11位温度值 if(temp)return tem; //返回温度值 else return -tem; }
main函数
printf("this is DS18B20 test "); if(!DS18B20_Init()) { printf(" DS18B20 is here "); }else { printf(" DS18B20 is not here "); } /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { temperature = DS18B20_Get_Temp(); if(temperature<0) { printf("-"); //显示负号 temperature=-temperature; //转为正数 } printf("temperature = %d.%d ",temperature/10,temperature%10); HAL_Delay(1000); }