本帖最后由 zero949079783 于 2021-10-30 21:37 编辑
开发环境:VSCODE(gcc编译链)+STM32CubeMX(也可以使用HUAWEI-LiteOS-Studio) 。
代码:链接:https://pan.baidu.com/s/1uXfIR0GFQOBZPl1NfQP08w
提取码:6b0c
◎单总线说明
DHT11 器件采用简化的单总线通信。单总线即只有一根数据线,系统中的数据交换、控制均由单总线
完成。设备(主机或从机)通过一个漏枀开路或三态端口连至该数据线,以允许设备在不发送数据时能够
释放总线,而让其它设备使用总线;单总线通常要求外接一个约 4.7kΩ 的上拉电阻,这样,当总线闲置时,
其状态为高电平。由于它们是主从结极,只有主机呼叫从机时,从机才能应答,因此主机访问器件都必须
严格遵循单总线序列,如果出现序列混乱,器件将不响应主机。
◎单总线传送数据位定义
DATA 用于微处理器与 DHT11 之间的通讯和同步,采用单总线数据格式,一次传送 40 位数据,高位先
出。
数据格式:
8bit 湿度整数数据 + 8bit 湿度小数数据 + 8bit 温度整数数据 + 8bit 温度小数数据 + 8bit 校验位。
注:其中湿度小数部分为 0。
◎校验位数据定义
“8bit 湿度整数数据 + 8bit 湿度小数数据 + 8bit 温度整数数据 + 8bit 温度小数数据”8bit 校验位等于
所得结果的末 8 位。
示例一:接收到的 40 位数据为:
0011 0101 0000 0000 0001 1000 0000 0100 0101 0001
湿度高 8 位 湿度低 8 位 温度高 8 位 温度低 8 位 校验位
计算:
0011 0101+0000 0000+0001 1000+0000 0100= 0101 0001
接收数据正确:
湿度:0011 0101(整数)=35H=53%RH 0000 0000(小数)=00H=0.0%RH =>53%RH + 0.0%RH =
53.0%RH
温度:0001 1000(整数)=18H=24℃ 0000 0100(小数)=04H=0.4℃ =>24℃ + 0.4℃ = 24.4℃ ◎特殊说明:
当温度低于 0 ℃ 时温度数据的低 8 位的最高位置为 1。
示例: -10.1 ℃ 表示为 0000 1010 1000 0001
温度:0000 1010(整数)=0AH=10℃,0000 0001(小数)=01H=0.1℃ =>-(10℃+0.1℃)= -10.1℃
示例二:接收到的 40 位数据为:
0011 0101 0000 0000 0001 1000 0000 0100 0100 1001
湿度高 8 位 湿度低 8 位 温度高 8 位 温度低 8 位 校验位
计算:
0011 0101+0000 0000+0001 1000+0000 0100= 0101 0001
0101 0001 不等于 0100 1001
本次接收的数据不正确,放弃,重新接收数据。
◎数据时序图
用户主机(MCU)发送一次开始信号后,DHT11 从低功耗模式转换到高速模式,待主机开始信号结束
后,DHT11 发送响应信号,送出 40bit 的数据,并触发一次信采集。信号发送如图所示。
步骤二:
微处理器的 I/O 设置为输出同时输出低电平,且低电平保持时间不能小于 18ms(最大不得超过 30ms),
然后微处理器的 I/O 设置为输入状态,由于上拉电阻,微处理器的 I/O 即 DHT11 的 DATA 数据线也随之变
高,等待 DHT11 作出回答信号,发送信号如图所示:
步骤三:
DHT11 的 DATA 引脚检测到外部信号有低电平时,等待外部信号低电平结束,延迟后 DHT11 的 DATA
引脚处于输出状态,输出 83 微秒的低电平作为应答信号,紧接着输出 87 微秒的高电平通知外设准备接
收数据,微处理器的 I/O 此时处于输入状态,检测到 I/O 有低电平(DHT11 回应信号)后,等待 87 微秒
的高电平后的数据接收,发送信号如图所示:
步骤四: 由 DHT11 的 DATA 引脚输出 40 位数据,微处理器根据 I/O 电平的变化接收 40 位数据,位数据“0”
的格式为: 54 微秒的低电平和 23-27 微秒的高电平,位数据“1”的格式为: 54 微秒的低电平加 68-74
微秒的高电平。位数据“0”、“1”格式信号如图所示:
结束信号:
DHT11 的 DATA 引脚输出 40 位数据后,继续输出低电平 54 微秒后转为输入状态,由于上拉电阻随
之变为高电平。但 DHT11 内部重测环境温湿度数据,并记录数据,等待外部信号的到来。
#include "DHT11.h"
#include "DHT11.h"
uint16_t Time =0;
/**
* [url=home.php?mod=space&uid=247401]@brief[/url] DHT11 GPIO初始化
* @param
* [url=home.php?mod=space&uid=2817080]@ARG[/url]
*
* @retval 无
*/
void DHT11_Config(void)
{
DHT11_OUT_H();
}
/**
* [url=home.php?mod=space&uid=247401]@brief[/url] DHT11 GPIO输出设置
* @param
* [url=home.php?mod=space&uid=2817080]@ARG[/url] cmd: 1 : DHT11_WRITE 输出
* 0 : DHT11_READ 输入
* @retval 无
*/
//DHT11 GPIO输出设置
void DHT11_Write_Out_Input(uint8_t cmd)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(cmd == DHT11_WRITE )
{
GPIO_InitStruct.Pin = GPIO_PIN_6;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
}
else
{
GPIO_InitStruct.Pin = GPIO_PIN_6;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
}
}
/**
* [url=home.php?mod=space&uid=247401]@brief[/url] DHT11 读一个字节
* @param
* [url=home.php?mod=space&uid=2817080]@ARG[/url]
*
* @retval dat 反回数据
*/
uint8_t DHT11_Read_Byte(void)
{
uint8_t dat = 0;
for(uint8_t i=0;i<8;i++)
{
DHT11_Write_Out_Input(DHT11_READ);
while((DHT11_IN() == Bit_RESET) &&(Time++<1000)); //
Time = 0;
dat <<= 1;
delay_us(4);
if(DHT11_IN() == 1)
{
dat |=0x01;
while((DHT11_IN() == Bit_SET) &&(Time++<1000)); //
}
// else
// {
// dat |=0x00;
// }
}
return dat;
}
/**
* [url=home.php?mod=space&uid=247401]@brief[/url] DHT11 读湿度,温度
* @param
* *HuimH :湿度整数部分
*HuimL :湿度小数部分
*TempH :温度整数部分
*TempL :温度小数部分
* [url=home.php?mod=space&uid=2817080]@ARG[/url]
*
* @retval 0 :数据正确,1 :数据不正确
*/
uint8_t DHT11_Read_Huim_Temp(uint8_t *HuimH,uint8_t *HuimL,uint8_t *TempH,uint8_t *TempL)
{
uint8_t DHT11_Date[5]; //用来保存数据 ,DHT11 一次读40位数据
DHT11_Write_Out_Input(DHT11_WRITE);
DHT11_OUT_L();
delay_ms(20); //拉低后至少18ms
DHT11_OUT_H(); //释放总线
delay_us(4); //释放总线20-40us
DHT11_Write_Out_Input(DHT11_READ);
while((DHT11_IN() == Bit_RESET) &&(Time++<1000)); // 低电平否过去
Time = 0;
while((DHT11_IN() == Bit_SET) &&(Time++<1000)); // 高电平否过去
Time = 0;
for(uint8_t i=0;i<5;i++)
{
DHT11_Date[i] = DHT11_Read_Byte();
}
delay_ms(1);
if(DHT11_Date[0]+DHT11_Date[1]+DHT11_Date[2]+DHT11_Date[3] == DHT11_Date[4] ) //校验和
{
*HuimH = DHT11_Date[0];
*HuimL = DHT11_Date[1];
*TempH = DHT11_Date[2];
*TempL = DHT11_Date[3];
}
else
{
return 1; //数据不正确
}
return 0 ; //数据正确
}
|