您的位置:首页 > 文旅 > 美景 > 郑州网站优化方案_专业旅游网站建设_软文推广是什么_广告联盟app下载赚钱

郑州网站优化方案_专业旅游网站建设_软文推广是什么_广告联盟app下载赚钱

2024/10/5 19:09:44 来源:https://blog.csdn.net/WLSWEET6157/article/details/142597721  浏览:    关键词:郑州网站优化方案_专业旅游网站建设_软文推广是什么_广告联盟app下载赚钱
郑州网站优化方案_专业旅游网站建设_软文推广是什么_广告联盟app下载赚钱

1.引脚定义

Pin名称注释
1VDD供电 3-5.5V
2GND接地,电源负极
3DATA串行数据,单总线
4NC空脚,请悬空

 2.数据格式

  • DHT11 采用单总线协议与单片机通信,单片机发送一次复位信号后,DHT11 从低功耗模式转换到高速模式,等待主机复位结束后,DHT11 发送响应信号,并拉高总线准备传输数据。
  • 一次完整的数据为 40bit,按照高位在前,低位在后的顺序传输。
  • 数据格式为:8bit 湿度整数数据+8bit 湿度小数数据+8bit 温度整数数据+8bit 温度小数数据+8bit 校验和,一共 5 字节(40bit)数据。
  • 由于 DHT11 分辨率只能精确到个位,所以小数部分是数据全为 0。校验和为前 4 个字节数据相加,校验的目的是为了保证数据传输的准确性。

3.操作时序

通过研究时序来实现对DHT11读取数据和通信的功能。下面将时序拆解,有助于更好地理解和封装功能。

3.1 配置DHT11为输入模式(即32单片机配置为输出)

void DHT11_Init_Out(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//开启时钟GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;//推挽输出GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);}

这里通信数据线选择为PA5

3.2 配置DHT11为输出模式(即32单片机配置为输入)

void DHT11_Init_In(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);}

3.3 实现通信开始时序

DHT11时序图

 分析该时序可知,总线空闲状态为高电平,通信开始信号为主机将总线拉低至少18ms,之后再拉高20-40us;之后的总线控制权交由DHT11控制。功能实现代码如下:

void DHT11_Start(void)
{DHT11_Init_Out();//主机输出模式DHT11_BitValue(0);//主机拉低总线Delay_ms(20);//延时20msDHT11_BitValue(1);//主机再次拉高总线Delay_us(22);//延时20msDHT11_Init_In();//开始时序结束,总线交于DHT11控制
}

为了方便更改电位,封装函数

void DHT11_BitValue(uint8_t BitValue)
{GPIO_WriteBit(GPIOA,GPIO_Pin_5, (BitAction)BitValue);//强转为BitAction类型
}

3.4 读取一个字节

时序图

首先关于数字0和数字1信号的时序区分

数字0信号

数字1信号

由时序图可以得知,数字1信号时序高电平持续时间为70us,远大于数字0信号的26us-38us,因此我们可以采用在30us时读取该电平信号,若为高电平,则为数字信号1。另外其余的7个bit操作完全相同,所以我们可以用for把他们套起来。

功能实现代码如下:

uint8_t DHT11_ReadByte(void)
{uint8_t data = 0x00;//给数据付一个初始值uint8_t i = 0;for(i=0;i<8;i++)//循环8次,接受一个字节{while(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_5)==RESET);//等待电平跳变为高电平Delay_us(40);if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_5)==SET)//此时检测电平高低,若为高电平{data |= (0x80>>i);//将该位置一while(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_5)==SET);//等待高电平结束,进入下一位}	}return data;//返回一个字节的数据
}

3.5 接收完整数据

此时我们实现了通信开始,传输一个字节的数据,这样的字节我们一共有5个,每个的操作与上一步相同,所以我们依然可以用for循环五次,来接收数据

 注意在接收数据之前,我们要等待DHT响应 ,所以要判断是否响应

为了方便编写和阅读代码我们用宏定义替换GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_5)

#define  dht11_get  GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_5)void DHT11_Data(uint8_t *temp,uint8_t *shidu)
{int8_t i = 0;int8_t arr[5];DHT11_Start();//通信开始时序DHT11_BitValue(1);//拉高电平,方便检测DHT进入低电平//检测响应信号if(dht11_get == 0){while(dht11_get == 0);//低电平等待跳变高电平while(dht11_get == 1);//高电平等待跳变低电平for(i=0;i<5;i++){arr[i] = DHT11_ReadByte();}DHT11_BitValue(0);//通信结束,DHT11拉低总线Delay_us(50);DHT11_Init_Out();//总线交给主机DHT11_BitValue(1);//拉高总线进入空闲if(arr[0]+arr[1]+arr[2]+arr[3]==arr[4])//校验位检测{*temp = arr[2];*shidu = arr[0];}}
}

3.6 DHT11.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h" #define  dht11_get  GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_5)//电平高低翻转
void DHT11_BitValue(uint8_t BitValue)
{GPIO_WriteBit(GPIOA,GPIO_Pin_5, (BitAction)BitValue);
}//stm32对dht11输出
void DHT11_Init_Out(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);}
//DHT11对stm32输入
void DHT11_Init_In(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);}//通信开始时序
void DHT11_Start(void)
{DHT11_Init_Out();//DHT11_BitValue(1);DHT11_BitValue(0);Delay_ms(20);DHT11_BitValue(1);Delay_us(22);DHT11_Init_In();
}
//读取一个字节
uint8_t DHT11_ReadByte(void)
{uint8_t data = 0x00;int i = 0;for(i=0;i<8;i++){while(dht11_get==RESET);Delay_us(40);if(dht11_get  == SET){data |= (0x80>>i);while(dht11_get==SET);}	}return data;
}//接受完整数据
void DHT11_Data(uint8_t *temp,uint8_t *shidu)
{int8_t i = 0;int8_t arr[5];DHT11_Start();DHT11_BitValue(1);//检测响应信号if(dht11_get==0){while(dht11_get==0);while(dht11_get==1);for(i=0;i<5;i++){arr[i] = DHT11_ReadByte();}DHT11_BitValue(0);Delay_us(50);DHT11_Init_Out();DHT11_BitValue(1);if(arr[0]+arr[1]+arr[2]+arr[3]==arr[4]){*temp = arr[2];*shidu = arr[0];}}
}

3.7 DHT11.h

#ifndef __DHT11_H
#define __DHT11_Huint8_t DHT11_Data(uint8_t *temp,uint8_t *shidu);#endif

 3.8 main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "Serial.h"
#include "DHT11.h"uint8_t temp,shidu;int main(void)
{OLED_Init();Serial_Init();while (1){Delay_s(1);DHT11_Data(&temp,&shidu);Serial_Printf("\r\ntemp=%d", temp);Serial_Printf("\r\nshidu=%d", shidu);Serial_Printf("\r\n");		}
}

3.9 serial.c(串口输出)

#include "stm32f10x.h"                  // Device header
#include <stdio.h>
#include <stdarg.h>void Serial_Init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);USART_InitTypeDef USART_InitStructure;USART_InitStructure.USART_BaudRate = 9600;USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;USART_InitStructure.USART_Mode = USART_Mode_Tx;USART_InitStructure.USART_Parity = USART_Parity_No;USART_InitStructure.USART_StopBits = USART_StopBits_1;USART_InitStructure.USART_WordLength = USART_WordLength_8b;USART_Init(USART1, &USART_InitStructure);USART_Cmd(USART1, ENABLE);
}void Serial_SendByte(uint8_t Byte)//发送一个字节
{USART_SendData(USART1, Byte);while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
}void Serial_SendArray(uint8_t *Array, uint16_t Length)//发送多字节
{uint16_t i;for (i = 0; i < Length; i ++){Serial_SendByte(Array[i]);}
}void Serial_SendString(char *String)//发送字符串
{uint8_t i;for (i = 0; String[i] != '\0'; i ++){Serial_SendByte(String[i]);}
}int fputc(int ch, FILE *f)
{Serial_SendByte(ch);return ch;
}void Serial_Printf(char *format, ...)
{char String[100];va_list arg;va_start(arg, format);vsprintf(String, format, arg);va_end(arg);Serial_SendString(String);
}

3.10 serial.h

#ifndef __SERIAL_H
#define __SERIAL_H#include <stdio.h>void Serial_Init(void);
void Serial_SendByte(uint8_t Byte);
void Serial_SendArray(uint8_t *Array, uint16_t Length);
void Serial_SendString(char *String);
void Serial_Printf(char *format, ...);#endif

4.功能实现

oled显示屏实现

5.不足

 该程序目前还有更进一步的可能,比如在不同的不同时序单元内加入状态返回值,方便判断和调试,欢迎各位与我交流。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com