九、单总线操作DS18B20采集温度
1、DS18B20温度传感器介绍
- 测温范围为-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即可获得此时的温度值。
2、接线方式
上拉电阻是必须的。
3、DS18B20内部构成
- 64位ROM;
- 存储独有的序列号,出厂前被光刻好的,每个DS18B20序列号均不相同,可以实现一根总线上挂接多个DS18B20的目的。
- 高速暂存器;
- 温度传感器,字节0保存温度低八位,字节1保存温度高八位;
- 温度上限和下限报警触发器,字节2高温触发器数据,字节3低温触发器数据;
- 配置寄存器,允许设置温度分辨率,9、10、11、12位,对应分辨率为0.5、0.25、0.125、0.0625℃。
- 存储器
- 由一个高速RAM和一个可擦除的EEPROM组成,EEPROM存储着温度上下限和配置寄存器的数据。
4、DS18B20工作步骤
- 初始化DS18B20
- 执行ROM命令
- 执行DS18B20功能指令
5、时序介绍
5.1. 初始化
- 单片机拉低总线至少480us,产生复位脉冲,然后释放总线(拉高电平);
- 等待15-60us后DS18B20会拉低信号,在60-240us内低电平表示DS18B20应答;
- DS18B20拉低60-240us后会释放总线,复位脉冲产生释放总线开始到接收完应答信号时间至少480us。
复位初始化代码如下:
1 static u8 DS18B20_Rest(void) 2 { 3 u8 ack=1; 4 DQ_To_Out(); 5 DQ_OUT=0;//拉低总线 6 Delay_Us(500);//拉低总线时间大于480us小于960us 7 DQ_OUT=1; 8 Delay_Us(20); 9 Delay_Us(40);//拉高总线时间15~60us 10 DQ_To_In(); 11 Delay_Us(40);//等待40us后接收数据,60-240us存在数据 12 if(DQ_IN){ 13 ack=1; 14 }else{ 15 ack=0; 16 } 17 Delay_Us(140);//接收时间达到240us,等待DS18B20释放总线 18 Delay_Us(300);//接收存在信号至少480us 19 return ack; 20 }
5.2. 写时序
- 单片机拉低总线至少1us;
- 然后判断发送时序“1”还是时序“0”,DS18B20在15-60us之间采样,在此期间,总线为1则向DS18B20写1,总线为0则向DS18B20写0;
- 当发送时序0时,需要保持拉低单总线时间大于60us并且小于120us,然后释放总线,至少1us进行下一次数据发送;
- 当发送时序1时,需要在拉低总线后15us内释放总线,并在15us-60us之间保持高电平。
写一个字节数据代码如下:
1 static void DS18B20_Write_Byte(u8 cmd) 2 { 3 DQ_To_Out(); 4 for(u8 i=0;i<8;i++){ 5 DQ_OUT=0; 6 Delay_Us(5);//拉低总线至少1us,15us之内拉高发送"1" 7 DQ_OUT=1; 8 Delay_Us(10);//达到15us 9 if(cmd&0x01){//最低位为1,发送"1" 10 DQ_OUT=1; 11 Delay_Us(50);//15-60us内为DS18B20采样时间 12 }else{ 13 DQ_OUT=0; 14 Delay_Us(50);//15-60us内为DS18B20采样时间 15 } 16 DQ_OUT=1;//释放总线 17 Delay_Us(3);//两个写时隙之间时间至少有1us 18 cmd>>=1; 19 } 20 }
5.3. 读时隙
- 单片机拉低单总线至少1us,然后释放总线,在15us之内读取DS18B20发送过来的数据;
- 15us后DS18B20释放总线,然后保持至少45us,开始下一次读时序,两个读时隙之间至少需要1us的恢复时间。
读一字节的代码如下:
1 static u8 DS18B20_Read_Byte(void) 2 { 3 u8 data=0; 4 for(int i=0;i<8;i++){ 5 DQ_To_Out(); 6 DQ_OUT=0; 7 Delay_Us(2);//拉低总线 8 DQ_OUT=1;//释放总线 9 Delay_Us(3);//拉低总线后15us内有效 10 data>>=1; 11 DQ_To_In(); 12 if(DQ_IN){ 13 data|=0x80; 14 } 15 Delay_Us(60);//读时隙至少60us 16 Delay_Us(2); 17 } 18 19 return data; 20 }
6.DS18B20命令
- 0xCC:跳过ROM
- 0x44:温度转换指令
- 0xBE:读暂存器指令
- 0x33:读ROM
- 0x55:匹配ROM,发送此命令后,发送64位的ROM编码进行匹配
- 0xF0:搜索ROM
- 0xEC:警报搜索
7.获取温度的代码如下:
1 static void DS18B20_Start(void) 2 { 3 DS18B20_Rest();//复位初始化DS18B20 4 DS18B20_Write_Byte(0xCC);//跳过ROM指令 5 DS18B20_Write_Byte(0x44);//温度转换指令 6 Delay_Us(100); 7 } 8 9 float DS18B20_Get_Temp(void) 10 { 11 u8 TL,TH; 12 float temp; 13 int tem; 14 DS18B20_Start(); 15 DS18B20_Rest();//复位初始化DS18B20 16 DS18B20_Write_Byte(0xCC);//跳过ROM指令 17 DS18B20_Write_Byte(0xBE);//读取数据指令 18 19 TL=DS18B20_Read_Byte(); 20 TH=DS18B20_Read_Byte(); 21 22 //转换温度数据,没有考虑负数情况 23 tem=TH<<8; 24 tem+=TL; 25 temp=tem*6.25; 26 return temp; 27 }
8.头文件和其他代码
1 #ifndef __DS18B20_H__ 2 #define __DS18B20_H__ 3 #include "stm32f10x.h" 4 #include "sys.h" 5 #include "delay.h" 6 7 #define DQ_IN PAin(0) 8 #define DQ_OUT PAout(0) 9 10 #define DQ_To_Out() {GPIOA->CRL&=0xFFFFFFF0;GPIOA->CRL|=3<<0;} 11 #define DQ_To_In() {GPIOA->CRL&=0xFFFFFFF0;GPIOA->CRL|=8<<0;} 12 13 //初始化DS18B20 14 void DS18B20_Init(void); 15 //改变引脚输出输入状态 16 //void DQ_To_In(void); 17 //void DQ_To_Out(void); 18 //复位初始化DS18B20 19 static u8 DS18B20_Rest(void); 20 //写一字节数据 21 static void DS18B20_Write_Byte(u8 cmd); 22 //读一字节数据 23 static u8 DS18B20_Read_Byte(void); 24 //开启温度转换命令 25 static void DS18B20_Start(void); 26 //读取温度数据 27 float DS18B20_Get_Temp(void); 28 29 #endif 30 31 32 void DS18B20_Init(void) 33 { 34 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); 35 36 GPIO_InitTypeDef GPIO_InitStruct; 37 GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0; 38 GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; 39 GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; 40 GPIO_Init(GPIOA,&GPIO_InitStruct); 41 42 Delay_Init(); 43 } 44 45 //void DQ_To_In(void) 46 //{ 47 // GPIO_InitTypeDef GPIO_InitStruct; 48 // GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0; 49 // GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU; 50 // GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; 51 // GPIO_Init(GPIOA,&GPIO_InitStruct); 52 //} 53 54 //void DQ_To_Out(void) 55 //{ 56 // GPIO_InitTypeDef GPIO_InitStruct; 57 // GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0; 58 // GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; 59 // GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; 60 // GPIO_Init(GPIOA,&GPIO_InitStruct); 61 //}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具