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);
        }
    }
}

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

基于温度湿度一体的传感器DHT11 以下是在51单片机上测试成功的代码 #include<at89x52.h> #include<intrins.h>//加上这句下面的 _nop_();就能用 bit xianshiqiehuan; // sbit dht11_dat=P1^6; //开发板用 sbit dht11_dat=P2^0; //使用版用 unsigned char c,count, dht11temp,dht11dat; unsigned char dht11value[5]; unsigned int x,y,z; unsigned char code dat[]={ 0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0x88,}; delay() { unsigned char a; for(a=200;a>0;a--); } display(unsigned char x) //使用版用 { P0=dat[(x0)/10];//十位 P2_3=0; delay(); P2_3=1; P0=dat[(x0)];//个位 P2_2=0; delay(); P2_2=1; } /*display(unsigned char x) //开发板用 { P0=dat[(x0)/10];//十位 P1_2=0; delay(); P1_2=1; P0=dat[(x0)];//个位 P1_3=0; delay(); P1_3=1; } */ delay_1s() { unsigned int i=50000; while(i--); } delay_10us() //10us { _nop_();_nop_();_nop_();_nop_();_nop_();_nop_(); } void delayms(unsigned char x) //1ms单位延时程序 { unsigned char j; while(x--) { for(j=0;j<123;j++){;} } } read_dht11() { unsigned char i; dht11_dat=1; _nop_(); //起始 dht11_dat=0;//拉低总线 delayms(18);//手册要求大于18ms dht11_dat=1;//拉高总线等待dht11回应 while(dht11_dat); // 等待dht11回应 若有回应 dht11_dat=0;往下执行 while(!dht11_dat);//回应后dht11将总线拉低80us,过后又将总线拉高,进入下一步 while(dht11_dat); //拉高80us 又变低,往下执行 进入50us延时 for(i=0;i<24;i++) { while(!dht11_dat);//50us过后...... dht11_dat=1;往下执行 delay_10us();delay_10us();delay_10us();//延时30us,查看总线是高是低, dht11temp=0; //先默认为0处理 if(dht11_dat) dht11temp=1; //1处理 dht11dat=dht11dat<<1; //必须先移动再或 若先或再移本次数据就移动了 dht11dat=dht11dat|dht11temp; dht11value[i/8]=dht11dat; while(dht11_dat);//如果处理的是1,30us过后总线还是1,那就在此等待总线变为0进入下一个50us低电平,不然会重复进行0处理 } } main() { delay_1s(); //要求上电等1秒,让dht11稳定 EA=1;//开放中断 TMOD=0x01;//设T0 为16位计数方式 ET0=1;//定时0中断允许 TR0=1;//开启TR0 while(1) { if(!xianshiqiehuan) //显示温度 display(dht11value[2]) ; else {display(dht11value[0]) ; //显示湿度 P0=0x92&0x7f; //千位显 S.代表湿度 P2_5=0; delay(); P2_5=1; } } } dingshi() interrupt 1 //定时器0服务程序 { TH0=0; TL0=0; count++; if(count==55){count=0;read_dht11();xianshiqiehuan=~xianshiqiehuan; } //在切换显示时采集,以防中断采样带来的显示闪烁 }
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值