STM32HAL库 DHT11驱动+0.96寸4针OLED显示
单片机:STM32F103C8T6
软件版本:STM32CubeMX 4.20.1
单片机固件包:STM32Cube_FW_F1_V1.4.0
本代码为DHT11的驱动代码,OLED驱动相关代码请阅读以下这篇博客:STM32HAL库 0.96寸4针OLED驱动代码
本代码是参考网络上的部分程序代码编写,仅用于学习和交流。希望能给各位读者些许帮助。
根据DHT11手册,可得以下信息:
一次完整的数据传输为40bit,高位先出。
数据格式:8bit湿度整数数据+8bit湿度小数数据+8bit温度整数数据+8bit温度小数数据+8bit校验和
数据传送正确时校验和数据等于“8bit湿度整数数据+8bit湿度小数数据+8bit温度整数数据+8bit温度小数数据”所得结果的末8位。
用户MCU发送一次开始信号后,DHT11从低功耗模式转换到高速模式,等待主机开始信号结束后,DHT11发送响应信号,送出40bit的数据,并触发一次信号采集,用户可选择读取部分数据.从模式下,DHT11接收到开始信号触发一次温湿度采集如果没有接收到主机发送开始信号,DHT11不会主动进行温湿度采集.采集数据后转换到低速模式。
1.通讯过程如图所示
总线空闲状态为高电平,主机把总线拉低等待DHT11响应,主机把总线拉低必须大于18毫秒,保证DHT11能检测到起始信号。DHT11接收到主机的开始信号后,等待主机开始信号结束,然后发送80us低电平响应信号.主机发送开始信号结束后,延时等待20-40us后, 读取DHT11的响应信号,主机发送开始信号后,可以切换到输入模式,或者输出高电平均可, 总线由上拉电阻拉高。
总线为低电平,说明DHT11发送响应信号,DHT11发送响应信号后,再把总线拉高80us,准备发送数据,每一bit数据都以50us低电平时隙开始,高电平的长短定了数据位是0还是1.格式见下面图示.如果读取响应信号为高电平,则DHT11没有响应,请检查线路是否连接正常.当最后一bit数据传送完毕后,DHT11拉低总线50us,随后总线由上拉电阻拉高进入空闲状态。
数字0信号表示方法如图所示:
数字1信号表示方法.如图所示:
dht11.c代码:
/*************************************************
// 文件说明: DHT11驱动代码
// 创 建 人: mnWu522
// 日期: 2020-2-20
// 修 改 人:
// 修改日期: 20xx-xx-xx
*************************************************/
#include "dht11.h"
#include "tim.h"
#include <string.h>
#include "common.h"
#include "oled.h"
uint8_t DHT_data[5];
//DHT11引脚初始化
void DHT_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
DHT_GPIO_CLK_ENABLE();
GPIO_InitStruct.Pin = DHT_DAT_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOx_DHT_PORT, &GPIO_InitStruct);
DHT_DAT_ON();
}
void DHT_DAT_GPIO_Output_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
DHT_GPIO_CLK_ENABLE();
GPIO_InitStruct.Pin = DHT_DAT_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOx_DHT_PORT, &GPIO_InitStruct);
}
void DHT_DAT_GPIO_Input_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
DHT_GPIO_CLK_ENABLE();
GPIO_InitStruct.Pin = DHT_DAT_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOx_DHT_PORT, &GPIO_InitStruct);
}
//DHT11复位
void DHT_Reset(void)
{
DHT_DAT_GPIO_Output_Init();
DHT_DAT_ON();
}
//DHT11读1Byte数据
uint8_t DHT_Read_Byte(void)
{
uint8_t i;
uint8_t data = 0;
// DHT_DAT_GPIO_Input_Init();//DAT设置为输入
for(i=0; i<8; i++)
{
data <<= 1;
while(!READ_DHT_DAT());//每一位数据前会有一个50us的低电平时间,等待该低电平结束
//26-28us的高电平表示该位是0,70us高电平表示该位是1
Delay_us(30);//延时30us后检测电平状态
if(READ_DHT_DAT())
{
data |= 0x01;
while(READ_DHT_DAT());
}
}
return data;
}
//DHT11读数据
void DHT_ReadData(void)
{
uint8_t i;
DHT_DAT_GPIO_Output_Init();//DAT设置为输出
DHT_DAT_OFF();//低电平大于18ms发送开始信号
Delay_ms(20);
DHT_DAT_ON();
Delay_us(40);//延时20-40us
DHT_DAT_GPIO_Input_Init();//DAT设置为输入
if(!READ_DHT_DAT())
{
while(!READ_DHT_DAT());
}
while(READ_DHT_DAT());
for(i=0; i<5; i++)
{
DHT_data[i] = DHT_Read_Byte();
}
Delay_us(50);
}
void DHT_ShowData(void)
{
int i,j,k,p;
DHT_ReadData();
DHT_Reset();
OLED_ALL_Clear();
for(i=0; i<5; i++)
{
j = 0;p = (int)DHT_data[i];
if(p/100 != 0)
{
k = p/100;
OLED_Draw_8_6_ASCII(i,j,16+k);
j += 6;p = p - k * 100;
k = p/10;
OLED_Draw_8_6_ASCII(i,j,16+k);
j += 6;p = p - k * 10;
OLED_Draw_8_6_ASCII(i,j,16+p);
}
else if(p/10 != 0)
{
k = p/10;
OLED_Draw_8_6_ASCII(i,j,16+k);
j += 6;p = p - k * 10;
OLED_Draw_8_6_ASCII(i,j,16+p);
}
else
{
OLED_Draw_8_6_ASCII(i,j,16+p);
}
}
}
dht11.h代码:
#ifndef __DHT11_H__
#define __DHT11_H__
#include "stm32f1xx_hal.h"
///
#define DHT_GPIO_CLK_ENABLE() __HAL_RCC_GPIOB_CLK_ENABLE()
#define GPIOx_DHT_PORT GPIOB
#define DHT_DAT_PIN GPIO_PIN_4
#define DHT_DAT_ON() HAL_GPIO_WritePin(GPIOx_DHT_PORT, DHT_DAT_PIN, GPIO_PIN_SET)
#define DHT_DAT_OFF() HAL_GPIO_WritePin(GPIOx_DHT_PORT, DHT_DAT_PIN, GPIO_PIN_RESET)
#define DHT_DAT_TOGGLE() HAL_GPIO_TogglePin(GPIOx_DHT_PORT, DHT_DAT_PIN)
#define READ_DHT_DAT() HAL_GPIO_ReadPin(GPIOx_DHT_PORT, DHT_DAT_PIN)
///
extern uint8_t DHT_data[5];
void DHT_GPIO_Init(void);
void DHT_DAT_GPIO_Output_Init(void);
void DHT_DAT_GPIO_Input_Init(void);
void DHT_Reset(void);
uint8_t DHT_Read_Byte(void);
void DHT_ReadData(void);
void DHT_ShowData(void);
#endif
注意事项:
读取DHT11模块数据周期不易小于2s。(即运行一次DHT_ShowData();后应加上Delay_ms(2000);形成有至少两秒的延时)