- DS18B20介绍
1.单线接口,1wire总线接口,1个IO可挂多个传感器
2.不需要外围电路,一般情况下需要上拉一个电阻到VCC即可。
3.测量范围从-55℃到125℃,最大分辨率为0.5℃
4.供电我们一般3.3V~5V 的CPU都直接可以使用。
- 温度的计算
DS18B20内部提供温度为0.5℃分辨率的值。其温度读数是以16bit带有符号位的二进制补码形式进行存储。传感器支持多种精度温度的读取9~12bit,最大支持12bit。由于温度传感器默认为12bit,因此我们以12bit精度来读取,关于怎么转换精度,因为用的比较少,这里就不介绍了,思路就是只需要向DS18B20相应的寄存器的写入对应值即可。温度存储如下图1
图1 DS18B20温度存放方式
从图1中我们看到温度值由LSB和MSB组成,低八位带有小数部分,高八位带有符号位。我们看LSB最低位为1/16,因此2进制的1位代表1/16=0.0625℃。这么就简单了,对于正温度,温度值就是除过符号位的值*0.0625,例如图1中125℃为0000 0111 1101 0000换算成10进制为:2000,那么温度就是2000*0.0625=125;对于负温度,我们知道是按照补码形式存放的那么,我们进行换算成正温度即可。例如-10.125℃的二进制:1111 1111 0101 1110 经过取反加1后为:0000 0000 1010 0010 其十进制为162,温度就是162*0.0625=10.125℃ 温度符号单独自己加入即可。
- 读取温度的过程
对于DS18B20来说,每一次读取温度的流程如下:
DS18B20复位—>ROM操作(匹配ROM or 跳过匹配) —>执行转换命令—>读取温度值—>温度计算和转换。
在复位之前我们先考虑对GPIO的初始化,因为器件时单线通信,1个GPIO既需要输出还需要输入采集,因此我们需要把GPIO设置为多种模式进行调用,首先看GPIO的初始化,
代码如下:
void DS18B20_GPIO_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(DS18B20_GPIO_CLK,ENABLE); GPIO_InitStructure.GPIO_Pin = DS18B20_GPIO_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(DS18B20_GPIO_PORT, &GPIO_InitStructure ); /*默认上拉数据线,释放总线*/ GPIO_SetBits(DS18B20_GPIO_PORT, DS18B20_GPIO_PIN); }
其中宏的定义如下:
/************************** DS18B20 连接引脚定义********************************/ #define DS18B20_GPIO_CLK RCC_APB2Periph_GPIOA #define DS18B20_GPIO_PORT GPIOA #define DS18B20_GPIO_PIN GPIO_Pin_3 /************************** DS18B20 函数宏定义********************************/ #define DS18B20_GPIO_L GPIO_ResetBits ( DS18B20_GPIO_PORT, DS18B20_GPIO_PIN ) #define DS18B20_GPIO_H GPIO_SetBits ( DS18B20_GPIO_PORT, DS18B20_GPIO_PIN ) #define DS18B20_GPIO_ReadData GPIO_ReadInputDataBit ( DS18B20_GPIO_PORT, DS18B20_GPIO_PIN )
对于GPIO初始化我们初始化为推完输出模式,因为所有通信都是以主机拉低数据信号开始,也就是需要输出模式。总线为高电平为空闲状态。
GPIO设置为输入模式:
void DS18B20_Mode_IPU(void) { GPIO_InitTypeDef GPIO_InitStructure; /*选择要控制的DS18B20_DQ_GPIO_PORT引脚*/ GPIO_InitStructure.GPIO_Pin = DS18B20_GPIO_PIN; /*设置引脚模式为浮空输入模式*/ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; /*调用库函数,初始化DS18B20_DQ_GPIO_PORT*/ GPIO_Init(DS18B20_GPIO_PORT, &GPIO_InitStructure); }
然后在把GPIO设置成输出状态 用于总线状态转换:
void DS18B20_Mode_Out_PP(void) { GPIO_InitTypeDef GPIO_InitStructure; /*选择要控制的DS18B20_DQ_GPIO_PORT引脚*/ GPIO_InitStructure.GPIO_Pin = DS18B20_GPIO_PIN; /*设置引脚模式为通用推挽输出*/ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; /*设置引脚速率为50MHz */ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; /*调用库函数,初始化DS18B20_DQ_GPIO_PORT*/ GPIO_Init(DS18B20_GPIO_PORT, &GPIO_InitStructure); }
这样就完成了对GPIO的初始化。有了初始化我们就是看一下器件的复位,手册对器件的复位这么写道,主机发送复位脉冲,接着由从属器件返回存在的应答脉冲(PS,脉冲都是低电平)。具体时序参考手册P18页,这么写道: 主机发送低电平复位信号(拉低信号480us-960us)—>等待15us-60us—>接收从器件返回的低电平应答信号(该应答信号持续60us-240us)。
具体代码如下:
unsigned char DS18B20_Rst(void) { unsigned char timeout=0; unsigned char timewait=0; DS18B20_Mode_Out_PP();/* 主机设置为推挽输出 */ DS18B20_GPIO_L; ds18b20_delay(75); /* 主机至少产生480us的低电平复位信号 */ DS18B20_GPIO_H; /* 主机在产生复位信号后,需将总线拉高 释放总线 */ ds18b20_delay(2) ; /*从机接收到主机的复位信号后,会在15~60us后给主机发一个存在脉冲*/ /***********开始检测 器件是否存在***************/ DS18B20_Mode_IPU(); // IO变成输入状态 do { timeout++; //等待15~60us 后从机就会发送低电平 ds18b20_delay(1); //我们在100us内 如果没有读取到低电平,跳出循环 } while ((DS18B20_GPIO_ReadData==1) && timeout<100 ); if (timeout>=100) //判断等待时间超过100us 说明无响应 返回错误值。 { printf("复位失败,从机无响应"); return 1; } else //在100us 检测到低电平 { while ((DS18B20_GPIO_ReadData==0) && timewait<240)//判断低电平持续时间是否符合时序 { timewait++; ds18b20_delay(1); } if(timewait<240) //符合返回正常 { return 0; } else return 1; //不符合返回失败 } }
首先设置为输出模式,然后拉低总线,等待480-960us我们这里等待750us,延迟函数1次为10us,具体我们最后会单独说明这个延迟函数,在这里我们知道是延迟多少就行,拉高总线释放总线等待20us后,改为输入状态,开始循环检测是否有返回低电平应答信号,如果循环100次仍未检测到,说明器件无响应,反之,我们在持续检测低电平持续时间是否符合时序,排除掉误触发。这样就完成了器件的复位操作。
我们把GPIO初始化和复位封装一下,加入到main函数中后,就完成了初始化了,代码如下:
void DS18B20_Open(void) { DS18B20_GPIO_Config (); DS18B20_Rst(); }
DS18B20的初始化我们就说到这里,下一章我们介绍温度读取的剩下部分。
原创文章,作者:小峰,如若转载,请注明出处:http://www.wfblog.com/archives/443.html