欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

STM32温湿度传感器读取温湿度数据并显示到PC端串口助手

程序员文章站 2022-07-14 08:06:30
...

STM32F407ZE使用温湿度传感器 (广州奥松) ,读取温湿度数据并显示到PC端串口助手实例
输出结果:
STM32温湿度传感器读取温湿度数据并显示到PC端串口助手

具体代码及解析如下:

main.c部分:

#include <stm32f4xx.h> 
#include "dht11.h"
#include "ustart.h"
#include <string.h>

DHT11_Data_TypeDef DHT11_Data;

int main()
{
	Systick_Init();
	USART1_Init();
	DHT11_Init(GPIO_Mode_OUT);
	USART_SendString(USART1, "Hello world!\r\n");

	while(1)
	{
		//调用Read_DHT11读取温湿度,若成功则输出该信息*/
		if( Read_DHT11 ( & DHT11_Data ) == SUCCESS)
		{
			printf("\r\n 湿度:%d RH ,温度:%d.%d C\r\n",DHT11_Data.humi_int,		//湿度精度为整数
									DHT11_Data.temp_int,DHT11_Data.temp_deci);	//温度精度为小数
			delay_s(1);															//延时1us
		}	
	}
}

ustart.h部分

#ifndef USTART_H
#define USTART_H

#include <stm32f4xx.h>
#include <stm32f4xx_usart.h>
#include <stdio.h>
#include "sys.h"
#include "delay.h"

extern char USART1_ReceiveData[50];								//接收PC端发送过来的字符
extern int Receive_Flag;

void USART1_Init();
void USART_SendString(USART_TypeDef* USARTx, char *DataString);
#endif

ustart.c部分

#include "ustart.h"
#include <string.h>

int fputc(int ch, FILE *f) 
{
	/* 发送一个字节数据到串口 */
	USART_SendData(USART1, (uint8_t) ch); //程序开始时,会发送一次数据,ch是系统分配的(可能是0),串口会显示大概两个空格的内容
	/* 等待发送完毕 */
	while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
	return (ch);
}

void USART1_Init()
{
	GPIO_InitTypeDef 	GPIOInit_Struct;
	USART_InitTypeDef 	USARTInit_Struct;
	NVIC_InitTypeDef  	USARTNVIC_Struct;
	
	//1、使能时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
	
	//2、初始化对应的IO引脚复用为USART1功能
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);
	
	GPIOInit_Struct.GPIO_Pin 	= GPIO_Pin_9 | GPIO_Pin_10;
	GPIOInit_Struct.GPIO_Mode	= GPIO_Mode_AF;
	GPIOInit_Struct.GPIO_OType	= GPIO_OType_PP;
	GPIOInit_Struct.GPIO_Speed 	= GPIO_Fast_Speed;
	GPIOInit_Struct.GPIO_PuPd	= GPIO_PuPd_UP;
	GPIO_Init(GPIOA,&GPIOInit_Struct);
	
	//将PA9  PA10复用为USART1功能
	GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1);
	GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1);
	
	//3、USART1初始化
	USARTInit_Struct.USART_BaudRate 	= 115200; 								//波特率
	USARTInit_Struct.USART_Parity		= USART_Parity_No;						//无校验位
	USARTInit_Struct.USART_StopBits		= USART_StopBits_1;						//1位停止位
	USARTInit_Struct.USART_WordLength	= USART_WordLength_8b;					//8位数据位
	USARTInit_Struct.USART_Mode			= USART_Mode_Rx | USART_Mode_Tx;		//收发模式
	USARTInit_Struct.USART_HardwareFlowControl	= USART_HardwareFlowControl_None;//无硬件控制流
	USART_Init(USART1,&USARTInit_Struct);
	
	//开启串口终端
	USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);
	
	USARTNVIC_Struct.NVIC_IRQChannel = USART1_IRQn;//stm32f4xx.h
	USARTNVIC_Struct.NVIC_IRQChannelPreemptionPriority = 0;
	USARTNVIC_Struct.NVIC_IRQChannelSubPriority        = 0;
	USARTNVIC_Struct.NVIC_IRQChannelCmd	= ENABLE;
	NVIC_Init(&USARTNVIC_Struct);
	
	//4、开启串口
	USART_Cmd(USART1,ENABLE);
}

void USART_SendString(USART_TypeDef* USARTx, char *DataString)
{
	int i = 0;
	USART_ClearFlag(USARTx,USART_FLAG_TC);										//发送字符前清空标志位(否则缺失字符串的第一个字符)
	while(DataString[i] != '\0')												//字符串结束符
	{
		USART_SendData(USARTx,DataString[i]);									//每次发送字符串的一个字符
		while(USART_GetFlagStatus(USARTx,USART_FLAG_TC) == 0);					//等待数据发送成功
		USART_ClearFlag(USARTx,USART_FLAG_TC);									//发送字符后清空标志位
		i++;
	}
}

char USART_ReceiveString[50];													//接收PC端发送过来的字符
int Receive_Flag = 0;															//接收消息标志位
int Receive_sum = 0;															//数组下标
void USART1_IRQHandler(void)
{
	if(USART_GetITStatus(USART1,USART_IT_RXNE) == 1)							//USART_FLAG_RXNE判断数据,== 1则有数据
	{
		if(Receive_sum > 49)													//数组能存放50个字节的数据				
		{
			USART_ReceiveString[49] = '\0';										//数据字节超过50位时,将最后一位设置为\0	
			Receive_Flag = 1;													//接收标志位置1,停止接收数据
			Receive_sum = 0;													//数组下标置0
		}
		
		if(Receive_Flag == 0)													//接收标志位等于0,开始接收数据
		{
			USART_ReceiveString[Receive_sum] = USART_ReceiveData(USART1);		//通过USART1串口接收字符
			Receive_sum++;														//数组下标++
		}
		
		if(Receive_sum >= 2)													//数组下标大于2
		{
			if(USART_ReceiveString[Receive_sum-2] == '\r' && USART_ReceiveString[Receive_sum-1] == '\n' )
			{
				USART_ReceiveString[Receive_sum-1] = '\0';						
				USART_ReceiveString[Receive_sum-2] = '\0';
				Receive_Flag = 1;												//接收标志位置1,停止接收数据
				Receive_sum = 0;												//数组下标置0
				printf("%s\r\n",USART_ReceiveString);					

				if(strcmp(USART_ReceiveString,"hello") == 0)
				{
					PFout(9) = !PFout(9);
				}
				if(strcmp(USART_ReceiveString,"world") == 0)
				{
					PFout(10) = !PFout(10);
				}
				if(strcmp(USART_ReceiveString,"jiajia") == 0)
				{
					PEout(13) = !PEout(13);
				}
				if(strcmp(USART_ReceiveString,"haha") == 0)
				{
					PEout(14) = !PEout(14);
				}
			}		
		}
		USART_ClearITPendingBit(USART1,USART_IT_RXNE);							//接收后先清空标志位
	}
}

delay.h部分:

#ifndef _DELAY_H_
#define _DELAY_H_

//头文件
#include "stm32f4xx.h"

//宏定义

//函数声明
void Systick_Init(void);
void delay_us(u32 nus);
void delay_ms(u32 nms);
void delay_s(u32 ns);

#endif

delay.c部分:

#include "delay.h"

u8 	my_us = 0;
u16 my_ms = 0;

//初始化滴答定时器
void Systick_Init(void)
{
	//得到的Systick时钟 21MHZ
	SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); 
	my_us = 168/8;        //21
	my_ms = 21000;
}

//微秒延时,nms最大值:798.915
void delay_us(u32 nus)
{
	u32 temp = 0;
	//往自动重装载除值寄存器写入延时nus  SysTick->LOAD最大值0xFFFFFF
	SysTick->LOAD = nus*my_us;
	SysTick->VAL  = 0x00;
	SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; //开启计数
	do
	{
		//读控制寄存器
		temp = SysTick->CTRL;
	}while(!(temp & (1<<16)));
	SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; //关闭计数
	SysTick->VAL  = 0x00;
}

//毫秒延时,nus最大值,nus最大值798915
void delay_ms(u32 nms)
{
	u32 temp = 0;
	//往自动重装载除值寄存器写入延时nus  SysTick->LOAD最大值0xFFFFFF
	SysTick->LOAD = nms*my_ms;
	SysTick->VAL  = 0x00;
	SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk; //开启计数
	do
	{
		//读控制寄存器
		temp = SysTick->CTRL;
	}while(!(temp & (1<<16)));
	SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk; //关闭计数
	SysTick->VAL  = 0x00;

}

//秒延时
void delay_s(u32 ns)
{
	for(; ns>0; ns--)
	{
		delay_ms(500);
		delay_ms(500);
	}
}

dht11.h部分:

#ifndef _DHT11_H_
#define _DHT11_H_

//头文件
#include  "stm32f4xx.h"
#include "delay.h"
#include "ustart.h"


//宏定义
#define DHT11_HIGH  1
#define DHT11_LOW   0
#define DHT11_DATA_OUT(a)	if (a)
							   GPIO_SetBits(GPIOG,GPIO_Pin_9);
							else
							   GPIO_ResetBits(GPIOG,GPIO_Pin_9)

#define  DHT11_DATA_IN()	  GPIO_ReadInputDataBit(GPIOG,GPIO_Pin_9)

//外部变量声明
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;

//函数声明
void DHT11_Init(GPIOMode_TypeDef mode);
unsigned char Read_Byte(void);
unsigned char Read_DHT11(DHT11_Data_TypeDef *DHT11_Data);

#endif //__DHT11_H_

dht11.c部分:

#include "dht11.h"

//DHT11初始化,并将模式以参数形式传入
void DHT11_Init(GPIOMode_TypeDef mode)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE);	//使能 GPIOG 时钟

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 ;
	GPIO_InitStructure.GPIO_Mode = mode;					//自定义模式
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		//50MHz
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;		//浮空输入
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;			//推挽输出
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;			//上拉
	
	GPIO_Init(GPIOG, &GPIO_InitStructure);					//初始化
}

//读取DHT11的数据
unsigned char Read_Byte(void)
{
	int i, data=0;

	for(i=0;i<8;i++)    
	{
		while(DHT11_DATA_IN()==0);							//每bit以50us低电平标置开始,等待低电平结束
															//DHT11以26~28us的高电平表示“0”,以70us高电平表示“1”
		delay_us(30); 										//延时x us, 26~28 < x < 80  	  
		
		if(DHT11_DATA_IN()==1)								//x us后仍为高电平表示数据“1” 
		{
			while(DHT11_DATA_IN()==1);						//等待高电平结束,进入下一bit开始
			data|=(unsigned char)(0x01<<(7-i));  			//把第7-i位置1,MSB先行 
		}
		else												//30us后为低电平表示数据“0” 
		{			   
			data&=(unsigned char)~(0x01<<(7-i)); 			//把第7-i位置0,MSB先行
		}
	}
	return data;
}

unsigned char Read_DHT11(DHT11_Data_TypeDef *DHT11_Data)
{  
	int count;
	DHT11_Init(GPIO_Mode_OUT);								//输出模式
	
	DHT11_DATA_OUT(0);										//主机拉低电平
	delay_ms(18);											//延时18ms
	
	DHT11_DATA_OUT(1); 										//总线拉高
	delay_us(21);   										//延时20~40us	
	
	DHT11_Init(GPIO_Mode_IN);								//主机设为输入,判断从机响应信号

	count=0;												//超时计数初始化
	while(DHT11_DATA_IN()==0)     							//等待电平被拉低
	{
		count++;											//超时计数
		if(count>160) return -1;							//超时	
		delay_us(1);										//延时1us
	}
		
	count=0;												//超时计数初始化
	while(DHT11_DATA_IN()==1)								//等待电平被拉高
	{	
		count++;											//超时计数
		if(count>160) return -1;							//超时		
		delay_us(1); 										//延时1us
	}    

	count=0;												//超时计数初始化
	while(DHT11_DATA_IN()==0)								//等待电平被拉低,开始传送数据
	{
		count++;											//超时计数
		if(count>160) return -1;							//超时		
		delay_us(1); 										//延时1us
	}  
															//开始接收数据
	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_Init(GPIO_Mode_OUT);								//读取结束,引脚改为输出模式
	DHT11_DATA_OUT(1);										//主机拉高

															//检查读取的数据是否正确
	if(DHT11_Data->check_sum == DHT11_Data->humi_int + DHT11_Data->humi_deci + DHT11_Data->temp_int+ DHT11_Data->temp_deci)
		return 1;
	else 
		return 0;
}

使用温湿度传感器需要读懂下面的信号图

unsigned char Read_DHT11(DHT11_Data_TypeDef *DHT11_Data);
此函数对应图2编写延时
STM32温湿度传感器读取温湿度数据并显示到PC端串口助手

unsigned char Read_Byte(void)
此函数则通过对应图4、5编写延时
STM32温湿度传感器读取温湿度数据并显示到PC端串口助手
STM32温湿度传感器读取温湿度数据并显示到PC端串口助手