[STM32 HAL]STM32F103CxT6_BluePill DHT11获取温湿度值并且显示到ST7789TFT-LCD

这是一个使用STM32F103CxT6 HAL的项目,功能是使用DHT11获取当前温湿度然后显示到LCD屏幕上。 

项目使用到了以下外设: GPIO, TIM, SPI, DMA;

其中SPI和USART使用了DMA,所以刷屏速度很快。 

我近期在忙的项目分支之一,同时也作为一个“任务”。

在这我提供我使用F103CBT6写的项目地址,里面有我上传的代码但不是最新的,优化完之后便会上传。

WeACT_BulePillicon-default.png?t=N7T8https://github.com/chixiaoshu/WeAct_BluePill

目录

一、系统定义

引脚定义

定时器定义

SPI定义

二、源码部分

DHT11 模块

三、代码实现

导入头文件

定义变量

初始化LCD与DHT11模块

时间处理与LCD显示函数

四、结果展示

五、结尾


一、系统定义

引脚定义

定时器定义

SPI定义

我在这里说明一下,我的项目不是单一实现某个功能的,而是把我用到的引脚都定义好了。


二、源码部分

DHT11 模块

"dht11.c"

#include "dht11.h"
#include <stdint.h>

void Delay_us(uint8_t us)
{
    uint16_t differ = 0xffff - us - 5;
    __HAL_TIM_SET_COUNTER(&DHT11_TIMER, differ); // 设定TIM计数器起始值
    HAL_TIM_Base_Start(&DHT11_TIMER);            // 启动定时器
    while (differ < 0xffff - 5)
    {                                                 // 判断
        differ = __HAL_TIM_GET_COUNTER(&DHT11_TIMER); // 查询计数器的计数值
    }
    HAL_TIM_Base_Stop(&DHT11_TIMER);
}

void GPIO_Input(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;
    /*Configure GPIO pin : PB4 */
    GPIO_InitStruct.Pin = GPIO_PIN_4;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}

void GPIO_Output(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;
    /*Configure GPIO pin : PB4 */
    GPIO_InitStruct.Pin = GPIO_PIN_4;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}

void DHT11_Rst(void) // 主机开始信号
{
    GPIO_Output();
    DHT11_OUT_LOW;
    HAL_Delay(18);
    DHT11_OUT_HIGH;
    Delay_us(30);
}

uint8_t DHT11_Check(void)
{
    uint8_t retry = 0;
    GPIO_Input();
    while (DHT11_IN_Read && retry < 100) // 等待回应拉位低电平
    {
        retry++;
        Delay_us(1);
    }

    if (retry >= 100)
        return 1;
    else
        retry = 0; // 当变量值大于100 返回1 说明无响应  返回 0 则为正确响应

    while (!DHT11_IN_Read && retry < 100) // 等待变为高电平
    {
        retry++;
        Delay_us(1);
    }
    if (retry >= 100)
        return 1;
    return 0;
}

uint8_t DHT11_Init(void)
{
    DHT11_Rst();
    return DHT11_Check();
}

uint8_t DHT11_ReadBit(void) // 读取一个位
{
    uint8_t retry = 0;
    while (DHT11_IN_Read && retry < 100) // 等待变为低电平
    {
        retry++;
        Delay_us(1);
    }
    retry = 0;
    while (!DHT11_IN_Read && retry < 100) // 等待变为高电平
    {
        retry++;
        Delay_us(1);
    }
    Delay_us(40); // 40us 后如果为低电平 数据为0   高电平数据为1
    if (DHT11_IN_Read)
        return 1;
    else
        return 0;
}

uint8_t DHT11_ReadByte(void) // 读取一个字节  返回值位采集值
{
    uint8_t i, dat;
    dat = 0;
    for (i = 0; i < 8; i++)
    {
        dat <<= 1;              // 数据左移一位
        dat |= DHT11_ReadBit(); // 每读取到一个位 放到dat的最后一位
    }
    return dat;
}

uint8_t DHT11_ReadData(float *temp, float *hum)
{
    uint8_t buf[5];
    uint8_t i;
    DHT11_Rst();
    if (DHT11_Check() == 0)
    {
        for (i = 0; i < 5; i++)
        {
            buf[i] = DHT11_ReadByte();
        }
        if ((buf[0] + buf[1] + buf[2] + buf[3]) == buf[4])
        {
            // 湿度:buf[0]是整数部分,buf[1]是小数部分
            *hum = buf[0] + buf[1] / 10.0;
            // 温度:buf[2]是整数部分,buf[3]是小数部分
            *temp = buf[2] + buf[3] / 10.0;
        }
        else
        {
            return 1; // 校验和错误
        }
    }
    else
    {
        return 1; // 传感器检查失败
    }
    return 0; // 成功
}

"dht11.h" 

#ifndef __DHT11_H__
#define __DHT11_H__

#ifdef __cplusplus
extern "C" {
#endif

#include "main.h"

#define DHT11_TIMER         htim3
extern TIM_HandleTypeDef    DHT11_TIMER;  	// 引入变量

#define DHT11_OUT_HIGH  HAL_GPIO_WritePin(GPIOB,GPIO_PIN_4,GPIO_PIN_SET)
#define DHT11_OUT_LOW   HAL_GPIO_WritePin(GPIOB,GPIO_PIN_4,GPIO_PIN_RESET)
#define DHT11_IN_Read   HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_4)

//函数原型
//void Delay_us(uint8_t us);   //微秒级延时函数,启用了一个定时器。因为DHT11通讯过程涉及微秒延时
void GPIO_Input(void);	  //GPIO 状态转变的函数 CUBEMX默认的GPIO初始化我只开启了相关总线的使能
//把GPIO状态(输入 输出)封装成了两个函数
void GPIO_Output(void);
void DHT11_Rst(void);		//主机开始采集的信号
uint8_t DHT11_Check(void);  //检查DHT是否回应
uint8_t DHT11_Init(void);   //初始化函数
uint8_t DHT11_ReadBit(void);   //读取一位
uint8_t DHT11_ReadByte(void);  //读取一个字节
uint8_t DHT11_ReadData(float *temp, float *hum);   //读取数据(40个位) 

#ifdef __cplusplus
}
#endif

#endif /* __DHT11_H__ */

这个DHT11需要将定时器打开,因为使用到了微秒级延时; 

可以通过宏定义来修改为你用定义的定时器, TIM1,TIM2, TIM3;

然后这个ST7789屏幕的函数比较多我就不放了,接下来是用法;


三、代码实现

显示定义两个函数,一个是每秒获取一遍DHT11的数据,而另外一个是LCD显示函数;

其一, 时间处理函数用了系统滴答定时器以防止HAL_Delay阻塞;

其二, 这个延时1000ms可以去掉,我在这仅仅是调试使用;

其三, temperature和humidity是全局变量;

导入头文件

头文件只需要导入两个,"st7789.h"与"dht11.h" ;

看到我导入的头文件就知道我其实些了这几个相关的函数;

定义变量

然后在"stm32fxxx_it.c" 里写入上面这个一秒事件变量;

初始化LCD与DHT11模块

  /* USER CODE BEGIN 2 */
  ST7789_Init();
  ST7789_Fill_Color(WHITE);
  while (DHT11_Init())
  {
    sprintf((char *)temp_buffer, "DHT11 failed");
    OLED_ShowString(0, 1, temp_buffer);
    HAL_UART_Transmit(&huart1, temp_buffer, strlen((char *)temp_buffer), 0xFF);
    HAL_Delay(500);
  }
  sprintf((char *)temp_buffer, "DHT11 Sucess");
  HAL_UART_Transmit(&huart1, temp_buffer, strlen((char *)temp_buffer), 0xFF);

  /* USER CODE END 2 */

说明: DHT11的初始化其实有返回值的,这边用while其实有点问题。比如我不接这个模块,那么会怀疑单片机是否坏了(并没有)。同时也需要注意,DHT11要是初始化不了,可以在串口1中查看。检查是模块损坏还是线没接好;

时间处理与LCD显示函数

/* USER CODE BEGIN 4 */
void time_process_event(void)
{
  if (isTimerElapsed == 1)
  {
    LCD_process_event();
    if (DHT11_ReadData(&temperature, &humidity) == 0)
    {
      // 使用 sprintf 将浮点数格式化为字符串
      // sprintf((char *)temp_buffer, "Temp=%.1fC,Hum=%.0f%%\r\n", temperature, humidity);
      // HAL_UART_Transmit(&huart1, temp_buffer, strlen((char *)temp_buffer), 0xFF);
      isTimerElapsed = 0;
    }
    else
    {
      // 处理错误
      // sprintf((char *)temp_buffer, "Error DHT11");
      // HAL_UART_Transmit(&huart1, temp_buffer, strlen((char *)temp_buffer), 0xFF);
      isTimerElapsed = 0;
      HAL_Delay(1000);
    }
  }
}

void LCD_process_event(void)
{
  uint8_t temp_buffer[128];
  sprintf((char *)temp_buffer, "Temp=%.1fC    ", temperature);
  ST7789_WriteString(0, 18, (char *)temp_buffer, Font_11x18, BLACK, WHITE);
  sprintf((char *)temp_buffer, "Hum=%.0f%%    ", humidity);
  ST7789_WriteString(0, 18 + 18, (char *)temp_buffer, Font_11x18, BLACK, WHITE);
}
/* USER CODE END 4 */

 PS: 里面的注释内容纯纯调试,可以克隆或者下载我的项目,然后编译下载到单片机里面查看信息;

最后是将这个函数放到while这里,其实还有其它写法,就是取消下面的注释。然后将时间处理函数的LCD显示函数给注释掉。

四、结果展示

因为这里我加了个延时以及加上等待DHT11初始化完毕,所以开头就有些缓慢;

总是感觉这个模块又准又不准的。不清楚,能用就行。

五、结尾

这是我项目中使用到的模块,现在将其拆分并分享出来,供大家学习。

制作不易,有问题可以评论区交流。

最后,这个PCB底板是我使用嘉立创打板制作的,后期调整好之后可以将它开源?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值