STM32F407VET6 -- FreeRTOS -- DS18B20温度检测
1、DS18B20 单线数字温度传感器,即“一线器件”,其具有独特的优点:
a、采用单总线的接口方式 与微处理器连接时仅需要一根线即可实现微处理器与 DS18B20 的双向通讯。单总线具有经济性好,抗干扰能力强,适合于恶劣环境的现场温度测量。
b、测量温度范围宽,测量精度高 DS18B20 的测量范围为 -55 ℃ ~+ 125 ℃ ; 在 -10~+ 85°C范围内,精度为 ± 0.5°C 。
c、在使用中不需要任何外围元件。
d、支持多点组网功能,多个 DS18B20 可以并联在惟一的单线上,实现多点测温。
e、供电方式灵活 DS18B20 可以通过内部寄生电路从数据线上获取电源。因此,当数据线上的时序满足一定的要求时,可以不接外部电源,从而使系统结构更趋简单,可靠性更高。
f、测量参数可配置 DS18B20 的测量分辨率可通过程序设定 9~12 位。
g、负压特性电源极性接反时,温度计不会因发热而烧毁,但不能正常工作。
h、掉电保护功能 DS18B20 内部含有 EEPROM ,在系统掉电以后,它仍可保存分辨率及报警温度的设定值。
2、DS18B20内部结构:
DS18B20内部主要包括,64位ROM、2字节温度输出寄存器、1字节上下警报寄存器(TH和TL)和1字节配置寄存器。ROM中的64位序列号是出厂前被光刻好的,它可以看作是该DS18B20的地址序列码,每个DS18B20的64位序列号均不相同,这样就可以实现一根总线挂接多个DS18B20的目的。配置寄存器允许用户将温度 - 数字转换的分辨率设置为9,10,11或12位。DS18B20控制引脚需要一个上拉电阻,并通过开漏模式连接到总线。DS18B20无需外部电源也可运行,当总线为高电平时,通过DQ引脚提高电源,并将电存储在Cpp电容中,在总线处于低电平时为器件供电,这种方法称为“寄生电源”。另外DS18B20也可通过VDD供电。
3、DS18B20内部构成:
高速暂存存储器由9个字节组成,分别为:
1、温度的低八位数据
2、温度的高8位数据
3、高温阈值
4、低温阈值
5、配置寄存器
6、保留
7、保留
8、保留
9、CRC校验
器件断电时,EEPROM寄存器中的数据保留,上电后,EEPROM数据被重新加载到相应的寄存器位置,也可以使用命令随时将数据从EEPROM重新加载到暂存器中。
4、温度寄存器数据格式:
DS18B20中的温度传感器数据用16位二进制形式提供,其中S为符号位(正数S=0,负数S=1)。温度传感器的分辨率可由用户配置为9、10、11或12位,分别对应0.5℃、0.25 ℃、0.125℃和0.0625℃的增量。开机时的默认分辨率是12位。如果DS18B20配置为12位分辨率,那么温度寄存器中的所有位都将包含有效数据。对于11位分辨率,bit0没有定义。对于10位分辨率,bit1和bit0没有定义,对于9位分辨率,bit2、bit1和bit0没有定义。
5、TH和TL报警寄存器格式:
TH和TL寄存器存储温度报警触发值,符号位S表示值是正还是负,对于正数,S=0,对于负数,S=1。DS18B20执行温度转换后,将温度值与用户定义的两个报警触发值进行比较,由于TH和TL是8位寄存器,因此在比较TH和TL时只使用温度寄存器的第11位到第4位,如果被测温度低于或等于TL值,或高于或等于TH值,则在DS18B20内部存在报警条件,并设置报警标志。主设备可以通过发出一个[EC]命令来检查总线上所有DS18B20的报警标志状态。TH和TL寄存器是非易失性的(EEPROM),当设备断电时,它们将保留数据。可以通过内存部分暂存器的字节2和字节3访问TH和TL。
6、配置寄存器数据格式:
在配置寄存器中,我们可以通过R0和R1设置DS18B20的转换分辨率,DS18B20在上电后默认R0=1和R1=1(12分辨率),寄存器中的第7位和第0位到4位保留给设备内部使用。
7、 初始化时序:
static ePinType_t pin;
static eGpioType_t gpio;
static float TemperatureValue = 0.0f;
* 函数功能:DS18B20器件复位
* 形 参:无
* 返 回 值:0=成功,1=失败
********************************************************/
static unsigned char ds18b20_reset(void)
{
unsigned char status = 0;
unsigned short timeout = 0;
delay_us(520); // 持续最少480us
gpio_set_pin(gpio, pin, 1); // 释放总线
delay_us(10); // 需要等待15 - 60us
gpio_config(gpio, pin, eGPIO_IN_UP, 1); // 设置总线为输入模式
while(gpio_read_pin(gpio, pin) != 0)
{
if(++timeout > 0xFFF0U)
{
status = 1;
break;
}
}
timeout = 0;
while(gpio_read_pin(gpio, pin) == 0)
{
if(++timeout > 0xFFF0U)
{
status = 1;
break;
}
}
return status;
}
* 函数功能:向DS18B20写一个字节数据
* 形 参:写入的字节数据
* 返 回 值:无
********************************************************/
static void ds18b20_write_byte(unsigned char dat)
{
unsigned char i = 0;
{
gpio_set_pin(gpio, pin, 0);
delay_us(2); // 总线拉低持续时间要大于1us
if(dat & (0x01U << i)) // 低位先发
{
gpio_set_pin(gpio, pin, 1);
}
delay_us(60); // 延时60us,等待ds18b20采样读取
gpio_set_pin(gpio, pin, 1); // 释放总线
delay_us(2);
}
}
/********************************************************
* 函数功能:从DS18B20读一个字节数据
* 形 参:无
* 返 回 值:读出的字节数据
********************************************************/
static unsigned char ds18b20_read_byte(void)
{
unsigned char i = 0;
unsigned char dat = 0;
for(i = 0; i < 8; i++)
{
gpio_set_pin(gpio, pin, 0); // 拉低总线
delay_us(2);
gpio_set_pin(gpio, pin, 1); // 释放总线
gpio_config(gpio, pin, eGPIO_IN_UP, 1); // 设置总线为输入模式
delay_us(10);
if(gpio_read_pin(gpio, pin) != 0) // 读时隙产生7 us后读取总线数据
{
dat |= 0x01U << i; // 低位先收
}
delay_us(50); // 延时60us,满足读时隙的时间长度要求
gpio_config(gpio, pin, eGPIO_OUT_PP_UP, 1); // 释放总线
delay_us(2);
}
return dat;
}
/********************************************************
* 函数功能:DS18B20温度采集线程
* 形 参:parg:线程形参
* 返 回 值:无
********************************************************/
static void ds18b20_task(void *parg)
{
unsigned char data = 0;
unsigned short temp = 0;
while(1)
{
if(ds18b20_reset() != 0)
{
continue;
}
os_critical_enter(); // 进入临界区
ds18b20_write_byte(0xCC); // skip rom
ds18b20_write_byte(0x44); // 启动温度转换
os_critical_exit(); // 退出临界区
os_delay(500);
if(ds18b20_reset() != 0)
{
continue;
}
os_critical_enter(); // 进入临界区
ds18b20_write_byte(0xCC); // skip rom
ds18b20_write_byte(0xBE); // 发出读取命令
data = ds18b20_read_byte(); // 读出温度低八位
temp = ds18b20_read_byte(); // 读出温度高八位
// 计算温度值
temp = (temp << 8) | data;
// 高五位为符号位,当温度为正的时候,高五位的字节是0,当温度为负的时候,高五位字节为1
if((temp & 0xF800) != 0)
{
temp = (~temp) + 1; // 正温度值直接计算,负温度值需取反加1
TemperatureValue = -0.0625f; // 温度为负
}
else
{
TemperatureValue = 0.0625f;
}
// DS18B20的分辨率是0.0625度
TemperatureValue = TemperatureValue * temp;
os_critical_exit(); // 退出临界区
os_delay(1500); // 1.5s采集一次温度数据
}
}
/********************************************************
* 函数功能:DS18B20初始化
* 形 参:gpiox:引脚端口
pinx:引脚号
* 返 回 值:无
********************************************************/
unsigned int ds18b20_init(eGpioType_t gpiox, ePinType_t pinx)
{
gpio = gpiox;
pin = pinx;
// 初始化引脚
gpio_config(gpio, pin, eGPIO_OUT_PP_UP, 1);
// 创建温度采集线程
if(os_task_create(ds18b20_task, NULL, 128, eOS_PRIO_LL) != 0)
{
return 1; // 创建失败
}
return 0;
}
/********************************************************
* 函数功能:读取温度值
* 形 参:无
* 返 回 值:温度值
********************************************************/
float ds18b20_temperature_value_get(void)
{
return TemperatureValue;
}