本帖最后由 みずじ 于 2024-1-25 17:48 编辑
航芯ACM32G103开发板评测 07 LVGL 温湿度环境数据显示
参考移植教程
https://bbs.eeworld.com.cn/thread-1270136-1-1.html
https://bbs.eeworld.com.cn/thread-1270761-1-1.html
软硬件平台
- 航芯ACM32G103开发板
- 1.28寸圆形彩色TFT显示屏高清IPS 模块240X240 SPI接口 GC9A01驱动芯片
- DHT11 温湿度传感器
- LVGL V8.3.1源码
DHT11 温湿度传感器
DHT11是一款有已校准数字信号输出的温湿度传感器。 精度湿度+-5%RH, 温度+-2℃,量程湿度20-90%RH, 温度0~50℃。
更多DHT11信息请参考:https://baike.sogou.com/v73984313.htm?fromTitle=DHT11
下图为DHT11的引脚说明图,DATA引脚为信号输入输出。
DS18B20引脚说明
DHT11单总线传感器驱动
DHT11 整体工作时序为:主机发送开始信号、DHT11 响应输出、主机接收 40bit 数据(湿度数据+温度数据+校验值),结束信号(可选)。具体过程如下:
- 总线空闲状态为高电平,主机拉低总线等待 DHT11 响应, 主机把总线拉低必须大于 18ms,保证 DHT11 能检测到起始信号;
- 主机发送开始信号结束后,拉高总线电平并延时等待 20-40us 后,读取 DHT11 的响应信号;
- DHT11 接收到主机的开始信号后,等待微处理器开始信号结束,发送 80us 低电平响应信号;
- DHT11 发送 80us 高电平准备发送数据;
- DHT11 发送 40bit 数据(湿度数据+温度数据+校验值)。
起始及响应信号
主机拉低总线至少 18ms,然后再拉高总线,延时 20~40us,此时起始信号(有时也叫复位信号)发送完毕。
DHT11 检测到复位信号后,触发一次采样,并拉低总线 80us 表示响应信号,告诉主机数据已经准备好了。DHT11 之后拉高总线 80us,然后开始传输数据。如果检测到响应信号为高电平,则 DHT11 初始化失败,请检查线路是否连接正常。
读时序
DHT11 开始传输数据。每 1bit 数据都以 50us 低电平开始,告诉主机开始传输一位数据了。DHT11 以高电平的长短定义数据位是 0 还是 1:当 50us 低电平过后拉高总线,高电平持续 26~28us 表示 0,高电平持续 70us 表示数据 1。
当最后 1bit 数据传送完毕后,DHT11 拉低总线 50us,表示数据传输完毕,随后总线由上拉电阻拉高进入空闲状态。
位数据0表示方式:
以 50us 低电平开始,高电平持续 26~28us 表示 0。
位数据1表示方式:
以 50us 低电平开始,高电平持续 70us 表示 1。
驱动代码
- 端口初始化
* 函数名:DHT11_GPIO_Config
* 描述:配置DHT11用到的I/O口
* 输入:无
* 输出:无
*/
static void DHT11_GPIO_Config ( void )
{
GPIO_InitTypeDefGPIO_InitStruct;
DHT11_GPIO_CLK_ENABLE();
GPIO_InitStruct.Pin = DHT11_Dout_GPIO_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Drive = GPIO_DRIVE_LEVEL3;
GPIO_InitStruct.Alternate = GPIO_FUNCTION_0;
HAL_GPIO_Init(DHT11_Dout_GPIO_PORT, &GPIO_InitStruct);
}
* <a href="https://bbs.eeworld.com.cn/home.php?mod=space&uid=159083" target="_blank">@brief</a>DHT11 初始化函数
* @param无
* @retval 无
*/
void DHT11_Init ( void )
{
DHT11_GPIO_Config ();
DHT11_Dout_1;
}
* 函数名:DHT11_Mode_IPU
* 描述:使DHT11-DATA引脚变为上拉输入模式
* 输入:无
* 输出:无
*/
static void DHT11_Mode_IPU(void)
{
GPIO_InitTypeDefGPIO_InitStruct;
DHT11_GPIO_CLK_ENABLE();
GPIO_InitStruct.Pin = DHT11_Dout_GPIO_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Drive = GPIO_DRIVE_LEVEL3;
GPIO_InitStruct.Alternate = GPIO_FUNCTION_0;
HAL_GPIO_Init(DHT11_Dout_GPIO_PORT, &GPIO_InitStruct);
}
* 函数名:DHT11_Mode_Out_PP
* 描述:使DHT11-DATA引脚变为推挽输出模式
* 输入:无
* 输出:无
*/
static void DHT11_Mode_Out_PP(void)
{
GPIO_InitTypeDefGPIO_InitStruct;
DHT11_GPIO_CLK_ENABLE();
GPIO_InitStruct.Pin = DHT11_Dout_GPIO_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Drive = GPIO_DRIVE_LEVEL3;
GPIO_InitStruct.Alternate = GPIO_FUNCTION_0;
HAL_GPIO_Init(DHT11_Dout_GPIO_PORT, &GPIO_InitStruct);
}
- 从DHT11读取一个字节
static uint8_t DHT11_ReadByte ( void )
{
uint8_t i, temp=0;
for(i=0;i<8;i++)
{
while(DHT11_Dout_IN()==Bit_RESET);
*通过检测 x us后的电平即可区别这两个状 ,x 即下面的延时
*/
HAL_DelayUs(40);
if(DHT11_Dout_IN()==Bit_SET)
{
while(DHT11_Dout_IN()==Bit_SET);
temp|=(uint8_t)(0x01<<(7-i));
}
else
{
temp&=(uint8_t)~(0x01<<(7-i));
}
}
return temp;
}
- 温湿度数据获取函数
* 一次完整的数据传输为40bit,高位先出
* 8bit 湿度整数 + 8bit 湿度小数 + 8bit 温度整数 + 8bit 温度小数 + 8bit 校验和
*/
uint8_t DHT11_Read_TempAndHumidity(DHT11_Data_TypeDef *DHT11_Data)
{
DHT11_Mode_Out_PP();
DHT11_Dout_0;
HAL_DelayMs(18);
DHT11_Dout_1;
HAL_DelayUs(30);
DHT11_Mode_IPU();
if(DHT11_Dout_IN()==Bit_RESET)
{
while(DHT11_Dout_IN()==Bit_RESET);
while(DHT11_Dout_IN()==Bit_SET);
DHT11_Data->humi_int= DHT11_ReadByte();
DHT11_Data->humi_deci= DHT11_ReadByte();
DHT11_Data->temp_int= DHT11_ReadByte();
DHT11_Data->temp_deci= DHT11_ReadByte();
DHT11_Data->check_sum= DHT11_ReadByte();
DHT11_Mode_Out_PP();
DHT11_Dout_1;
if(DHT11_Data->check_sum == DHT11_Data->humi_int + DHT11_Data->humi_deci + DHT11_Data->temp_int+ DHT11_Data->temp_deci)
return SUCCESS;
else
return ERROR;
}
else
return ERROR;
}
- bsp_dht11.h
#ifndef __BSP_DHT11_H
#define __BSP_DHT11_H
#include "main.h"
typedef struct
{
uint8_thumi_int;
uint8_thumi_deci;
uint8_ttemp_int;
uint8_ttemp_deci;
uint8_tcheck_sum;
}DHT11_Data_TypeDef;
#define Bit_RESET 0
#define Bit_SET 1
#define DHT11_Dout_GPIO_PORT GPIOC
#define DHT11_Dout_GPIO_PIN GPIO_PIN_5
#define DHT11_GPIO_CLK_ENABLE() __HAL_RCC_GPIOC_CLK_ENABLE()
#define DHT11_Dout_0 HAL_GPIO_WritePin(DHT11_Dout_GPIO_PORT,DHT11_Dout_GPIO_PIN,GPIO_PIN_RESET)
#define DHT11_Dout_1 HAL_GPIO_WritePin(DHT11_Dout_GPIO_PORT,DHT11_Dout_GPIO_PIN,GPIO_PIN_SET)
#define DHT11_Dout_IN() HAL_GPIO_ReadPin( DHT11_Dout_GPIO_PORT, DHT11_Dout_GPIO_PIN )
static void DHT11_GPIO_Config ( void );
void DHT11_Init ( void );
uint8_t DHT11_Read_TempAndHumidity ( DHT11_Data_TypeDef * DHT11_Data );
#endif
案例测试
- 主函数
*<a href="https://bbs.eeworld.com.cn/home.php?mod=space&uid=1307177" target="_blank">@File</a>: main.c
*@brief : main program
******************************************************************************/
#include "main.h"
#include "lvgl_timer.h"
LoopFunction loopFunction[MAX_INIT_FUNCTIONS];
int loopFunctionCount = 0;
void callInitFunctions(void){
uint8_t i ;
for(i = 0 ; i<loopFunctionCount;i++){
loopFunction<i>();
}
}
*@brief : main program
*@param : none
*@return: none
******************************************************************************/
#include "lvgl.h"
#include "lv_port_disp.h"
#include "lv_port_indev.h"
#include "lv_demo_widgets.h"
#include "lv_examples.h"
lv_obj_t *labe_temp;
lv_obj_t *labe_humi;
static void lv_ex_label_1(void)
{
lv_obj_t * scr = lv_obj_create(NULL);
lv_scr_load(scr);
lv_obj_set_style_bg_color(scr,lv_palette_main(LV_PALETTE_ORANGE),0);
lv_obj_align(scr,LV_ALIGN_CENTER,0,0);
lv_obj_t * btn = lv_btn_create(scr);
lv_obj_align(btn, NULL, LV_ALIGN_CENTER, 40);
lv_obj_t * label = lv_label_create(btn);
lv_label_set_text(label, "Hello EEWORLD !");
lv_obj_t * btn1 = lv_btn_create(scr);
lv_obj_align(btn1, NULL, LV_ALIGN_CENTER, 90);
lv_obj_t * label1 = lv_label_create(btn1);
lv_label_set_text(label1, "By End 2024.01.24!");
lv_obj_t * btn2 = lv_btn_create(scr);
lv_obj_align(btn2, NULL, LV_ALIGN_CENTER, 140);
lv_obj_t * label2 = lv_label_create(btn2);
lv_label_set_text(label2, "ACM32G103-Board Testing");
}
lv_obj_t * chart;
lv_chart_series_t * ser1;
void lv_example_style_1(void)
{
lv_obj_t * scr = lv_obj_create(NULL);
lv_scr_load(scr);
lv_obj_set_style_bg_color(scr,lv_palette_main(LV_PALETTE_ORANGE),0);
lv_obj_align(scr,LV_ALIGN_CENTER,0,0);
lv_obj_t * label1 = lv_label_create(lv_scr_act());
lv_obj_align(label1,LV_ALIGN_CENTER,0,-80);
lv_label_set_text(label1, "Temperature");
labe_temp = lv_label_create(lv_scr_act());
lv_obj_align(labe_temp,LV_ALIGN_CENTER,0,-60);
lv_label_set_text_fmt(labe_temp, "%d°C", 0) ;
lv_obj_t * label2 = lv_label_create(lv_scr_act());
lv_obj_align(label2,LV_ALIGN_CENTER,0,60);
lv_label_set_text(label2, "Humidity");
labe_humi = lv_label_create(lv_scr_act());
lv_obj_align(labe_humi,LV_ALIGN_CENTER,0,80);
lv_label_set_text_fmt(labe_humi, "%d%%", 0) ;
}
int main(void)
{
int8_t Temperature;
int8_t Humidity;
DHT11_Data_TypeDef DHT11_Data;
HAL_Init();
SystemClock_Config();
BSP_UART_Init();
TIM6_Init();
DHT11_Init ();
RTC_Init();
lv_init();
lv_port_disp_init();
lv_example_style_1();
while(1)
{
lv_task_handler();
HAL_Delay(5);
if( DHT11_Read_TempAndHumidity ( & DHT11_Data ) == SUCCESS)
{
DHT11_Data.humi_int,DHT11_Data.humi_deci,DHT11_Data.temp_int,DHT11_Data.temp_deci);
Temperature = DHT11_Data.temp_int;
Humidity = DHT11_Data.humi_int;
}
else
{
printf("Read DHT11 ERROR!\r\n");
}
lv_label_set_text_fmt(labe_temp, "%d°C", (int)Temperature) ;
lv_label_set_text_fmt(labe_humi, "%d%%", (int)Humidity) ;
}
}
- 测试效果
- 总结
主函数主要是lvgl简单界面代码编写,dht11温湿度传感器数据获取,后面可以定时器定时去获取,不需要一直检测,或者在rtos中创建任务。原本打算做一个动态曲线的,但是屏幕刷新太慢了,毕竟用的是软件SPI,虽然硬件好一点,但是,我看不如测试发现其实帧率差不了多少,可能后面有时间研究研究硬件SPI+DMA的方式,加快刷屏。对于lvgl的使用可能需要加强一点。