STM32使用DHT11读取温湿度以及usart串口显示乱码解决

使用开发板为stm32f103. USART串口显示乱码问题往下翻
上原理图:
在这里插入图片描述
在这里插入图片描述
DHT11数据传送过程解释:
在这里插入图片描述
步骤一:
DHT11 上电后(DHT11 上电后要等待 1S 以越过不稳定状态在此期间不能发送任何指令),测试环境
温湿度数据,并记录数据,同时 DHT11 的 DATA 数据线由上拉电阻拉高一直保持高电平;此时 DHT11 的
DATA 引脚处于输入状态,时刻检测外部信号。
步骤二:
微处理器的 I/O 设置为输出同时输出低电平,且低电平保持时间不能小于 18ms(最大不得超过 30ms),
然后微处理器的 I/O 设置为输入状态,由于上拉电阻,微处理器的 I/O 即 DHT11 的 DATA 数据线也随之变
高,等待 DHT11 作出回答信号,发送信号如图所示:
在这里插入图片描述
图 4 主机发送起始信号
步骤三:
DHT11 的 DATA 引脚检测到外部信号有低电平时,等待外部信号低电平结束,延迟后 DHT11 的 DATA
引脚处于输出状态,输出 83 微秒的低电平作为应答信号,紧接着输出 87 微秒的高电平通知外设准备接
收数据,微处理器的 I/O 此时处于输入状态,检测到 I/O 有低电平(DHT11 回应信号)后,等待 87 微秒
的高电平后的数据接收,发送信号如图所示:
在这里插入图片描述
图 5 从机响应信号
步骤四: 由 DHT11 的 DATA 引脚输出 40 位数据,微处理器根据 I/O 电平的变化接收 40 位数据,位数据“0”
的格式为: 54 微秒的低电平和 23-27 微秒的高电平,位数据“1”的格式为: 54 微秒的低电平加 68-74
微秒的高电平。位数据“0”、“1”格式信号如图所示:
在这里插入图片描述

DHT11 的 DATA 引脚输出 40 位数据后,继续输出低电平 54 微秒后转为输入状态,由于上拉电阻随
之变为高电平。但 DHT11 内部重测环境温湿度数据,并记录数据,等待外部信号的到来。
以上就是具体数据读取传送不揍
下面我们看一下伪代码实现:

(1)配置引脚为输出:推挽输出;
(2)输出高电平;延时100ms;
(3)输出低电平;延时20ms;
(4)输出高电平;
(5)配置引脚为输入:浮空输入;
(6)等待从机拉低:(while(引脚电平为高电平);)
(7)等待从机拉高:(while(引脚为低电平);)
(8)取数据:
a)       Dat[5]={0};
b        )For(i=0;i<5;i++)
c)      {
d)      For(j=0;j<8;j++)
e)      {
f)     While();//等待拉低;
g)     While();//等待拉高
h)      //延时30us;
i )      Dat[i]<<=1;
j)       If(输入数据位为1/0)
          Dat[i] |=0x01;
k)}
l)}
(9)校验:前4字节的数据取和的末8位和校验值比较;
(10)取对应的温湿度数据;

注意延时操作,最好使用滴答(毫秒延时)定时器结合系统延时(微妙延时)
下面具体看一下代码的实现

#define DHT11_OUT 1
#define DHT11_IN 2
//PB6
void DHT11_Config(uint8_t p)
{
	RCC->APB2ENR |=(0x01<<3);//开B端口时钟
	
	GPIOB->CRL &=~(0x0F<<24);//端口配置清0
	
	if(p==DHT11_OUT)
		GPIOB->CRL |=(0x01<<24);//通用推挽输出
	else if(p==DHT11_IN)
		GPIOB->CRL |=(0x01<<27);//浮空输入
}

#define DHT11(x) (x?(GPIOB->ODR |=(0x01<<6)):(GPIOB->ODR &=~(0x01<<6)))//高低电平
#define DHT11_Val (GPIOB->IDR & (0x01<<6))  //0100 0000=0x40输入数据寄存器


void DHT11_read(float *Hum,float *Temp)//Hum:湿度   Temp:温度
{
	uint8_t rdata[5]={0};
	uint8_t i,j;
	
//STM32的GPIO引脚配置为输出,输出高电平;
	DHT11_Config(DHT11_OUT);
	DHT11(1);//输出高电平
	DelayMs(100);
	
//GPIO拉低,保持18ms~30ms,再拉高;----起始信号
	DHT11(0);//输出低电平 保持20ms
	DelayMs(20);
	DHT11(1);//拉高电平

//GPIO引脚配置为输入模式;
	DHT11_Config(DHT11_IN);
//等待DHT11拉低;while(总线为高电平);
	while(DHT11_Val);
	
//等待DHT11拉高;while(总线为低电平);-----响应信号
	while(DHT11_Val==0);

	for(i=0;i<5;i++)
	{
		for(j=0;j<8;j++)
		{
			//等待DHT11拉低;while(总线为高电平);
			while(DHT11_Val);//等待数据发送
			
			//等待DHT11拉高;while(总线为低电平);
			while(DHT11_Val==0);//等待数据发送
			
			rdata[i] <<=1;
			
			//判断0/1:延时30us~50us之间,判断当前输入的电平高低。
			DelayUsCnt(40);
			if(DHT11_Val)//此刻输入的是高电平为“1”
			{
				rdata[i] +=1;
			}
			else//输入为0
			{
				rdata[i] +=0;
			}
		}
	}
	
	if(rdata[0]+rdata[1]+rdata[2]+rdata[3] == rdata[4])
	{
		*Hum  = (float)(rdata[0]+rdata[1]/10.0);//湿度值读取
		
		//温度值读取
		if(rdata[3] & (0x01<<8))   //正温度/负温度
		{
			rdata[3] &=~ (0x80);
			*Temp = -(float)(rdata[2]+rdata[3]/10.0);
		}
		else
			*Temp = (float)(rdata[2]+rdata[3]/10.0);
	}
}

DHT11读取数据最好间隔2s读取一次

**

USART串口显示乱码问题

**

大部分都是系统时钟的问题
举个例子,我的开发板是stm32f103,但是我的晶振是12000000的,系统默认的是8000000

在这里插入图片描述
我这个已经改成12000000了

你以为已近改好了嘛!!!还没有哈
system_stm32f10x.c 中
注意到/* PLL configuration: PLLCLK = HSE * 9 = 72 MHz /这一句没
HSE上面已近改成了12000000,但是这里倍频仍然是9.
12x6=72
在这里插入图片描述
RCC_CFGR_PLLMULL6注意这个地方
这个地方是我已近改过的原本是这个RCC_CFGR_PLLMULL9(9倍频)
我们跳过去看看
在这里插入图片描述
注意后面的注释 PLL INPUT CLOCK
N
你晶振是12000000,系统时钟是72000000,所以倍频这里也要改为配套的哟!
这里我改后就是如第一张图所示RCC_CFGR_PLLMULL6

  • 1
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
好的,下面是stm32f103通过usart2采集dht11温湿度数据并发送到串口助手的完整代码示例: ``` #include "stm32f10x.h" #include <stdio.h> // 定义DHT11数据引脚 #define DHT11_DATA_PIN GPIO_Pin_0 #define DHT11_DATA_PORT GPIOA // 定义USART2发送函数 void USART2_SendData(uint8_t data) { while (USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET); // 等待发送缓冲区为空 USART_SendData(USART2, data); // 发送数据 } // 初始化USART2 void USART2_Init(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO | RCC_APB2Periph_USART1, ENABLE); // 使能USART2时钟和GPIOA时钟 // 配置PA2为USART2的Tx引脚 GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); // 配置PA3为USART2的Rx引脚 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, &GPIO_InitStructure); // USART2初始化设置 USART_InitTypeDef USART_InitStructure; USART_InitStructure.USART_BaudRate = 9600; // 波特率设置为9600 USART_InitStructure.USART_WordLength = USART_WordLength_8b; // 字长为8位数据格式 USART_InitStructure.USART_StopBits = USART_StopBits_1; // 1个停止位 USART_InitStructure.USART_Parity = USART_Parity_No; // 无奇偶校验位 USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; // 无硬件数据流控制 USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; // 支持收发模式 USART_Init(USART2, &USART_InitStructure); // 初始化USART2 USART_Cmd(USART2, ENABLE); // 使能USART2 } // 初始化DHT11 void DHT11_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // 使能GPIOA时钟 // 配置DHT11数据引脚为GPIO输出模式 GPIO_InitStructure.GPIO_Pin = DHT11_DATA_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(DHT11_DATA_PORT, &GPIO_InitStructure); GPIO_SetBits(DHT11_DATA_PORT, DHT11_DATA_PIN); // 将DHT11数据引脚输出高电平 } // 从DHT11读取数据 void DHT11_ReadData(uint8_t *temp, uint8_t *humi) { uint8_t buffer[5] = {0}; uint8_t i = 0, j = 0; GPIO_ResetBits(DHT11_DATA_PORT, DHT11_DATA_PIN); // 发送起始信号 delay_ms(18); GPIO_SetBits(DHT11_DATA_PORT, DHT11_DATA_PIN); delay_us(30); GPIO_ResetBits(DHT11_DATA_PORT, DHT11_DATA_PIN); // 接收响应信号 delay_us(40); GPIO_SetBits(DHT11_DATA_PORT, DHT11_DATA_PIN); delay_us(10); GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; // 切换DHT11数据引脚为输入模式 GPIO_Init(DHT11_DATA_PORT, &GPIO_InitStructure); while (GPIO_ReadInputDataBit(DHT11_DATA_PORT, DHT11_DATA_PIN) == SET); // 等待DHT11拉低数据引脚 while (GPIO_ReadInputDataBit(DHT11_DATA_PORT, DHT11_DATA_PIN) == RESET); // 跳过DHT11的低电平响应信号 while (GPIO_ReadInputDataBit(DHT11_DATA_PORT, DHT11_DATA_PIN) == SET); // 接收数据 for (j = 0; j < 5; j++) { for (i = 0; i < 8; i++) { while (GPIO_ReadInputDataBit(DHT11_DATA_PORT, DHT11_DATA_PIN) == RESET); // 跳过每个数据位的低电平 delay_us(40); // 等待数据位的高电平持续时间 if (GPIO_ReadInputDataBit(DHT11_DATA_PORT, DHT11_DATA_PIN) == SET) // 判断高电平持续时间,如果大于等于30us,则该数据位为1,否则为0 { buffer[j] |= (1 << (7 - i)); // 将读取到的数据保存到缓冲区中 } while (GPIO_ReadInputDataBit(DHT11_DATA_PORT, DHT11_DATA_PIN) == SET); // 等待数据位的高电平结束 } } *humi = buffer[0]; // 湿度值 *temp = buffer[2]; // 温度值 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 切换DHT11数据引脚为输出模式 GPIO_Init(DHT11_DATA_PORT, &GPIO_InitStructure); GPIO_SetBits(DHT11_DATA_PORT, DHT11_DATA_PIN); // 将DHT11数据引脚输出高电平 } int main(void) { USART2_Init(); // 初始化USART2 DHT11_Init(); // 初始化DHT11 uint8_t temp, humi; char buffer[50]; while (1) { DHT11_ReadData(&temp, &humi); // 从DHT11读取温湿度数据 sprintf(buffer, "Temperature: %d℃, Humidity: %d%%\r\n", temp, humi); // 将温湿度数据格式化成字符串 for (uint8_t i = 0; i < strlen(buffer); i++) { USART2_SendData(buffer[i]); // 发送温湿度数据到串口助手 } delay_ms(1000); // 延时1秒 } } ``` 使用以上代码,您就可以在stm32f103采集dht11温湿度数据并通过usart2发送到串口助手了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值