3.8 ds18b20温度传感器实验
DS18B20是常用的数字温度传感器,具有体积小,硬件开销低,抗干扰能力强,精度高的特点。DS18B20 单线数字温度传感器,即“一线器件”,其具有独特的优点:
1,采用单总线的接口方式 与微处理器连接时仅需要一条口线即可实现微处理器与 DS18B20 的双向通讯。单总线具有经济性好,抗干扰能力强,适合于恶劣环境的现场温度测量,使用方便等优点,使用户可轻松地组建传感器网络,为测量系统的构建引入全新概念。
2,测量温度范围宽,测量精度高 DS18B20 的测量范围为 -55 ℃ ~+ 125 ℃ ; 在 -10~+ 85°C范围内,精度为 ± 0.5°C 。
3,在使用中不需要任何外围元件。
4,持多点组网功能多个 DS18B20 可以并联在惟一的单线上,实现多点测温。
5,供电方式灵活 DS18B20 可以通过内部寄生电路从数据线上获取电源。因此,当数据线上的时序满足一定的要求时,可以不接外部电源,从而使系统结构更趋简单,可靠性更高。
6,测量参数可配置 DS18B20 的测量分辨率可通过程序设定 9~12 位。
7,负压特性电源极性接反时,温度计不会因发热而烧毁。
8,掉电保护功能 DS18B20 内部含有 EEPROM ,在系统掉电以后,它仍可保存分辨率及报警温度的设定值。
DS18B20 具有体积更小、适用电压更宽、更经济、可选更小的封装方式,更宽的电压适用范围,适合于构建自己的经济的测温系统,因此也就被设计者们所青睐。
DS18B20内部结构:
主要由4部分组成:64 位ROM、温度传感器、非挥发的温度报警触发器TH和TL、配置寄存器。ROM中的64位序列号是出厂前被光刻好的,它可以看作是该DS18B20的地址序列码,每个DS18B20的64位序列号均不相同。64位ROM的排的循环冗余校验码(CRC=X8+X5+X^4+1)。 ROM的作用是使每一个DS18B20都各不相同,这样就可以实现一根总线上挂接多个DS18B20的目的。
首先创建读取ds18b20的任务:
define TASK_SIZE 256
static OS_STK ds18b20_task_stk[TASK_SIZE];
void UserMain(void)
{
tls_os_task_create(NULL, NULL,
ds18b20_task,
NULL,
(void *)ds18b20_task_stk,
TASK_SIZE * sizeof(u32),
32,
0);
}
在任务中初始化DS18B20,并获取DS18B20序列号后读取温度值。
static void ds18b20_task(void *data)
{
uint8_t uc, ucDs18b20Id [ 8 ];
int i;
printf("\r\n this is a ds18b20 test demo \r\n");
while( DS18B20_Init() )
{
for(i=0;i<1000;i++)
{
us_delay(1000);
}
printf("\r\n ds18b20 exit \r\n");
}
printf("\r\n ds18b20 ok \r\n");
DS18B20_ReadId ( ucDs18b20Id ); // 读取 DS18B20 的序列号
printf("\r\nDS18B20: 0x");
for ( uc = 0; uc < 8; uc ++ ) // 打印 DS18B20 的序列号
printf ( "%.2x", ucDs18b20Id [ uc ] );
for( ; ; )
{
printf ( "\r\ntemperature: %.1f\r\n", DS18B20_GetTemp_MatchRom ( ucDs18b20Id ) ); // 打印通过 DS18B20 序列号获取的温度值
DS18B20_DELAY_MS(1000);
}
}
其它函数:
/**
-
@brief DS18B20 初始化函数
-
@param 无
-
@retval 无
*/
uint8_t DS18B20_Init(void)
{
DS18B20_GPIO_Config ();DS18B20_DQ_1;
DS18B20_Rst();
return DS18B20_Presence ();
}
/*
-
函数名:DS18B20_GPIO_Config
-
描述 :配置DS18B20用到的I/O口
-
输入 :无
-
输出 :无
*/
static void DS18B20_GPIO_Config(void)
{tls_gpio_cfg(DS18B20_DQ_GPIO_PORT, WM_GPIO_DIR_OUTPUT, WM_GPIO_ATTR_PULLHIGH);//配置为上拉输出
}
/*
- 函数名:DS18B20_Mode_IPU
- 描述 :使DS18B20-DATA引脚变为输入模式
- 输入 :无
- 输出 :无
*/
static void DS18B20_Mode_IPU(void)
{
tls_gpio_cfg(DS18B20_DQ_GPIO_PORT, WM_GPIO_DIR_INPUT, WM_GPIO_ATTR_FLOATING);//配置为上拉输出
}
/*
- 函数名:DS18B20_Mode_Out_PP
- 描述 :使DS18B20-DATA引脚变为输出模式
- 输入 :无
- 输出 :无
*/
static void DS18B20_Mode_Out_PP(void)
{
tls_gpio_cfg(DS18B20_DQ_GPIO_PORT, WM_GPIO_DIR_OUTPUT, WM_GPIO_ATTR_PULLHIGH);//配置为上拉输出
}
/*
*主机给从机发送复位脉冲
/
static void DS18B20_Rst(void)
{
/ 主机设置为推挽输出 */
DS18B20_Mode_Out_PP();
DS18B20_DQ_0;
/* 主机至少产生480us的低电平复位信号 */
us_delay(750);
/* 主机在产生复位信号后,需将总线拉高 */
DS18B20_DQ_1;
/*从机接收到主机的复位信号后,会在15~60us后给主机发一个存在脉冲*/
us_delay(15);
}
/*
-
检测从机给主机返回的存在脉冲
-
0:成功
-
1:失败
*/
static uint8_t DS18B20_Presence(void)
{
uint8_t pulse_time = 0;/* 主机设置为上拉输入 */
DS18B20_Mode_IPU();/* 等待存在脉冲的到来,存在脉冲为一个60~240us的低电平信号
- 如果存在脉冲没有来则做超时处理,从机接收到主机的复位信号后,会在15~60us后给主机发一个存在脉冲
/
while( DS18B20_DQ_IN() && pulse_time<100 )
{
pulse_time++;
us_delay(1);
}
/ 经过100us后,存在脉冲都还没有到来*/
if( pulse_time >=100 )
return 1;
else
pulse_time = 0;
/* 存在脉冲到来,且存在的时间不能超过240us */
while( !DS18B20_DQ_IN() && pulse_time<240 )
{
pulse_time++;
us_delay(1);
}
if( pulse_time >=240 )
return 1;
else
return 0;
} - 如果存在脉冲没有来则做超时处理,从机接收到主机的复位信号后,会在15~60us后给主机发一个存在脉冲
/*
-
从DS18B20读取一个bit
*/
static uint8_t DS18B20_ReadBit(void)
{
uint8_t dat;/* 读0和读1的时间至少要大于60us /
DS18B20_Mode_Out_PP();
/ 读时间的起始:必须由主机产生 >1us <15us 的低电平信号 */
DS18B20_DQ_0;
us_delay(10);/* 设置成输入,释放总线,由外部上拉电阻将总线拉高 */
DS18B20_Mode_IPU();
//us_delay(2);if( DS18B20_DQ_IN() == SET )
dat = 1;
else
dat = 0;/* 这个延时参数请参考时序图 */
us_delay(45);return dat;
}
/*
-
从DS18B20读一个字节,低位先行
*/
static uint8_t DS18B20_ReadByte(void)
{
uint8_t i, j, dat = 0;for(i=0; i<8; i++)
{
j = DS18B20_ReadBit();
dat = (dat) | (j<<i);
}return dat;
}
/*
-
写一个字节到DS18B20,低位先行
*/
static void DS18B20_WriteByte(uint8_t dat)
{
uint8_t i, testb;
DS18B20_Mode_Out_PP();for( i=0; i<8; i++ )
{
testb = dat&0x01;
dat = dat>>1;
/* 写0和写1的时间至少要大于60us /
if (testb)
{
DS18B20_DQ_0;
/ 1us < 这个延时 < 15us */
us_delay(8);DS18B20_DQ_1; us_delay(58); } else { DS18B20_DQ_0; /* 60us < Tx 0 < 120us */ us_delay(70); DS18B20_DQ_1; /* 1us < Trec(恢复时间) < 无穷大*/ us_delay(2); }
}
}
/**
-
@brief 跳过匹配 DS18B20 ROM
-
@param 无
-
@retval 无
*/
static void DS18B20_SkipRom ( void )
{
DS18B20_Rst();DS18B20_Presence();
DS18B20_WriteByte(0XCC); /* 跳过 ROM */
}
/**
-
@brief 执行匹配 DS18B20 ROM
-
@param 无
-
@retval 无
*/
static void DS18B20_MatchRom ( void )
{
DS18B20_Rst();DS18B20_Presence();
DS18B20_WriteByte(0X55); /* 匹配 ROM */
}
/*
-
存储的温度是16 位的带符号扩展的二进制补码形式
-
当工作在12位分辨率时,其中5个符号位,7个整数位,4个小数位
-
|---------整数----------|-----小数 分辨率 1/(2^4)=0.0625----|
-
低字节 | 2^3 | 2^2 | 2^1 | 2^0 | 2^(-1) | 2^(-2) | 2^(-3) | 2^(-4) |
-
|-----符号位:0->正 1->负-------|-----------整数-----------|
-
高字节 | s | s | s | s | s | 2^6 | 2^5 | 2^4 |
-
温度 = 符号位 + 整数 + 小数*0.0625
/
/* -
@brief 在跳过匹配 ROM 情况下获取 DS18B20 温度值
-
@param 无
-
@retval 温度值
*/
float DS18B20_GetTemp_SkipRom ( void )
{
uint8_t tpmsb, tplsb;
short s_tem;
float f_tem;DS18B20_SkipRom ();
DS18B20_WriteByte(0X44); /* 开始转换 */DS18B20_SkipRom ();
DS18B20_WriteByte(0XBE); /* 读温度值 */tplsb = DS18B20_ReadByte();
tpmsb = DS18B20_ReadByte();s_tem = tpmsb<<8;
s_tem = s_tem | tplsb;if( s_tem < 0 ) /* 负温度 */
f_tem = (~s_tem+1) * 0.0625;
else
f_tem = s_tem * 0.0625;return f_tem;
}
/**
-
@brief 在匹配 ROM 情况下获取 DS18B20 温度值
-
@param ds18b20_id:用于存放 DS18B20 序列号的数组的首地址
-
@retval 无
*/
void DS18B20_ReadId ( uint8_t * ds18b20_id )
{
uint8_t uc;DS18B20_WriteByte(0x33); //读取序列号
for ( uc = 0; uc < 8; uc ++ )
ds18b20_id [ uc ] = DS18B20_ReadByte();
}
/**
-
@brief 在匹配 ROM 情况下获取 DS18B20 温度值
-
@param ds18b20_id:存放 DS18B20 序列号的数组的首地址
-
@retval 温度值
*/
float DS18B20_GetTemp_MatchRom ( uint8_t * ds18b20_id )
{
uint8_t tpmsb, tplsb, i;
short s_tem;
float f_tem;DS18B20_MatchRom (); //匹配ROM
for(i=0;i<8;i++)
DS18B20_WriteByte ( ds18b20_id [ i ] );
DS18B20_WriteByte(0X44); /* 开始转换 */
DS18B20_MatchRom (); //匹配ROM
for(i=0;i<8;i++)
DS18B20_WriteByte ( ds18b20_id [ i ] );
DS18B20_WriteByte(0XBE); /* 读温度值 */
tplsb = DS18B20_ReadByte();
tpmsb = DS18B20_ReadByte();
s_tem = tpmsb<<8;
s_tem = s_tem | tplsb;
if( s_tem < 0 ) /* 负温度 */
f_tem = (~s_tem+1) * 0.0625;
else
f_tem = s_tem * 0.0625;
return f_tem;
}
编译下载到开发板运行: