项目1:STM32+DHT11+FreeRTOS+emwin+LCD

2024-05-08 21:28

本文主要是介绍项目1:STM32+DHT11+FreeRTOS+emwin+LCD,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

【屏幕显示DHT11数据】

     面向对象的思想编写硬件驱动程序,DHT11采集环境中的温湿度数据。使用FreeRTOS提供的任务间通信、同步、互斥,将DHT11的数据传递给显示任务。显示任务中,使用emWin中间件,制作屏幕的各种界面,并将DHT11的数据显示到屏幕上。

项目开发流程:

第一个项目内容:屏幕显示DHT11数据

       面向对象的思想编写硬件驱动程序,DHT11采集环境中的温湿度数据。使用FreeRTOS提供的任务间通信、同步、互斥,将DHT11的数据传递给显示任务。显示任务中,使用emWin中间件,制作屏幕的各种界面,并将DHT11的数据显示到屏幕上。

项目框架:

TFT彩屏

TFT-LCD 即薄膜晶体管液晶显示器。其英文全称为:Thin Film Transistor-Liquid Crystal Display。TFT-LCD与无源 TN-LCD、STN-LCD 的简单矩阵不同,它在液晶显示屏的每一个象素上都设置有一个薄膜晶体管(TFT),可有效地克服非选通时的串扰,使显示液晶屏的静态特性与扫描线数无关。     

TFT-LCD具有:亮度好、对比度高、层次感强、颜色鲜艳等特点。应用于电视、手机、电脑、平板等各种电子产品。

分辨率:240*320 驱动IC:ILI9341 自带触摸屏(电阻触摸屏) 16位80并口驱动 16位真彩显示(65536色)

TFT彩屏引脚定义

TFT写数据

TFT读数据

TFT控制框图

DHT11模块简介

DHT11数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器。它应用专用的数字模块采集技术和温湿度传感技术,确保产品具有极高的可靠性与卓越的长期稳定性。

 传感器包括一个电阻式感湿元件和一个NTC测温元件,并与一个高性能8位单片机相连接。

DHT11电路图

DHT11参数

测量分辨率分别为 8bit(温度)、8bit(湿度)。

DHT11传输数据:串行接口(单线双向)

DHT11采用单总线协议与stm32通信。DHT11只有在接收到开始信号后才会触发温湿度采集。数据采集完毕且无开始信号后,DHT11自动切换到低速模式(复位信号触发DHT11从低速到高速模式)

(1)一次完整的数据传输为40bit,高位先出。

(2)数据格式:
8bit湿度整数数据 + 8bit湿度小数数据 + 8bi温度整数数据 + 8bit温度小数数据 + 8bit校验和

(3)数据传送正确时,校验和数据等于
“8bit湿度整数数据+8bit湿度小数数据 +8bi温度整数数据+8bit温度小数数据”所得结果的末8位

注:DHT11传输时,时序非常严格,不允许各种意外情况打断。

DHT11时序 (通信过程)

如下图所示,用户MCU发送一次开始信号后,DHT11从低功耗模式转换到高速模式,等待主机开始信号结束后,DHT11发送响应信号,送出40bit的数据,并触发一次信号采集,用户可选择读取部分数据。

从模式下,DHT11接收到开始信号触发一次温湿度采集,如果没有接收到主机发送开始信号,DHT11不会主动进行温湿度采集。采集数据后转换到低速模式。

如下图所示,总线空闲状态为高电平,主机把总线拉低等待DHT11响应,主机把总线拉低必须大于18毫秒,保证DHT11能检测到起始信号。DHT11接收到主机的开始信号后,等待主机开始信号结束,然后发送80us低电平响应信号。主机发送开始信号结束后,延时等待20-40us后,读取DHT11的响应信号,主机发送开始信号后,可以切换到输入模式,或者输出高电平均可,总线由上拉电阻拉高。

如上图所示,总线为低电平,说明DHT11发送响应信号,DHT11发送响应信号后,再把总线拉高80us,准备发送数据。

DHT11数据位格式 

如下图所示每一bit数据都以50us低电平时隙开始,高电平的长短定了数据位是0还是1。如果读取响应信号为高电平,则DHT11没有响应,请检查线路是否连接正常。当最后一bit数据传送完毕后,DHT11拉低总线50us,随后总线由上拉电阻拉高进入空闲状态。
     数字0信号表示方法如下图所示:                             数字1信号表示方法如下图所示:

数字0信号与数字1信号的不同之处在于高电平的时间不同,利用这点,我么们可以通过设置电平时间阈值来判断信号的种类。

DHT11驱动程序

DHT11.c

 配置输入输出GPIO:

复位DHT11

复位DHT11就是发送DHT11起始信号,告诉传感器通讯开始。

 

检查DHT11是否正常

检查DHT11是否正常,正常的话会在单片机发送起始信号完成后,传感器返回80us低电平,然后发送80us高电平。即证明DHT11工作正常,该函数工作正常返回0,否则返回1,该函数中利用了while循环检测在一定时间内的电平变化,此类用法在后面也会经常用到。

读取一位数据(返回值0/1)

该函数采用两个while循环是等待每个周期的电平变化,先等待低电平到来,后等待高电平到来,延时40us后判断引脚电平,来判断该位数据为1或0。之所以是40微秒是因为传感器数字0的信号持续时间为26-28us,数字1的信号持续时间为70us,选择一个中值来区分两种信号,当然也可以选择其他值,但最好在40us附近,在while循环中选择循环100次也就是100us,是因为防止当单片机由于某些原因迟迟收不到传感器电平信号,造成死机。

读取一个字节(返回值:读到的数据)

循环读入一个字节的数据,并将每一步新加入的数据放置在最低位。

读取DHT11数据(读取成功返回0,失败返回1)

读取数据将数据存入数组,这里仅保留了温度数据的整数位,注意数据较验方法,校验和数据等于“8bit湿度整数数据+8bit湿度小数数据 +8bi温度整数数据+8bit温度小数数据”所得结果的末8位

完整版.c文件
#include "dht11.h"
#include "delay.h"#define    DHT11_DelayMs(t)                      Delay_Ms(t)
#define    DHT11_DelayUs(t)                      Delay_Us(t)#define    DHT11_PIN_HIGH                        1
#define    DHT11_PIN_LOW                         0 #if  defined  (STM32F40_41xxx)#include "stm32f4xx.h"
//配置输入输出GPIO://温湿度模块输入函数
//浮空输入+设置IO口速度+选择端口
#define    __DHT11_CONFIG_IO_INPUT(DHT11)           {  GPIO_InitTypeDef GPIO_InitStructure; \ GPIO_InitStructure.GPIO_Mode     = GPIO_Mode_IN; \GPIO_InitStructure.GPIO_PuPd     = GPIO_PuPd_UP; \GPIO_InitStructure.GPIO_Speed    = GPIO_Speed_50MHz; \GPIO_InitStructure.GPIO_Pin      = DHT11->pin; \GPIO_Init(DHT11->port, &GPIO_InitStructure); \}
//温湿度模块输入函数
//推挽输出+设置IO口速度+选择端口
#define    __DHT11_CONFIG_IO_OUTPUT(DHT11)          {  GPIO_InitTypeDef GPIO_InitStructure; \GPIO_InitStructure.GPIO_Mode     = GPIO_Mode_OUT; \GPIO_InitStructure.GPIO_OType    = GPIO_OType_PP; \  GPIO_InitStructure.GPIO_PuPd     = GPIO_PuPd_UP; \GPIO_InitStructure.GPIO_Speed    = GPIO_Speed_50MHz; \GPIO_InitStructure.GPIO_Pin      = DHT11->pin; \GPIO_Init(DHT11->port, &GPIO_InitStructure); \}#define    __DHT11_IO_SET(DHT11, value)             {  if (value == DHT11_PIN_HIGH) \GPIO_SetBits(DHT11->port, DHT11->pin); \else \GPIO_ResetBits(DHT11->port, DHT11->pin); \}#define    DHT11_IO_H(DHT11)                        {__DHT11_IO_SET(DHT11, DHT11_PIN_HIGH)}
#define    DHT11_IO_L(DHT11)                        {__DHT11_IO_SET(DHT11, DHT11_PIN_LOW)}
#define    DHT11_IO_IN(DHT11)                       GPIO_ReadInputDataBit(DHT11->port, DHT11->pin)#endif/******************************************************************************* @brief      复位DHT11** @param[in]  dht11  :  dht11结构体指针** @return     0, 表示正常, 其他值表示失败*******************************************************************************/
//根据DHT11时序图
//复位DHT11:发送DHT11起始信号,告诉传感器通讯开始
static int DHT11_Rst(DHT11_t *dht11)     //DHT端口复位,发出起始信号(IO发送)
{__DHT11_CONFIG_IO_OUTPUT(dht11);    //设置引脚为输出模式DHT11_IO_L(dht11);                  //拉低DQDHT11_DelayMs(20);                  //拉低至少18ms  拉低20msDHT11_IO_H(dht11);                  //DQ=1 DHT11_DelayUs(30);                  //主机拉高20~40us__DHT11_CONFIG_IO_INPUT(dht11);     //设置引脚为输入模式//随后主机开始读取return 0;
}//复位DHT11可以理解为开始/******************************************************************************* @brief      等待DHT11的回应** @param[in]  dht11  :  dht11结构体指针** @return     0, 存在, 返回1:未检测到DHT11的存在*******************************************************************************/
//检查DHT11是否正常:检查DHT11是否正常,正常的话会在单片机发送起始信号完成后,传感器返回80us低电平,然后发送80us高电平。
static int DHT11_Check(DHT11_t *dht11)  //读取引脚的状态 retry临界值
{int retry = 0; while (DHT11_IO_IN(dht11) && (retry < 100)) {   //DHT11会拉低40-80usretry++;DHT11_DelayUs(1);};if (retry >= 100) {       //超过100ms说明统计没有相应return -2;} else {retry = 0;}while (!DHT11_IO_IN(dht11) && (retry < 100)) {  //DHT11拉低后会再次拉高40-80usretry++;DHT11_DelayUs(1);};if (retry >= 100) {return -3;}return 0;
}/******************************************************************************
以上没有问题就可以传输数据了* @brief      从DHT11读取一个位** @param[in]  dht11  :  dht11结构体指针** @return     0, 1 读取一位数据(返回值0/1)*该函数采用两个while循环是等待每个周期的电平变化,先等待低电平到来,
*等待高电平到来,延时40us后判断引脚电平,来判断该位数据为1或0。******************************************************************************/
static uint8_t DHT11_ReadBit(DHT11_t *dht11)
{int retry = 0;while (DHT11_IO_IN(dht11) && (retry < 100)) {   //等待变为低电平retry++;DHT11_DelayUs(1);}retry = 0;while (!DHT11_IO_IN(dht11) && (retry < 100)) {  //等待变高电平retry++;DHT11_DelayUs(1);}DHT11_DelayUs(40);//等待40usif (DHT11_IO_IN(dht11)) {return 1;} else {return 0;}
}/******************************************************************************* @brief      从DHT11读取一个字节** @param[in]  dht11  :  dht11结构体指针** @return     读到的数据*读取一个字节(返回值:读到的数据)
循环读入一个字节的数据,并将每一步新加入的数据放置在最低位。******************************************************************************/
static uint8_t DHT11_ReadByte(DHT11_t *dht11)
{uint8_t i, dat;dat = 0;for (i = 0; i < 8; i++) {dat <<= 1;dat |= DHT11_ReadBit(dht11);}return dat;
}/******************************************************************************* @brief      从DHT11读取一次数据    把协议全部放进去*                   temp:温度值(范围:0~50°)*                   humi:湿度值(范围:20%~90%)** @param[in]  dht11  :  dht11结构体指针** @return     0, 表示正常, 其他值表示失败*读取DHT11数据(读取成功返回0,失败返回1)
读取数据将数据存入数组,这里仅保留了温度数据的整数位,注意数据较验方法,校验和数据
等于“8bit湿度整数数据+8bit湿度小数数据 +8bi温度整数数据+8bit温度小数数据”所得结果的末8位。******************************************************************************/
int DHT11_ReadData(DHT11_t *dht11)
{if (!dht11 || !dht11->init) return -1;  //初始化引脚之后uint8_t buf[5];uint8_t i;DHT11_Rst(dht11);       //复位传感器if (DHT11_Check(dht11) == 0) {for (i = 0; i < 5; i++) {   //读取40位数据   40位 五个字节 连续读五次buf[i] = DHT11_ReadByte(dht11);}if ((buf[0] + buf[1] + buf[2] + buf[3]) == buf[4]) {     //校验  相等说明传输数据么有问题dht11->humidity = buf[0];dht11->temperature = buf[2];             //放入温湿度}} else {return -2;}return 0;
}/******************************************************************************* @brief      初始化DHT11的IO口 DQ 同时检测DHT11的存在.*DHT11初始化
在上电后,对IO端口初始化,和检查DHT11状态。* @param[in]  dht11  :  dht11结构体指针** @return     0, 表示正常, 其他值表示失败*******************************************************************************/
int DHT11_Init(DHT11_t *dht11, DHT11_GPIO_Port_t port, uint32_t pin)    //对外提供两个接口 触发温湿度传感器  读取数据
{if(!dht11) return -1;//配置引脚,默认输出
#if defined (STM32F40_41xxx)assert_param(IS_GPIO_ALL_PERIPH(port));if (port  == GPIOA)        { RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); }else if (port  == GPIOB)   { RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); }else if (port  == GPIOC)   { RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE); }else if (port  == GPIOD)   { RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE); }else if (port  == GPIOE)   { RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE); }else if (port  == GPIOF)   { RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE); }else if (port  == GPIOG)   { RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE); }else return -1;__DHT11_CONFIG_IO_OUTPUT(dht11);#endifdht11->port = port;dht11->pin = pin;dht11->temperature = 0.0;dht11->humidity = 0.0;dht11->init = true;DHT11_IO_H(dht11);DHT11_Rst(dht11);return DHT11_Check(dht11);
}

DHT11.h

#ifndef __DHT11_H
#define __DHT11_H #include <stdint.h>
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>#if defined (STM32F40_41xxx)#include "stm32f4xx.h"typedef    GPIO_TypeDef*  DHT11_GPIO_Port_t;#else#error dht11.h: No processor defined!#endiftypedef struct dht11_t
{DHT11_GPIO_Port_t     port;             //所使用的端口uint32_t              pin;              //所使用的引脚double                temperature;      //温度值double                humidity;         //湿度bool                  init;             //初始化标志
}DHT11_t;int   DHT11_Init(DHT11_t* dht11, DHT11_GPIO_Port_t port, uint32_t pin);         //初始化DHT11  使用哪个引脚
int   DHT11_ReadData(DHT11_t* dht11);                                           //获取DHT11的数据#endif

main.c

#include "main.h"
DHT11_t gDht11;  //定义一个温湿度结构体
char show_buffer[100];
int main(void)
{Debug_Init(115200);Delay_Init();printf("DHT11 start\r\n");LCD_Init();          //初始化屏幕LCD_Clear(RED);      //屏幕显示红色Delay_Ms(1000);LCD_Clear(~RED);Delay_Ms(1000);/* 初始化DHT11 */int ret = DHT11_Init(&gDht11, GPIOA, GPIO_Pin_6);   //DHT11接到PA6引脚上去printf("ret: %d\r\n", ret);/* 每秒读取一次温湿度传感器,并通过串口发送 */while (1) {DHT11_ReadData(&gDht11);                               //读取温湿度传感器的数值memset(show_buffer, 0, sizeof(show_buffer));sprintf(show_buffer, "T: %0.2f   H: %0.2f\r\n", gDht11.temperature, gDht11.humidity);printf("%s", show_buffer);                             //显示LCD_ShowString(0, 0, 240, 30, 24, show_buffer);        //通过LCD屏幕显示Delay_Ms(1000);}
}

总结

介绍DHT11温湿度传感器,及STM32版本驱动函数的编写

后续将加入freertos和emwin

这篇关于项目1:STM32+DHT11+FreeRTOS+emwin+LCD的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/971481

相关文章

Python 中 requests 与 aiohttp 在实际项目中的选择策略详解

《Python中requests与aiohttp在实际项目中的选择策略详解》本文主要介绍了Python爬虫开发中常用的两个库requests和aiohttp的使用方法及其区别,通过实际项目案... 目录一、requests 库二、aiohttp 库三、requests 和 aiohttp 的比较四、requ

SpringBoot项目启动后自动加载系统配置的多种实现方式

《SpringBoot项目启动后自动加载系统配置的多种实现方式》:本文主要介绍SpringBoot项目启动后自动加载系统配置的多种实现方式,并通过代码示例讲解的非常详细,对大家的学习或工作有一定的... 目录1. 使用 CommandLineRunner实现方式:2. 使用 ApplicationRunne

使用IntelliJ IDEA创建简单的Java Web项目完整步骤

《使用IntelliJIDEA创建简单的JavaWeb项目完整步骤》:本文主要介绍如何使用IntelliJIDEA创建一个简单的JavaWeb项目,实现登录、注册和查看用户列表功能,使用Se... 目录前置准备项目功能实现步骤1. 创建项目2. 配置 Tomcat3. 项目文件结构4. 创建数据库和表5.

Python项目打包部署到服务器的实现

《Python项目打包部署到服务器的实现》本文主要介绍了PyCharm和Ubuntu服务器部署Python项目,包括打包、上传、安装和设置自启动服务的步骤,具有一定的参考价值,感兴趣的可以了解一下... 目录一、准备工作二、项目打包三、部署到服务器四、设置服务自启动一、准备工作开发环境:本文以PyChar

多模块的springboot项目发布指定模块的脚本方式

《多模块的springboot项目发布指定模块的脚本方式》该文章主要介绍了如何在多模块的SpringBoot项目中发布指定模块的脚本,作者原先的脚本会清理并编译所有模块,导致发布时间过长,通过简化脚本... 目录多模块的springboot项目发布指定模块的脚本1、不计成本地全部发布2、指定模块发布总结多模

SpringBoot项目删除Bean或者不加载Bean的问题解决

《SpringBoot项目删除Bean或者不加载Bean的问题解决》文章介绍了在SpringBoot项目中如何使用@ComponentScan注解和自定义过滤器实现不加载某些Bean的方法,本文通过实... 使用@ComponentScan注解中的@ComponentScan.Filter标记不加载。@C

javafx 如何将项目打包为 Windows 的可执行文件exe

《javafx如何将项目打包为Windows的可执行文件exe》文章介绍了三种将JavaFX项目打包为.exe文件的方法:方法1使用jpackage(适用于JDK14及以上版本),方法2使用La... 目录方法 1:使用 jpackage(适用于 JDK 14 及更高版本)方法 2:使用 Launch4j(

Docker集成CI/CD的项目实践

《Docker集成CI/CD的项目实践》本文主要介绍了Docker集成CI/CD的项目实践,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学... 目录一、引言1.1 什么是 CI/CD?1.2 docker 在 CI/CD 中的作用二、Docke

SpringBoot项目引入token设置方式

《SpringBoot项目引入token设置方式》本文详细介绍了JWT(JSONWebToken)的基本概念、结构、应用场景以及工作原理,通过动手实践,展示了如何在SpringBoot项目中实现JWT... 目录一. 先了解熟悉JWT(jsON Web Token)1. JSON Web Token是什么鬼

手把手教你idea中创建一个javaweb(webapp)项目详细图文教程

《手把手教你idea中创建一个javaweb(webapp)项目详细图文教程》:本文主要介绍如何使用IntelliJIDEA创建一个Maven项目,并配置Tomcat服务器进行运行,过程包括创建... 1.启动idea2.创建项目模板点击项目-新建项目-选择maven,显示如下页面输入项目名称,选择