DHT11+OLED显示+串口打印

一、部分代码详解

DHT11.c

        一个字节是八位,因此需要循环八次,来读取一个字节

for (i=0; i<8; i++)    
{	 
    // 等待信号变为高电平
    while (DHT11_DATA_IN() == Bit_RESET);

    // 延迟40微秒,确保数据有效
    Delay_us(40);    

    // 如果信号为高电平
    if (DHT11_DATA_IN() == Bit_SET)
    {
        // 等待信号变为低电平
        while(DHT11_DATA_IN() == Bit_SET);

        // 设置相应的位为1
        temp |= (uint8_t)(0x01 << (7 - i));
    }
    else
    {
        // 如果信号为低电平,则相应位保持为0
        temp &= (uint8_t) ~ (0x01<<(7-i)); 
    }
}

DHT11 数据位的分配遵循一个固定的格式,每次通信时,DHT11 会发送一个包含 40 位的数据包。这个数据包包含了五个字节,每个字节有 8 位。以下是具体的位分配情况:

数据包结构

  • 湿度整数部分:8 位
  • 湿度小数部分:8 位
  • 温度整数部分:8 位
  • 温度小数部分:8 位
  • 校验位:8 位

详细说明

  1. 湿度整数部分:第一个字节表示湿度的整数部分。
  2. 湿度小数部分:第二个字节表示湿度的小数部分。
  3. 温度整数部分:第三个字节表示温度的整数部分。
  4. 温度小数部分:第四个字节表示温度的小数部分。
  5. 校验位:第五个字节是校验位,它是前面四个字节的累加和(忽略溢出)。
uint8_t Read_DHT11(DHT11_Data_TypeDef *DHT11_Data)
{  
	DHT11_Mode_Out_PP();
	DHT11_DATA_OUT(LOW);
	Delay_ms(18);

	DHT11_DATA_OUT(HIGH); 

	Delay_us(30);  

	DHT11_Mode_IPU();

	if(DHT11_DATA_IN() == Bit_RESET)     
	{
		while(DHT11_DATA_IN() == Bit_RESET);

		while(DHT11_DATA_IN() == Bit_SET);

		DHT11_Data -> humi_int = Read_Byte();

		DHT11_Data -> humi_deci = Read_Byte();

		DHT11_Data -> temp_int = Read_Byte();

		DHT11_Data -> temp_deci = Read_Byte();

		DHT11_Data -> check_sum= Read_Byte();


		DHT11_Mode_Out_PP();
		DHT11_DATA_OUT(HIGH);

		if (DHT11_Data -> check_sum == DHT11_Data -> humi_int + DHT11_Data -> humi_deci + DHT11_Data -> temp_int + DHT11_Data -> temp_deci)
			return SUCCESS;
		else 
			return ERROR;
	}
	else
	{		
		return ERROR;
	}   
}

二、完整代码

DHT11.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "DHT11.h"

// 配置用于与DHT11通信的GPIO引脚
void DHT11_GPIO_Config(void)
{		
	GPIO_InitTypeDef GPIO_InitStructure;

	// 启用用于DHT11通信的GPIO外设时钟
	RCC_APB2PeriphClockCmd(DHT11_Out_RCC, ENABLE); 
  	// 设置要配置的GPIO引脚
  	GPIO_InitStructure.GPIO_Pin = DHT11_Out_Pin;	
 	// 设置GPIO模式为推挽输出
 	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   
  	// 设置GPIO速度为50MHz
  	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 
  	// 初始化GPIO
  	GPIO_Init(DHT11, &GPIO_InitStructure);		  

	// 设置引脚为高电平
	GPIO_SetBits(DHT11, DHT11_Out_Pin);	 
}

// 设置GPIO模式为上拉输入
static void DHT11_Mode_IPU(void)
{
 	  GPIO_InitTypeDef GPIO_InitStructure;
	  // 设置要配置的GPIO引脚
	  GPIO_InitStructure.GPIO_Pin = DHT11_Out_Pin;
	  // 设置GPIO模式为上拉输入
	  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU ; 
	  // 重新初始化GPIO
	  GPIO_Init(DHT11, &GPIO_InitStructure);	 
}

// 设置GPIO模式为推挽输出
static void DHT11_Mode_Out_PP(void)
{
 	GPIO_InitTypeDef GPIO_InitStructure;

  	// 设置要配置的GPIO引脚
  	GPIO_InitStructure.GPIO_Pin = DHT11_Out_Pin;	

  	// 设置GPIO模式为推挽输出
  	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   

  	// 设置GPIO速度为50MHz
  	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

  	// 重新初始化GPIO
  	GPIO_Init(DHT11, &GPIO_InitStructure);	 	 
}

// 读取一个字节的数据
static uint8_t Read_Byte(void)
{
	uint8_t i, temp=0;

	for (i=0; i<8; i++)    
	{	 
		// 等待信号变为高电平
		while (DHT11_DATA_IN() == Bit_RESET);

		// 延迟40微秒,确保数据有效
		Delay_us(40);    	  

		// 如果信号为高电平
		if (DHT11_DATA_IN() == Bit_SET)
		{
			// 等待信号变为低电平
			while(DHT11_DATA_IN() == Bit_SET);

			// 设置相应的位为1
			temp |= (uint8_t)(0x01 << (7 - i));
		}
		else
		{
			// 如果信号为低电平,则相应位保持为0
			temp &= (uint8_t) ~ (0x01<<(7-i)); 
		}
	}
	// 返回读取到的一个字节数据
	return temp;
}

// 读取DHT11的数据
uint8_t Read_DHT11(DHT11_Data_TypeDef *DHT11_Data)
{  
	// 设置引脚为推挽输出
	DHT11_Mode_Out_PP();
	// 将引脚拉低,启动DHT11的数据传输
	DHT11_DATA_OUT(LOW);
	Delay_ms(18); // 持续18毫秒

	// 将引脚拉高
	DHT11_DATA_OUT(HIGH); 

	// 延迟30微秒
	Delay_us(30);  

	// 设置引脚为上拉输入
	DHT11_Mode_IPU();

	// 检查是否收到了DHT11的应答信号
	if(DHT11_DATA_IN() == Bit_RESET)     
	{
		// 等待信号变为高电平
		while(DHT11_DATA_IN() == Bit_RESET);

		// 等待信号变为低电平
		while(DHT11_DATA_IN() == Bit_SET);

		// 读取湿度整数部分
		DHT11_Data -> humi_int = Read_Byte();

		// 读取湿度小数部分
		DHT11_Data -> humi_deci = Read_Byte();

		// 读取温度整数部分
		DHT11_Data -> temp_int = Read_Byte();

		// 读取温度小数部分
		DHT11_Data -> temp_deci = Read_Byte();

		// 读取校验位
		DHT11_Data -> check_sum= Read_Byte();

		// 设置引脚为推挽输出
		DHT11_Mode_Out_PP();
		// 将引脚拉高,结束本次通信
		DHT11_DATA_OUT(HIGH);

		// 检查校验位是否正确
		if (DHT11_Data -> check_sum == DHT11_Data -> humi_int + DHT11_Data -> humi_deci + DHT11_Data -> temp_int + DHT11_Data -> temp_deci)
			return SUCCESS; // 如果校验通过,返回成功
		else 
			return ERROR; // 否则返回错误
	}
	else
	{		
		return ERROR; // 如果没有收到应答信号,直接返回错误
	}   
}
	 

DHT11.h

#ifndef __DHT11_H
#define __DHT11_H

// 定义用于DHT11通信的GPIO引脚
#define DHT11_Out_Pin		GPIO_Pin_0
// 定义用于DHT11通信的GPIO外设时钟
#define DHT11_Out_RCC		RCC_APB2Periph_GPIOA
// 定义用于DHT11通信的GPIO端口
#define DHT11		GPIOA

// 定义高低电平常量
#define HIGH  1
#define LOW   0

// 定义一个宏来设置DHT11数据引脚的电平
#define DHT11_DATA_OUT(a)	if (a)	\
					GPIO_SetBits(DHT11, DHT11_Out_Pin);\
					else		\
					GPIO_ResetBits(DHT11, DHT11_Out_Pin)

// 定义一个宏来读取DHT11数据引脚的状态
#define  DHT11_DATA_IN()	   GPIO_ReadInputDataBit(DHT11, DHT11_Out_Pin)

// 定义一个结构体来存储DHT11的数据
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;

// 配置用于与DHT11通信的GPIO引脚
void DHT11_GPIO_Config(void);

// 设置GPIO模式为上拉输入
static void DHT11_Mode_IPU(void);

// 设置GPIO模式为推挽输出
static void DHT11_Mode_Out_PP(void);

// 读取DHT11的数据
uint8_t Read_DHT11(DHT11_Data_TypeDef *DHT11_Data);

// 读取一个字节的数据
static uint8_t Read_Byte(void);

#endif // __DHT11_H

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"                      // Header for delay functions
#include "OLED.h"                       // Header for OLED display functions
#include "DHT11.h"                      // Header for DHT11 sensor functions
#include "uart.h"                       // Header for UART communication functions

// 定义一个结构体变量来存储DHT11的数据
DHT11_Data_TypeDef DHT11_Data;

int main(void)
{
    // 初始化OLED显示
    OLED_Init();
    
    // 配置用于与DHT11通信的GPIO引脚
    DHT11_GPIO_Config();
    
    // 串口初始化
    Serial_Init(); 
    
    // 在OLED上显示字符串 "temp:"
    OLED_ShowString(1, 1, "temp:");
    
    // 在OLED上显示字符串 "humidity:"
    OLED_ShowString(2, 1, "humidity:");
    
    while (1)
    {
        // 读取DHT11的数据
        if(Read_DHT11(&DHT11_Data) == SUCCESS)
        {
            // 通过串口打印温度和湿度信息
            Serial_Printf("温度:%d.%d,湿度:%d.%d", 
                          DHT11_Data.temp_int, DHT11_Data.temp_deci,
                          DHT11_Data.humi_int, DHT11_Data.humi_deci);
            
            // 延迟100毫秒
            Delay_ms(100);
            
            // 在OLED上显示湿度的整数部分
            OLED_ShowNum(2, 10, DHT11_Data.humi_int, 2);
            
            // 在OLED上显示小数点
            OLED_ShowString(2, 12, ".");
            
            // 在OLED上显示湿度的小数部分
            OLED_ShowNum(2, 13, DHT11_Data.humi_deci, 2);
            
            // 在OLED上显示温度的整数部分
            OLED_ShowNum(1, 6, DHT11_Data.temp_int, 2);
            
            // 在OLED上显示小数点
            OLED_ShowString(1, 8, ".");
            
            // 在OLED上显示温度的小数部分
            OLED_ShowNum(1, 9, DHT11_Data.temp_deci, 1);
        }
    }
}

 三、完整工程评论区评论获取

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值