DHT11是很常用的温湿度传感器,时序也比较简单,如下所示:
直接给出HAL库的驱动:
1 微秒级延时函数
HAL库并没有直接的微秒级延时函数,下面是自己实现的微秒堵塞延时函数(使用定时器TIM3);
/**
* @brief 微秒级延时
*/
void bsp_delay_us(uint16_t us)
{
__HAL_TIM_SET_COUNTER(&htim3, 0);
HAL_TIM_Base_Start(&htim3);
while (__HAL_TIM_GET_COUNTER(&htim3) != us);
HAL_TIM_Base_Stop(&htim3);
}
2 配置DHT11数据引脚的输出模式和输入模式;
/**
* @brief DHT11 输出模式
*/
static void DHT11_Mode_OUT_PP(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Pin = BSP_DHT11_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(BSP_DHT11_PORT, &GPIO_InitStruct);
}
/**
* @brief DHT11 输入模式
*/
static void DHT11_Mode_IN_NP(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Pin = BSP_DHT11_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(BSP_DHT11_PORT, &GPIO_InitStruct);
}
3 读取一个字节的数据(经过测试,延时时间最好设置为 40 ~ 60,这里我设置为50us);
/**
* @brief DHT11 读取字节
*/
uint8_t DHT11_ReadByte(void)
{
uint8_t i, temp = 0;
for (i = 0; i < 8; i++)
{
while (DHT11_IN == 0); // 等待低电平结束
// 经过测试,这个值最好是 40 ~ 60,这里我选择 50 us
bsp_delay_us(50); // 至少延时 40 微秒 低电平为 0 ,高电平为 1
if (DHT11_IN == 1)
{
while (DHT11_IN == 1); // 等待高电平结束
temp |= (uint8_t)(0X01 << (7 - i)); // 先发送高位 MSB
}
else
{
temp &= (uint8_t)~(0X01 << (7 - i));
}
}
return temp;
}
4 完整的读取一次数据(读取数据间隔最好为2s及以上,不然容易出错);
/**
* @brief DHT11 读取一次数据
*/
uint8_t DHT11_ReadData(DHT11_Data_TypeDef *DHT11_Data)
{
DHT11_Mode_OUT_PP(); // 主机输出,主机拉低
DHT11_OUT_0;
HAL_Delay(18); // 延时 18 ms
DHT11_OUT_1; // 主机拉高,延时 30 us
bsp_delay_us(30);
DHT11_Mode_IN_NP(); // 主机输入,获取 DHT11 数据
if (DHT11_IN == 0) // 收到从机应答
{
while (DHT11_IN == 0); // 等待从机应答的低电平结束
while (DHT11_IN == 1); // 等待从机应答的高电平结束
/*开始接收数据*/
DHT11_Data->humi_int = DHT11_ReadByte();
DHT11_Data->humi_deci = DHT11_ReadByte();
DHT11_Data->temp_int = DHT11_ReadByte();
DHT11_Data->temp_deci = DHT11_ReadByte();
DHT11_Data->check_sum = DHT11_ReadByte();
DHT11_Mode_OUT_PP(); // 读取结束,主机拉高
DHT11_OUT_1;
// 数据校验
if (DHT11_Data->check_sum == DHT11_Data->humi_int + DHT11_Data->humi_deci + DHT11_Data->temp_int + DHT11_Data->temp_deci)
{
return 1;
}
else
{
return 0;
}
}
else // 未收到从机应答
{
return 0;
}
}
测试程序:
while (1)
{
if (DHT11_ReadData(&DHT11_Data))
{
DEBUG_INFO("rn读取DHT11成功!rnrn湿度为%d.%d %RH ,温度为 %d.%d℃ rn",
DHT11_Data.humi_int,DHT11_Data.humi_deci,DHT11_Data.temp_int,DHT11_Data.temp_deci);
}
else
{
DEBUG_INFO("Read DHT11 ERROR!rn");
}
HAL_Delay(3000);
}
完整的驱动程序,仅供参考。
bsp_dht11.c
/**
******************************************************************************
* @file bsp_dht11.c
* @author
* @date
* @version v1.0
* @note DHT11 driver
******************************************************************************
*/
#include "tim.h"
#include "bsp_dht11.h"
/**
* @brief DHT11 输出模式
*/
static void DHT11_Mode_OUT_PP(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Pin = BSP_DHT11_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(BSP_DHT11_PORT, &GPIO_InitStruct);
}
/**
* @brief DHT11 输入模式
*/
static void DHT11_Mode_IN_NP(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.Pin = BSP_DHT11_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(BSP_DHT11_PORT, &GPIO_InitStruct);
}
/**
* @brief DHT11 读取字节
*/
uint8_t DHT11_ReadByte(void)
{
uint8_t i, temp = 0;
for (i = 0; i < 8; i++)
{
while (DHT11_IN == 0); // 等待低电平结束
bsp_delay_us(40); // 延时 40 微秒 低电平为 0 ,高电平为 1
if (DHT11_IN == 1)
{
while (DHT11_IN == 1); // 等待高电平结束
temp |= (uint8_t)(0X01 << (7 - i)); // 先发送高位 MSB
}
else
{
temp &= (uint8_t)~(0X01 << (7 - i));
}
}
return temp;
}
/**
* @brief DHT11 读取一次数据
*/
uint8_t DHT11_ReadData(DHT11_Data_TypeDef *DHT11_Data)
{
DHT11_Mode_OUT_PP(); // 主机输出,主机拉低
DHT11_OUT_0;
HAL_Delay(18); // 延时 18 ms
DHT11_OUT_1; // 主机拉高,延时 30 us
bsp_delay_us(30);
DHT11_Mode_IN_NP(); // 主机输入,获取 DHT11 数据
if (DHT11_IN == 0) // 收到从机应答
{
while (DHT11_IN == 0); // 等待从机应答的低电平结束
while (DHT11_IN == 1); // 等待从机应答的高电平结束
/*开始接收数据*/
DHT11_Data->humi_int = DHT11_ReadByte();
DHT11_Data->humi_deci = DHT11_ReadByte();
DHT11_Data->temp_int = DHT11_ReadByte();
DHT11_Data->temp_deci = DHT11_ReadByte();
DHT11_Data->check_sum = DHT11_ReadByte();
DHT11_Mode_OUT_PP(); // 读取结束,主机拉高
DHT11_OUT_1;
// 数据校验
if (DHT11_Data->check_sum == DHT11_Data->humi_int + DHT11_Data->humi_deci + DHT11_Data->temp_int + DHT11_Data->temp_deci)
{
return 1;
}
else
{
return 0;
}
}
else // 未收到从机应答
{
return 0;
}
}
// 测试程序
/*
while (1)
{
if (DHT11_ReadData(&DHT11_Data))
{
DEBUG_INFO("rn读取DHT11成功!rnrn湿度为%d.%d %RH ,温度为 %d.%d℃ rn",
DHT11_Data.humi_int,DHT11_Data.humi_deci,DHT11_Data.temp_int,DHT11_Data.temp_deci);
}
else
{
DEBUG_INFO("Read DHT11 ERROR!rn");
}
HAL_Delay(3000);
}
*/
bsp_dht11.h
#ifndef __BSP_DHT11_H
#define __BSP_DHT11_H
#include "tim.h"
#include "stm32f1xx_hal.h"
#define BSP_DHT11_PORT DHT11_GPIO_Port
#define BSP_DHT11_PIN DHT11_Pin
#define DHT11_OUT_1 HAL_GPIO_WritePin(BSP_DHT11_PORT, BSP_DHT11_PIN, GPIO_PIN_SET)
#define DHT11_OUT_0 HAL_GPIO_WritePin(BSP_DHT11_PORT, BSP_DHT11_PIN, GPIO_PIN_RESET)
#define DHT11_IN HAL_GPIO_ReadPin(BSP_DHT11_PORT, BSP_DHT11_PIN)
typedef struct
{
uint8_t humi_int; // 湿度的整数部分
uint8_t humi_deci; // 湿度的小数部分
uint8_t temp_int; // 温度的整数部分
uint8_t temp_deci; // 温度的小数部分
uint8_t check_sum; // 校验和
} DHT11_Data_TypeDef;
uint8_t DHT11_ReadData(DHT11_Data_TypeDef* DHT11_Data);
#endif /* __BSP_DHT11_H */
上一篇:stm32实用篇4: stm32数据类型长度
下一篇:stm32实用篇6:HAL库 DS18B20 驱动
推荐阅读
史海拾趣
作为一家有影响力的企业,eLED.com Corp始终关注社会责任的履行。公司积极参与各类公益活动,关注教育、环保和扶贫等领域。通过捐款捐物、志愿服务等方式,eLED.com Corp为社会做出了积极的贡献。此外,公司还注重员工培训和福利待遇的提升,努力为员工创造一个良好的工作环境和发展空间。通过这些举措的实施,eLED.com Corp不仅赢得了社会的广泛赞誉和支持,还为企业的发展注入了新的动力。
随着第一款产品的成功,Electric Imp Inc.公司开始积极拓展市场。公司与多家知名厂商建立了合作关系,将物联网设备管理平台应用于智能家居、工业自动化、智慧城市等领域。同时,公司还加强了与高校、科研机构的合作,共同研发新技术、新产品。这些努力使得公司在物联网领域的影响力逐渐扩大。
在电子行业竞争日益激烈的背景下,ELM Technology Corporation展现出了卓越的市场拓展能力。公司管理层准确把握市场趋势,及时调整产品策略,积极拓展国内外市场。通过与国际知名企业的合作,ELM成功打入国际市场,其产品在多个国家和地区得到了广泛应用。同时,公司还积极寻求与国内企业的合作机会,共同推动电子行业的发展。
ELM Technology Corporation自创立之初,就致力于电子技术的研发与创新。公司聚集了一批顶尖的科研人才,不断探索新的电子技术和解决方案。在某一关键时期,ELM推出了一款具有革命性的电子产品,该产品在市场上引起了巨大反响,不仅极大地提升了用户体验,还推动了整个电子行业的发展。通过不断的技术创新,ELM逐渐在电子行业中树立了领先地位。
随着全球经济的不断融合和发展,Bussmann公司也开始了其全球化战略。公司在全球范围内设立生产基地和研发中心,吸引和培养了大量的优秀人才。同时,公司也加大了对新技术和新产品的研发投入,不断推出具有竞争力的新产品。在全球市场上,Cooper Bussmann的电路保护方案广泛应用于各行各业,并获得了UL、CE、CSA等认证机构的认可。
这些故事展示了BUSSMANN公司在电子行业中的发展历程和取得的成就。从创业初期的艰辛与坚持,到汽车熔断器的崛起,再到库柏工业的收购与融合,以及芯片保险丝的创新突破和全球化战略的实施,BUSSMANN公司始终秉持着创新、质量和服务的理念,不断推动电子行业的发展和进步。
请注意,以上故事是基于BUSSMANN公司的历史和发展情况创作的,具体细节可能并不完全准确。如需了解更多关于BUSSMANN公司的信息,建议查阅相关的历史资料或访问其官方网站。
0 引言 数字化信息系统实验室(Digital Information System,DIS)是新一代的中小学实验教学系统,是先进的数字技术应用到实验教学的产物,也是探究、创新的实验教学新理念注入传统实验教学后的必然结果。2006年,教育部将DIS纳入了中小学实验仪 ...… 查看全部问答∨ |
|
Flash与S3C44B0X连接时地址线为什么要偏移一位,对应的代码也不甚清楚,劳烦各位大侠给看看。小弟先在此谢过了。 Flash与S3C44B0X连接时地址线为什么要偏移一位,对应的代码也不甚清楚,劳烦各位大侠给看看。小弟先在此谢过了。 Flash与S3C44B0X的接口电路图如图2所示。处理器ADDR20~1对应着Flash ROM的A19~0,偏移了1位,这是由于S3C44B0X是按照字节编址的, ...… 查看全部问答∨ |
用C8051F020与PC机之间串口通讯. 单片机用中断方式接收数据,用查询方式发送数据. 我的程序是为了实现:定义5字节数据为一帧,PC机向单片机发送数据,当数据到达一帧(5个字节)的时候,单片机向PC机将这一帧数据发送出去. 我用了2个BUFF,第1个BUFF用于 ...… 查看全部问答∨ |
用C语言给51单片机编程时,怎么给外部单元的地址赋值(单片机的指针问题) 初学51单片机,有些问题请教! 我知道在标准c语言里面是不能给指定的一个地址单元赋值的,但是不知道单片机这里能不能这样。 问题1:keil c51中怎么才能使用DPTR寄存器?用keil时包含<reg51.h>后我可以使用DPH和DPL但是不能使用DPTR, ...… 查看全部问答∨ |