历史上的今天
今天是:2024年11月03日(星期日)
2021年11月03日 | stm32实用篇6:HAL库 DS18B20 驱动
2021-11-03 来源:eefocus
DS18B20是很常用的温度传感器,精度很高,测试结果如下:

整个驱动程序基本是根据时序写的。要注意的地方有两个:
1 读数据的时间 < 15us,这个值要实际测试,跟自己实现的延时函数效率有关,我使用的是10us,这个值如果设置的不合理,会直接导致整个数据读取出错;
2 建议使用DS18B20_GetTemp_SkipRom函数,不推荐使用设备号相关的那个读取函数,不太稳定;
HAL库驱动程序源码:
bsp_ds18b20.c
/**
******************************************************************************
* @file bsp_ds18b20.c
* @author
* @date
* @version v1.0
* @note DHT11 driver
******************************************************************************
*/
#include "bsp_ds18b20.h"
/**
* @brief DS18B20 输出模式
*/
static void DS18B20_Mode_OUT_PP(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Pin = BSP_DS18B20_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(BSP_DS18B20_PORT, &GPIO_InitStruct);
}
/**
* @brief DS18B20 输入模式
*/
static void DS18B20_Mode_IN_NP(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Pin = BSP_DS18B20_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(BSP_DS18B20_PORT, &GPIO_InitStruct);
}
/**
* @brief 主机给从机发送复位脉冲
*/
static void DS18B20_Reset(void)
{
DS18B20_Mode_OUT_PP(); // 主机输出
DS18B20_OUT_0; // 主机至少产生 480us 的低电平复位信号
bsp_delay_us(750);
DS18B20_OUT_1; // 主机在产生复位信号后,需将总线拉高
// 从机接收到主机的复位信号后,会在 15 ~ 60 us 后给主机发一个存在脉冲
bsp_delay_us(15);
}
/**
* @brief 检测从机给主机返回的存在脉冲
* @return 0:成功 1:失败
*/
static uint8_t DS18B20_Presence(void)
{
uint8_t pulse_time = 0;
DS18B20_Mode_IN_NP(); // 主机设为输入
// 等待存在脉冲的到来,存在脉冲为一个 60 ~ 240 us 的低电平信号
// 如果存在脉冲没有来则做超时处理,从机接收到主机的复位信号后,会在 15 ~ 60 us 后给主机发一个存在脉冲
while (DS18B20_IN && (pulse_time < 100)) // 等待低电平响应脉冲
{
pulse_time++;
bsp_delay_us(1);
}
// 经过 100 us 后,存在脉冲都还没有到来
if (pulse_time >= 100)
{
return 1;
}
else
{
pulse_time = 0;
}
// 响应脉冲(低电平)到来,且存在的时间不能超过 240 us
while(!(DS18B20_IN) && pulse_time < 240)
{
pulse_time++;
bsp_delay_us(1);
}
if(pulse_time >= 240)
{
return 1;
}
else
{
return 0;
}
}
/**
* @brief DS18B20 初始化函数
* @reurn 0:成功 1:失败
*/
uint8_t DS18B20_Init(void)
{
DS18B20_Mode_OUT_PP();
DS18B20_OUT_1;
DS18B20_Reset();
return DS18B20_Presence();
}
/**
* @brief 从DS18B20读取一个bit
*/
static uint8_t DS18B20_ReadBit(void)
{
uint8_t dat;
DS18B20_Mode_OUT_PP(); // 读 0 和读 1 的时间至少要大于 60 us
DS18B20_OUT_0; // 读时间的起始:必须由主机产生 > 1us < 15us 的低电平信号
// 这个时间非常重要,设置为 < 15,需要多次尝试;如果设置不合理,数据会直接出错
// 参数建议设为 10 11 12,具体值要根据延时函数的执行效率测试
bsp_delay_us(10);
DS18B20_Mode_IN_NP(); // 设置成输入,释放总线,由外部上拉电阻将总线拉高
if (DS18B20_IN == 1)
{
dat = 1;
}
else
{
dat = 0;
}
bsp_delay_us(45); // 这个延时参数参考时序图
return dat;
}
/**
* @brief 从 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;
}
/**
* @brief 写一个字节到 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) // 当前位写 1
{
DS18B20_OUT_0;
bsp_delay_us(5); // 拉低发送写时段信号
DS18B20_OUT_1; // 读取电平时间保持高电平
bsp_delay_us(65);
}
else // 当前位写 0
{
DS18B20_OUT_0; // 拉低发送写时段信号
bsp_delay_us(70); // 读取电平时间保持低电平
DS18B20_OUT_1;
bsp_delay_us(2); // 恢复时间
}
}
}
/**
* @brief 跳过匹配 DS18B20 ROM
*/
static void DS18B20_SkipRom(void)
{
DS18B20_Reset();
DS18B20_Presence();
DS18B20_WriteByte(0XCC); /* 跳过 ROM */
}
/**
* @brief 执行匹配 DS18B20 ROM
*/
static void DS18B20_MatchRom(void)
{
DS18B20_Reset();
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;
int16_t 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.0625f;
}
else
{
f_tem = s_tem * 0.0625f;
}
return f_tem;
}
/**
* @brief 在匹配 ROM 情况下获取 DS18B20 温度值
* @param ds18b20_id:用于存放 DS18B20 序列号的数组的首地址
*/
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;
int16_t 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.0625f;
}
else
{
f_tem = s_tem * 0.0625f;
}
return f_tem;
}
// 测试程序
#if 0
uint8_t uc, ucDs18b20Id[8];
while (DS18B20_Init())
{
printf("rn no ds18b20 exit rn");
}
printf("rn ds18b20 exit rn");
DS18B20_ReadId(ucDs18b20Id); // 读取 DS18B20 的序列号
printf("rnDS18B20的序列号是: 0x");
for (uc = 0; uc < 8; uc++) // 打印 DS18B20 的序列号
{
printf("%.2x", ucDs18b20Id[uc]);
}
while (1)
{
printf("rn温度: %.1frn", DS18B20_GetTemp_SkipRom());
HAL_Delay(1000); /* 1s 读取一次温度值 */
}
#endif
bsp_ds18b20.h
/**
******************************************************************************
* @file bsp_ds18b20.h
* @author
* @date
* @version v1.0
* @note DS18B20 driver
******************************************************************************
*/
#ifndef __BSP_DS18B20_H
#define __BSP_DS18B20_H
#include "bsp_conf.h"
#define BSP_DS18B20_PORT TEMP_SENSOR_GPIO_Port
#define BSP_DS18B20_PIN TEMP_SENSOR_Pin
#define DS18B20_OUT_1 HAL_GPIO_WritePin(BSP_DS18B20_PORT, BSP_DS18B20_PIN, GPIO_PIN_SET)
#define DS18B20_OUT_0 HAL_GPIO_WritePin(BSP_DS18B20_PORT, BSP_DS18B20_PIN, GPIO_PIN_RESET)
#define DS18B20_IN HAL_GPIO_ReadPin(BSP_DS18B20_PORT, BSP_DS18B20_PIN)
uint8_t DS18B20_Init(void);
void DS18B20_ReadId(uint8_t *ds18b20_id);
float DS18B20_GetTemp_SkipRom(void);
float DS18B20_GetTemp_MatchRom(uint8_t * ds18b20_id);
#endif /* __BSP_DS18B20_H */
下一篇:STM32的DMA串口直通
史海拾趣
|
老师,我做的是简易数字频率计的,输入信号要进行放大的 ,输入信号的频率是0.1HZ到1MHZ. 我想要一个放大器集成块的,要求的频率达到1MHZ以上的。 老师听说你有这种放大器呀,是不是呀? 老师,下面是我找到的一个高频放大器集成块,你帮我看看 ...… 查看全部问答> |
|
AD6(protel)与PADS基本功能比较一、 原理图部分1、 库⑴ DxDesigner 的原理图库与PCB的库是相互独立的,而且每个原理图符号库都是一个文件,很难实现统一管理;AD6可以使用集成库来统一管理,不仅是原理图符号库与PCB封装库,还能把混合电路仿真库 ...… 查看全部问答> |
|
YAFFS移植到嵌入式Linux的案例非常多,但移植到其他操作系统却从来没见过。 所以想问下各位大虾,YAFFS能否移植到其他嵌入式操作系统?比如Nucleus Plus?… 查看全部问答> |
|
怎么样去理解内部电源层,和内部地层的意思? 如果一个双面板加了一个内部电源层或者地层是不是就变成多面板了?(意思就是内部电源层也是信号层呗,就是为了图个稳定加上的?) 指导一下.… 查看全部问答> |
|
一个在中断中读写USART1的小程序。在不擦除flash下原有程序的情况下,在ram中调试,虽然NVIC中USART1已经enable,USART1寄存器已经有中断使能且收/发事件发生,但无法进入中断。并不是flash中有任意程序都会发生此问题,目前暂未找到规律。而 ...… 查看全部问答> |
|
本帖最后由 jameswangsynnex 于 2015-3-3 19:59 编辑 iPhone 实在太牛了个叉了!!用 iPhone 的童鞋不是整天喊没电吗?于是人们不断发明一些解决方案,这两款小型风力发电机就是专门为 iPhone 充电的。一起来看看有多拉风吧…… 第一款:直充小风 ...… 查看全部问答> |




