STM32使用DHT11传感器读取温湿度,显示在LCD屏上

1. 温湿度传感器 DHT11/12

传感器中有一个高性能的8位单片机,会采集并完成数据转换。

1.1 DHT1x应用电路图

在这里插入图片描述

1.2 温湿度模块引脚

在这里插入图片描述

1.3 连接到STM32上的引脚

1.4 STM32CubeMX属性配置

这里给PA8重新给了名字,叫DHT,代码中也做相应修改。
在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述

1.5 调用函数

dht.c放在最后,主函数中需要开启tim6定时器,调用dht_read()函数即可实现温湿度的读取。
在这里插入图片描述

传输的数据格式(40位):8bit湿度整数数据 + 8bit湿度小数数据 + 8bit温度证书数据 + 8bit湿度小数数据 + 8bit校验和。
8位校验和 = 8bit湿度整数数据+8bit湿度小数数据+8bi温度整数数据+8bit温度小数数据 所得结果的末8位。

2. I2C和SPI的工作原理

I2C和SPI都是芯片和芯片之间通信总线,都有时钟线,都是同步的。
在这里插入图片描述

2.1 I2C

I2C用2根双向信号线(时钟线SCL,数据线SDA)来传输数据。
半双工的通信方式,同步

1对n的模式,一个主机,n个从机,每一个从机都有一个7位的地址,主机通过地址找到从机。
在这里插入图片描述

传输开始:时钟线高电平,数据线由高变低
在这里插入图片描述

传输结束:时钟线高电平,数据线由低变高

2.2 SPI

串行外围设备接口,全双工的通信总线,高速,同步。

接口有四根线:

  • 串行时钟线SCK
    
  • 主机输入/从机输出数据线MISO
    
  • 主机输出/从机输入数据线MOSI
    
  • 低电平有效的从机选择线SS ,也叫片选线(有的SPI接口芯片带有中断信号线INT或INT、有的SPI接口芯片没有主机输出/从机输入数据线MOSI)
    

片选线拉低表示主机选中某个从机。

SPI的工作模式有两种:主模式、从模式,无论那种模式,都支持3Mbit/s的速率

2.3 UART、I2C、SPI比较

UART:3条线(接收数据线RXD,发送数据线TXD,地线GND),串行,半双工,异步
I2C:2条线(时钟线SCL,数据线SDA),半双工,同步
SPI:4条线(串行时钟线SCK,主发从收MOSI,主收从发MISO,片选线SS),全双工,同步

3. 驱动LCD屏

3.1 STM32控制LCD方式

在这里插入图片描述

3.2 LCD屏引脚

在这里插入图片描述

3.3 连接到STM32上对应的引脚

在这里插入图片描述

3.4 STM32CubeMX中设置对应引脚模式

在这里插入图片描述

3.5 设置SPI属性

在这里插入图片描述

3.6 调用函数

显示在LCD屏上的字符是需要通过文字取模软件转换成16进制的,控制LCD的部分代码在最后。
主函数中需要对LCD屏进行初始化、设置显示区域、清屏。
在这里插入图片描述

函数用法举例说明:
lcd_drawcharWen(0, 15, (uint16_t)0x00FF00, (uint16_t)0x000000);
函数作用:在LCD上显示“温”字,温字对应的16进制已经通过取模软件保存在了.c文件的最后,直接调用即可。
参数1:横坐标,从左向右
参数2:纵坐标,从上到下
参数3:前景色
参数4:背景色

附 dht.c代码

#include "gpio.h"
#include <stdio.h>
extern uint8_t data_total[4];

void delay_us(uint16_t wait)
{
   
	//TIM6的一个时钟周期是1us
	
	//设置TIM6的计数器的值为1
	TIM6->CNT = 0;
	//LL_TIM_SetCounter(TIM6, 0);
	//LL_TIM_GetCounter(TIM6);
	
	//计数1次是1us,计数wait次就是waitus
  //printf("%d\n", TIM6->CNT);
	while(TIM6->CNT < wait);	
  //printf("%d\n", TIM6->CNT);
}

//等待高、低电平结束
//level:高/低电平
//timeout:超时时间(us)
//返回值:等待的时间(us)
uint32_t wait_level(GPIO_PinState level, uint32_t timeout)
{
   
  uint32_t wait = 0;
  while (HAL_GPIO_ReadPin(DHT_GPIO_Port, DHT_Pin) == level)
  {
   
    delay_us(1);
    wait++;
    if (wait >= timeout)
    {
   
      break; //超时退出
    }
  }
  
  return wait;
}

//读取温湿度
void dht_read(void)
{
   
  GPIO_InitTypeDef GPIO_InitStruct = {
   0};
  
  //将数据引脚设置为输出模式
  GPIO_InitStruct.Pin = DHT_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(DHT_GPIO_Port, &GPIO_InitStruct);
  
  //发送起始信号(输出低电平并持续18ms以上)
  HAL_GPIO_WritePin(DHT_GPIO_Port, DHT_Pin, GPIO_PIN_RESET);
  HAL_Delay(19);
  
  //将数据引脚设置为输入模式,电平由外部上拉电阻拉高
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  HAL_GPIO_Init(DHT_GPIO_Port, &GPIO_InitStruct);
  
  //主机发送开始信号结束后,延时等待20-40us后,读取DHT1X的响应信号
  delay_us(40);
  
  //判断DHT传感器是否发出响应信号(低电平)
  if (HAL_GPIO_ReadPin(DHT_GPIO_Port, DHT_Pin) == GPIO_PIN_SET)
  {
   
    //如果传感器没有响应,打印错误信息并终止读取
    printf("DHT sensor no response\r\n");
    return;
  }
  
  //如果传感器响应,等待响应信号结束
  //等待低电平结束
  wait_level(GPIO_PIN_RESET, 80);
  //等待高电平结束
  wait_level(GPIO_PIN_SET, 100);
  
  //保存收到的40bit数据
  uint8_t data[5];
  
  uint8_t j;
  for (j = 0; j < 5; j++)
  {
   
    //读取一个字节
    uint8_t i;
    for (i = 0; i < 8; i++)
    {
   
      //开始接收数据
      //统计低电平持续时间
      uint32_t low_time = wait_level(GPIO_PIN_RESET, 70);
      //统计高电平持续时间
      uint32_t high_time = wait_level(GPIO_PIN_SET, 100);
      if (low_time > high_time)
      {
   
        //收到bit0
        data[j] &= (~(0x80 >> i)); //将第i个有效位清0
      }
      else
      {
   
        //收到bit1
        data[j] |= (0x80 >> i); //将第i个有效位置1
      }
    }
  }
  
  //当最后一bit数据传送完毕后,DHT1X拉低总线50us
  wait_level(GPIO_PIN_RESET, 50);
  
  //计算校验和
  //数据传送正确时校验和数据等于
  //“8bit湿度整数数据+8bit湿度小数数据+8bit温度整数数据+8bit温度小数数据”
  //所得结果的末8位。
  uint8_t chksum = data[0] + data[1] + data[2] + data[3];
  if (chksum != data[4])
  {
   
    //校验和错误打印出错信息
    printf("checksum error\r\n");
    return;
  }
  
  //打印温湿度信息
  //printf("Humidity: %d.%d, ", data[0], data[1]);
  //printf("Temprature: %d.%d\r\n", data[2], data[3]);
	printf("ht,%d.%d,%d.%d",data[0],data[1],data[2], data[3]);
	data_total[0] = data[0];
	data_total[1]= data[1];
	data_total[2] = data[2];
	data_total[3] = data[3];
}

附 lcd.h和lcd.c代码

//lcd.h
#ifndef LCD_H
#define LCD_H

#include <stdint.h>

extern uint8_t ni1[4][32];
void lcd_init(void);
void lcd_clear(uint16_t color);
uint16_t lcd_color(uint8_t red, uint8_t green, uint8_t blue);
void lcd_drawimage(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint16_t* image);
void lcd_drawtext8x16(uint8_t x, uint8_t y, uint16_t fc, uint16_t bc, uint8_t* font);
void lcd_drawstringlower(uint8_t x, uint8_t y, uint16_t fc, uint16_t bc, char* s);
void lcd_drawname(uint8_t x, uint8_t y, uint16_t fc, uint16_t bc);
void lcd_drawni(uint8_t x, uint8_t y, uint16_t fc, uint16_t bc);
void lcd_drawfu(uint8_t x, uint8_t y, uint16_t fc, uint16_t bc);
void lcd_drawwendu(uint8_t x, uint8_t y, uint16_t fc, uint16_t bc);
void lcd_drawnum(uint8_t x, uint8_t y, uint16_t fc, uint16_t bc, uint8_t num);
void lcd_drawmid(uint8_t x, uint8_t y, uint16_t fc, uint16_t bc);
void lcd_drawtext16x16(uint8_t x, uint8_t y, uint16_t fc, uint16_t bc, uint8_t* font);
void lcd_region(uint8_t xbegin, uint8_t xend, uint8_t ybegin, uint8_t yend);
void lcd_drawtext32x32(uint8_t x, uint8_t y, uint16_t fc, uint16_t bc, uint8_t* font);
void lcd_drawpoint(uint8_t x, uint8_t y, uint16_t color);

void lcd_drawcharWen(uint8_t x, uint8_t y, uint16_t fc, uint16_t bc);
void lcd_drawcharDu(uint8_t x, uint8_t y, uint16_t fc, uint16_t bc);
void lcd_drawcharShi(uint8_t x, uint8_t y, uint16_t fc, uint16_t bc);
void lcd_drawcharKai(uint8_t x, uint8_t y, uint16_t fc, uint16_t bc);
void lcd_drawcharGuan(uint8_t x, uint8_t y, uint16_t fc, uint16_t bc);
void lcd_drawcharDeng(uint8_t x, uint8_t y, uint16_t fc, uint16_t bc);
#endif

//lcd.c
#include "spi.h"
#include "gpio.h"
#include "lcd.h"

#include "string.h"

//发送命令到ST7735S显示控制芯片
void lcd_sendcmd(uint8_t cmd)
{
   
  //拉低RS引脚,发送的字节作为命令执行
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_4, GPIO_PIN_RESET);
  //发送一个字节的命令码
  HAL_SPI_Transmit(&hspi1, &cmd, 1, HAL_MAX_DELAY);
}

//发送数据到ST7735S显示控制芯片
void lcd_senddata(uint8_t data)
{
   
  //拉高RS引脚,发送的字节作为数据
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_4,GPIO_PIN_SET);
  //发送一个字节的数据
  HAL_SPI_Transmit(&hspi1, &data, 1, HAL_MAX_DELAY);
}

//LCD初始化
void lcd_init(void)
{
   
  //发送复位命令
  lcd_sendcmd(0x01);
  //等待复位完成120ms
  HAL_Delay(120);
  //关闭睡眠模式
  lcd_sendcmd(0x11);
  //等待自检完成
  HAL_Delay(120);
  //配置显存访问方式
  lcd_sendcmd(0x36);
  //Row Address Order:1
  //Column Address Order:1
  //Row/Column Exchange:0
  //Vertical Refresh Order: Top to Bottom(0)
  //RGB-BGR ORDER: BGR(1)
  //Horizontal Refresh Order:Left to right(0)
  lcd_senddata(0xc8);
  //设置像素颜色格式
  lcd_sendcmd(0x3a);
  //使用16bit颜色
  lcd_senddata(0x05);
  //显示显存中的内容
  lcd_sendcmd(0x29);
}

//设置显示区域
void lcd_region(uint8_t xbegin, uint8_t xend, uint8_t ybegin, uint8_t yend)
{
   
  //设置起始列和结束列
  lcd_sendcmd(0x2a);
  //起始列高字节
  lcd_senddata(0);
  //起始列低字节
  lcd_senddata(xbegin + 2);
  //结束列高字节
  lcd_senddata(0);
  //结束列低字节
  lcd_senddata(xend + 2);
  
  //设置起始行和结束行
  lcd_sendcmd(0x2b);
  //起始行高字节
  lcd_senddata(0);
  //起始行低字节
  lcd_senddata(ybegin + 3);
  //结束行高字节
  lcd_senddata(0);
  //结束行低字节
  lcd_senddata(yend + 3);
  
  //写显存
  lcd_sendcmd(0x2c);
}

//发送一个像素的颜色
void lcd_sendpixel(uint16_t color)
{
   
  //高字节先发送
  lcd_senddata(color >> 8);
  lcd_senddata(color & 0xff);
}

//将RGB888转为RGB565
uint16_t lcd_color(uint8_t red, uint8_t green, uint8_t blue)
{
   
  return ((red & 0xf8) << 11)|((green & 0xfc) << 5)|((blue & 0xf8) >> 3);
}

//清屏函数
void lcd_clear(uint16_t color)
{
   
  int i;
  //定位显存写入位置
  lcd_region(0, 127, 0, 127);
  for (i = 0; i < 128 * 128; i++)
  {
   
    lcd_sendpixel(color);
  }
}



//显示图片
//x: 起始列
//y: 起始行
//w: 图像宽度(像素)
//h: 图像高度(像素)
//image: 保存图像数据的数组
void lcd_drawimage(uint8_t x, uint8_t y, uint8_t w, uint8_t h, const uint16_t* image)
{
   
  int i;
  //定位显存写入位置
  lcd_region(x, x + w - 1, y, y + h - 1);
  for (i = 0; i < w * h; i++)
  {
   
    lcd_sendpixel(image[i]);
  }
}


//取模配置:
//1. 前景色用bit1表示,背景色用bit0表示(阴码)
//2. 低位在前
//显示字符
//x: 起始列
//y: 起始行
//fc: 前景色
//bc: 背景色
//font: 字模数组
void lcd_drawtext8x16(uint8_t x, uint8_t y, uint16_t fc, uint16_t bc, uint8_t* font)
{
   
  lcd_region(x, x + 8 - 1, y, y + 16 -1);
  
  //填充16行
  uint8_t j;
  for (j = 0; j < 16; j++)
  {
   
    //填充一行
    uint8_t i;
    for (i = 0; i < 8; i++)
    {
   
      if ((font[j] & (1 << i)) != 0)
      {
   
        //填充前景色
        lcd_sendpixel(fc);
      }
      else
      {
   
        //填充背景色
        lcd_sendpixel(bc);
      }
    }
  }
}

uint8_t lower[][16] = {
   
  {
   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1C,0x22,0x30,0x2C,0x22,0x32,0x6C,0x00,0x00},/*"a",0*/
  {
   0x00,0x00,0x00,0x00,0x03,0x02,0x02,0x1A,0x26,0x42,0x42,0x42,0x26,0x1A,0x00,0x00},/*"b",1*/
  {
   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x44,0x02,0x02,0x02,0x44,0x38,0x00,0x00},/*"c",2*/
  {
   0x00,0x00,0x00,0x00,0x60,0x40,0x40,0x7C,0x42,0x42,0x42,0x42,0x62,0xDC,0x00,0x00},/*"d",3*/
  {
   0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3C,0x42,0x42,
  • 6
    点赞
  • 68
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下面是一个基于STM32DHT11LCD显示的蓝牙温湿度检测完整代码,使用HC-05蓝牙模块将温湿度数据发送到蓝牙终端设备上,同时将数据显示在1602液晶屏上: ``` #include <dht11.h> #include <SoftwareSerial.h> #include <LiquidCrystal.h> #define DHT11_PIN PB1 //DHT11传感器数据引脚 #define BT_TX PA2 //蓝牙模块TX引脚 #define BT_RX PA3 //蓝牙模块RX引脚 #define LCD_RS PA4 //LCD1602 RS引脚 #define LCD_EN PA5 //LCD1602 EN引脚 #define LCD_D4 PA6 //LCD1602 D4引脚 #define LCD_D5 PA7 //LCD1602 D5引脚 #define LCD_D6 PB0 //LCD1602 D6引脚 #define LCD_D7 PB10 //LCD1602 D7引脚 dht11 DHT11; //DHT11传感器对象 SoftwareSerial BTSerial(BT_TX, BT_RX); //蓝牙串口对象 LiquidCrystal lcd(LCD_RS, LCD_EN, LCD_D4, LCD_D5, LCD_D6, LCD_D7); //LCD1602对象 void setup() { Serial.begin(9600); BTSerial.begin(9600); lcd.begin(16, 2); lcd.print("Temp: Humi: "); } void loop() { int chk = DHT11.read(DHT11_PIN); if (chk == DHTLIB_OK) { float temp = DHT11.temperature; float humi = DHT11.humidity; String temp_str = String(temp, 1) + " C"; String humi_str = String(humi, 1) + " %"; lcd.setCursor(6, 0); lcd.print(temp_str); lcd.setCursor(6, 1); lcd.print(humi_str); String data = String(temp) + "," + String(humi); BTSerial.println(data); //将温湿度数据通过蓝牙发送出去 Serial.println(data); //将温湿度数据打印到串口监视器 } else { Serial.print("DHT11 read error: "); Serial.println(chk); } delay(3000); //每隔3秒采集一次温湿度数据 } ``` 需要注意的是,本示例使用的是HC-05蓝牙模块和LCD1602液晶屏,如果您使用的是其他型号的蓝牙模块或显示屏,可能需要进行相应的修改。另外,由于DHT11读取数据的时间较长,需要在发送数据之前加一定的延时,以免出现数据传输错误。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值