STM32温湿度传感器读取温湿度数据并显示到PC端串口助手
程序员文章站
2022-07-14 08:06:30
...
STM32F407ZE使用温湿度传感器 (广州奥松) ,读取温湿度数据并显示到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编写延时
unsigned char Read_Byte(void)
此函数则通过对应图4、5编写延时