基于stm32的LCD1602与无线蓝牙温湿度显示

news2024/12/24 3:32:52

       这一篇博客是为了实现温湿度的显示,温湿度传感器将数据穿给单片机,单片机又把数据送给LCD1602和蓝牙,让温度和湿度可以再LCD1602显示屏和手机上显示,它的执行逻辑和C51那里基本一样,就是要修改程序,在程序上有略微的差距。至于LCD1602显示屏和dth11温度传感器怎么用 ,大家可以看看我C51有关的博客,上面对于如何使用说的很详细,http://t.csdnimg.cn/8DY1b  

一、硬件介绍

名字图片作用
32单片机--
LCD1602显示屏显示温湿度,具体的接线如下所示:VSS -- GND VDD -- 5V , VO -- GND ;RS -- B1, RW -- B2, E -- 10; BLA -- 5V, BLK -- GDN ; D0到D7 -- A0.到A7
蓝牙模块与手机蓝牙通信,在手机上显示温湿度,TX接串口1的RX,RX接串口1的TX
温湿度传感器VCC接3.3V或5V,GND接地,中间的DATE引脚接PB7
继电器干控制电池为电机供电,当温度或者湿度达到临界值后,继电器闭合,干电翅,电机,继电器三者组成的电路通路.继电器的VCC接3.3V
电机-
2节干电池-为电机提供电源

二、stm32Cube的配置

SYS,RCC,照旧,我们要把如下图所示的GPIO口全部配置成推完输出,初始状态为高电平

串口使用串口1,对打开对应的中断,如下图所示

三、代码部分

这里要说的是,32单片机的引脚不同于C51,32单片机的引脚的输入和输出状态不能够同时出现。但是在dht11温度传感器里面,温度传感器里面的date引脚与单片机的引脚相连接,该单片机引脚既要输出信号启动温度传感器,又要读入信号,判断传感器是否工作,因此我们没有在stm32Cube里配置该引脚(PB7),而是自己手动配置。

#define DHT_VALUE HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_7)

void DHT_GPIO_Init(uint32_t mode)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    __HAL_RCC_GPIOB_CLK_ENABLE();

  /*Configure GPIO pin : PB8 */
  GPIO_InitStruct.Pin = GPIO_PIN_7;
  GPIO_InitStruct.Mode = mode;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}

void DHT11_Start()
{
    DHT_GPIO_Init(GPIO_MODE_OUTPUT_PP);//作为输出引脚,启动温度传感器
    DHT_HIGH;
    DHT_LOW;
    HAL_Delay(30);
    DHT_HIGH;
    
    DHT_GPIO_Init(GPIO_MODE_INPUT);作为输入引脚,判断温度传感器是否工作
    while(DHT_VALUE);
    while(!DHT_VALUE);
    while(DHT_VALUE);
}

在LCD1602中我们写了输入数据还有输入指令的函数

void Write_Cmd_Func(char cmd)
{
    RS_LOW;
    RW_LOW;
    EN_LOW;
    GPIOA->ODR = cmd;
    HAL_Delay(5);
    EN_HIGH;
    HAL_Delay(5);
    EN_LOW;
}

void Write_Data_Func(char dataShow)
{
    RS_HIGH;
    RW_LOW;
    EN_LOW;
    GPIOA->ODR = dataShow;
    HAL_Delay(5);
    EN_HIGH;
    HAL_Delay(5);
    EN_LOW;
}

ODR代表输出数据寄存器,  GPIOA->ODR = cmd就是说我们要把cmd这个数据给到输出数据寄存器,这样ODR就会把对应的内容给到LCD1602

在main函数里面

char message[16];

memset(message, 0, sizeof(message));

sprintf(message, "Temp: %d.%d", datas[2], datas[3]);

memset(message, 0, sizeof(message));

sprintf(message, "Humi: %d.%d", datas[0], datas[1]);

sprintf函数可以重映射,把datas[i]里面的数据变成字符串存到 message里,可以让LCD1602输出,但是不能用做串口的输出,串口输出依旧用printf函数,在下面的main.c里有体现

memset函数是清除message里面的内容,防止传输内容出错。

HAL_NVIC_SetPriority(SysTick_IRQn,0,0);

系统滴答定时器的优先级提前,否则当你执行完中断里的命令后,容易死机,最好在main函数里加上

main.c的代码

#include "main.h"
#include "usart.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "stdio.h"
#include "string.h"
#include "lcd1602.h"
#include "dht11.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */
extern char datas[5];
extern uint8_t buf;
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */
	char message[16];
  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */
HAL_NVIC_SetPriority(SysTick_IRQn,0,0);
  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
	printf("hello world\r\n");
	LCD1602_INIT();
	HAL_UART_Receive_IT(&huart1, &buf, 1);
//	Write_Cmd_Func(position);//选择要显示的地址
//	Write_Data_Func(dataShow);//发送要显示的字符
//	LCD1602_showLine(1,5,"NO.2");                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                
//	LCD1602_showLine(2,0,"LX handsome");
	HAL_Delay(2000);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
		Read_Data_From_DHT();
		if(datas[2]>24)
			HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_RESET);
		else
			HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_SET);
		printf("Temp: %d.%d\r\n", datas[2], datas[3]);
		memset(message, 0, sizeof(message));
		sprintf(message, "Temp: %d.%d", datas[2], datas[3]);
		LCD1602_showLine(1, 0, message);
		printf("Humi: %d.%d\r\n", datas[0], datas[1]);
		memset(message, 0, sizeof(message));
		sprintf(message, "Humi: %d.%d", datas[0], datas[1]);
		LCD1602_showLine(2, 0, message);
		HAL_Delay(1000);
  }

usart.c

#include "usart.h"

/* USER CODE BEGIN 0 */
#include "stdio.h"
#include "string.h"

//串口接收缓存(1字节)
uint8_t buf=0;

//定义最大接收字节数 200,可根据需求调整
#define UART1_REC_LEN 200

// 接收缓冲, 串口接收到的数据放在这个数组里,最大UART1_REC_LEN个字节
uint8_t UART1_RX_Buffer[UART1_REC_LEN];

//  接收状态
//  bit15,      接收完成标志
//  bit14,      接收到0x0d
//  bit13~0,    接收到的有效字节数目
uint16_t UART1_RX_STA=0;

#define SIZE 12

char buffer[SIZE];

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	// 判断中断是由哪个串口触发的
	if(huart->Instance == USART1)
	{
		// 判断接收是否完成(UART1_RX_STA bit15 位是否为1)
		if((UART1_RX_STA & 0x8000) == 0)
		{
			// 如果已经收到了 0x0d (回车),
			if(UART1_RX_STA & 0x4000)
			{
				// 则接着判断是否收到 0x0a (换行)
				if(buf == 0x0a)
				{
					// 如果 0x0a 和 0x0d 都收到,则将 bit15 位置为1
					UART1_RX_STA |= 0x8000;

					// 灯控指令
					if(!strcmp(UART1_RX_Buffer, "OPEN"))
						HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_RESET);
					
					if(!strcmp(UART1_RX_Buffer, "CLOSE"))
						HAL_GPIO_WritePin(GPIOB, GPIO_PIN_3, GPIO_PIN_SET);
					
					memset(UART1_RX_Buffer, 0, UART1_REC_LEN);
					UART1_RX_STA = 0;
				}
				else
					// 否则认为接收错误,重新开始
					UART1_RX_STA = 0;
			}
			else	// 如果没有收到了 0x0d (回车)
			{
				//则先判断收到的这个字符是否是 0x0d (回车)
				if(buf == 0x0d)
				{
					// 是的话则将 bit14 位置为1
					UART1_RX_STA |= 0x4000;
				}
				else
				{
					// 否则将接收到的数据保存在缓存数组里
					UART1_RX_Buffer[UART1_RX_STA & 0X3FFF] = buf;
					UART1_RX_STA++;
					
					// 如果接收数据大于UART1_REC_LEN(200字节),则重新开始接收
					if(UART1_RX_STA > UART1_REC_LEN - 1)
						UART1_RX_STA = 0;
				}
			}
		}
		// 重新开启中断
		HAL_UART_Receive_IT(&huart1, &buf, 1);
	}
}

int fputc(int ch, FILE *f)
{      
    unsigned char temp[1]={ch};
    HAL_UART_Transmit(&huart1,temp,1,0xffff);  
    return ch;
}

记得勾选Use Micro LIB

dht11.c

#include "dht11.h"
#include "gpio.h"

#define DHT_HIGH HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_SET)
#define DHT_LOW HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_RESET)
#define DHT_VALUE HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_7)

char datas[5];

void delay_us(uint16_t cnt)
{
    uint8_t i;

    while(cnt)
    {
        for (i = 0; i < 10; i++)
        {

        }
        cnt--;
    }
}

void DHT_GPIO_Init(uint32_t mode)
{
	GPIO_InitTypeDef GPIO_InitStruct = {0};
	__HAL_RCC_GPIOB_CLK_ENABLE();

  /*Configure GPIO pin : PB8 */
  GPIO_InitStruct.Pin = GPIO_PIN_7;
  GPIO_InitStruct.Mode = mode;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}

void DHT11_Start()
{
	DHT_GPIO_Init(GPIO_MODE_OUTPUT_PP);
	DHT_HIGH;
	DHT_LOW;
	HAL_Delay(30);
	DHT_HIGH;
	
	DHT_GPIO_Init(GPIO_MODE_INPUT);
	while(DHT_VALUE);
	while(!DHT_VALUE);
	while(DHT_VALUE);
}

void Read_Data_From_DHT(void)
{
	int i;//轮
	int j;//每一轮读多少次
	char tmp;
	char flag;
	
	DHT11_Start();
	DHT_GPIO_Init(GPIO_MODE_INPUT);
	for(i= 0;i < 5;i++){
		//卡g点:while(!dht)       有效数据都是高电平,持续时间不一样,50us读,低电平0 高电平
		for(j=0;j<8;j++){
			while(!DHT_VALUE);//等待卡g点
			delay_us(40);
			if(DHT_VALUE == 1){
				flag = 1;
				while(DHT_VALUE);
			}else{
				flag = 0;
			} 
			tmp = tmp << 1;
			tmp |= flag;
		}
		datas[i] = tmp;
	}
}

lcd1602.c

#include "lcd1602.h"
#include "gpio.h"

#define RS_GPIO_Port GPIOB
#define RW_GPIO_Port GPIOB
#define EN_GPIO_Port GPIOB
#define RS_GPIO_PIN GPIO_PIN_1
#define RW_GPIO_PIN GPIO_PIN_2
#define EN_GPIO_PIN GPIO_PIN_10

#define RS_HIGH HAL_GPIO_WritePin(RS_GPIO_Port, RS_GPIO_PIN, GPIO_PIN_SET)
#define RS_LOW HAL_GPIO_WritePin(RS_GPIO_Port, RS_GPIO_PIN, GPIO_PIN_RESET)
#define RW_HIGH HAL_GPIO_WritePin(RW_GPIO_Port, RW_GPIO_PIN, GPIO_PIN_SET)
#define RW_LOW HAL_GPIO_WritePin(RW_GPIO_Port, RW_GPIO_PIN, GPIO_PIN_RESET)
#define EN_HIGH HAL_GPIO_WritePin(EN_GPIO_Port, EN_GPIO_PIN, GPIO_PIN_SET)
#define EN_LOW HAL_GPIO_WritePin(EN_GPIO_Port, EN_GPIO_PIN, GPIO_PIN_RESET)

void Write_Cmd_Func(char cmd)
{
	RS_LOW;
	RW_LOW;
	EN_LOW;
	GPIOA->ODR = cmd;
	HAL_Delay(5);
	EN_HIGH;
	HAL_Delay(5);
	EN_LOW;
}

void Write_Data_Func(char dataShow)
{
	RS_HIGH;
	RW_LOW;
	EN_LOW;
	GPIOA->ODR = dataShow;
	HAL_Delay(5);
	EN_HIGH;
	HAL_Delay(5);
	EN_LOW;
}

void LCD1602_INIT(void)
{
	//(1)延时 15ms
	HAL_Delay(15);
//(2)写指令 38H(不检测忙信号) 
	Write_Cmd_Func(0x38);
//(3)延时 5ms
	HAL_Delay(5);
//(4)以后每次写指令,读/写数据操作均需要检测忙信号
//(5)写指令 38H:显示模式设置
	Write_Cmd_Func(0x38);
//(6)写指令 08H:显示关闭
	Write_Cmd_Func(0x08);
//(7)写指令 01H:显示清屏
	Write_Cmd_Func(0x01);
//(8)写指令 06H:显示光标移动设置
	Write_Cmd_Func(0x06);
//(9)写指令 0CH:显示开及光标设置}
	Write_Cmd_Func(0x0c);
}

void LCD1602_showLine(char row, char col, char *string)
{
	
	switch(row){

		case 1:
				Write_Cmd_Func(0x80+col);
				while(*string){
					Write_Data_Func(*string);
					string++;
				}
				break;
		
		case 2:
				Write_Cmd_Func(0x80+0x40+col);
				while(*string){
					Write_Data_Func(*string);
					string++;
				}
				break;
	
	}
}

按照上述代码后,连接实物,打开对应的手机蓝牙APP连接就可以使用了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1284177.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

选择排序、插入排序、希尔排序

1.选择排序 算法描述 将数组分为两个子集&#xff0c;排序的和未排序的&#xff0c;每一轮从未排序的子集中选出最小的元素&#xff0c;放入排序子集 重复以上步骤&#xff0c;直到整个数组有序 选择排序呢&#xff0c;就是首先在循环中&#xff0c;找到数组中最小的元素。在…

基恩士软件的基本操作(六,KV脚本的使用)

目录 什么是KV脚本&#xff1f; KV脚本有什么用&#xff1f; 怎么使用KV脚本&#xff08;脚本不能与梯形图并联使用&#xff09;&#xff1f; 插入框脚本&#xff08;CtrlB&#xff09; 插入域脚本&#xff08;CtrlR&#xff09; 区别 脚本语句&#xff08;.T是字符串类…

详解原生Spring当中的事务

&#x1f609;&#x1f609; 学习交流群&#xff1a; ✅✅1&#xff1a;这是孙哥suns给大家的福利&#xff01; ✨✨2&#xff1a;我们免费分享Netty、Dubbo、k8s、Mybatis、Spring...应用和源码级别的视频资料 &#x1f96d;&#x1f96d;3&#xff1a;QQ群&#xff1a;583783…

Redis实战篇笔记(最终篇)

Redis实战篇笔记&#xff08;七&#xff09; 文章目录 Redis实战篇笔记&#xff08;七&#xff09;前言达人探店发布和查看探店笔记点赞点赞排行榜 好友关注关注和取关共同关注关注推送关注推荐的实现 总结 前言 本系列文章是Redis实战篇笔记的最后一篇&#xff0c;那么到这里…

界面组件DevExpress Reporting v23.1新版亮点 - UX功能增强

DevExpress Reporting是.NET Framework下功能完善的报表平台&#xff0c;它附带了易于使用的Visual Studio报表设计器和丰富的报表控件集&#xff0c;包括数据透视表、图表&#xff0c;因此您可以构建无与伦比、信息清晰的报表 界面组件DevExpress Reporting v23.1已于前段时间…

探讨Unity中的动画融合技术(BlendTree)

动画在游戏和虚拟现实应用中扮演着关键的角色&#xff0c;而动画融合技术则是使角色动作更加流畅和逼真的核心。在Unity引擎中&#xff0c;我们可以使用动画混合树&#xff08;Blend Trees&#xff09;来实现这一目标。本篇技术博客将深入讨论动画融合技术的实现原理、在Unity中…

C++ 指针详解

目录 一、指针概述 指针的定义 指针的大小 指针的解引用 野指针 指针未初始化 指针越界访问 指针运算 二级指针 指针与数组 二、字符指针 三、指针数组 四、数组指针 函数指针 函数指针数组 指向函数指针数组的指针 回调函数 指针与数组 一维数组 字符数组…

FreeRTOS调度器启动过程分析

目录 引出思考 vTaskStartScheduler()启动任务调度器 xPortStartScheduler()函数 FreeRTOS启动第一个任务 vPortSVCHandler()函数 总结 引出思考 首先想象一下如何启动第一个任务&#xff1f; 假设我们要启动的第一个任务是任务A&#xff0c;那么就需要将任务A的寄存器值…

腾讯云手动下发指令到设备-用于设备调试

打开腾讯云API Explorer&#xff0c;Publish Msg https://console.cloud.tencent.com/api/explorer?Productiotcloud&Version2021-04-08&ActionPublishMessagehttps://console.cloud.tencent.com/api/explorer?Productiotcloud&Version2021-04-08&ActionPub…

【模电】设置静态工作点的必要性

设置静态工作点的必要性 静态工作点为什么要设置静态工作点 静态工作点 在放大电路中&#xff0c;当有信号输入时&#xff0c;交流量与直流量共存。将输入信号为零、即直流电源单独作用时晶体管的基极电流 I B I\tiny B IB、集电极电流 I C I\tiny C IC、b - e间电压 U B E U\t…

语义分割网络FCN

语义分割是一种像素级的分类&#xff0c;输出是与输入图像大小相同的分割图&#xff0c;输出图像的每个像素对应输入图像每个像素的类别&#xff0c;每一个像素点的灰度值都是代表当前像素点属于该类的概率。 语义分割任务需要解决的是如何把定位和分类这两个问题一起解决&…

佛罗里达大学利用神经网络,解密 GPCR-G 蛋白偶联选择性

内容一览&#xff1a;G 蛋白偶联受体 (GPCRs) 是一种将细胞膜外的刺激&#xff0c;传递到细胞膜内的跨膜蛋白&#xff0c;广泛参与到人体生理活动当中。近日&#xff0c;佛罗里达大学的研究者测定了 GPCRs 和 G 蛋白的结合选择性&#xff0c;并开发了预测二者选择性的算法&…

kubernetes监控GPA安装部署

本文在于指导如何对k8s的监控GPA(Grafana&#xff0c;prometheus以及alertmanager)进行安装部署。 1. 介绍 Prometheus 在真正部署Prometheus之前&#xff0c;应了解一下Prometheus的各个组件之间的关系及作用&#xff1a; 1&#xff09;MertricServer&#xff1a;是k8s集群…

朋友圈7大黄金发圈时间

众所周知&#xff0c;朋友圈运营是私域运营必不可少的重要环节。 因为做好朋友圈运营&#xff0c;能够打造形成高质量、高价值的私域流量&#xff0c;加快实现用户成交。 那么如何形成一个吸粉又吸金的人设&#xff0c;做出高质量的朋友圈发圈内容呢&#xff1f; 那么如何确保能…

SSM整合(注解版)

SSM 整合是指将学习的 Spring&#xff0c;SpringMVC&#xff0c;MyBatis 进行整合&#xff0c;来进行项目的开发。 1 项目基本的配置类 1.1 Spring 配置类 这个配置类主要是管理 Service 中的 bean&#xff0c;controller 层的 bean 对象是 SpringMVC 管理的 package cn.ed…

二极管:二极管的基本原理

一、认识导体、绝缘体、半导体 什么是导体&#xff1f; 导体 conductor &#xff0c;是指电阻率很小&#xff0c;且容易传导电流的物质。导体中存在大量可自由移动的带电粒子&#xff0c;也称为载流子。在外电场的作用下&#xff0c;载流子作定向运动&#xff0c;形成电流。 …

安装配置JDK1.8

JDK1.8的下载及配置 1.进入甲骨文官网甲骨文官网往下翻找到java8并且点击windows. 2.下载Java8必须登录账号 3下载完后点击进入安装&#xff0c;直接下一步就可以&#xff0c;记住这个路径。 4.右击我的电脑进入环境配置&#xff0c;新增变量。 CLASSPATH .;%JAVAHOME%\lib;…

3.C程序编译步骤

目录 1 预处理 2 编译 3 汇编 4 链接 5 文件大小情况 依次执行下面4个步骤 预处理 将所有头文件展开&#xff0c;比如stdio.h等&#xff0c;展开就相当于把stdio.h中的所有代码粘贴到你的代码里。将所有的宏文件展开&#xff0c;像stdio.h是官方定义的头文件&#x…

C# - Opencv应用(3) 之矩阵Mat使用[图像截取粘贴、ROI操作、位运算、数学计算]

C# - Opencv应用&#xff08;3&#xff09; 之矩阵Mat使用[图像截取粘贴、ROI操作、位运算、数学计算] 图像读取&#xff0c;大小、截取、位运算图像ROI操作&#xff1a;粘贴赋值、滤波图像数学计算部分结果如下&#xff1a; 1.图像读取&#xff0c;大小、截取、位运算 //图…

计算机辅助药物设计AIDD-小分子-蛋白质|分子生成|蛋白质配体相互作用预测

文章目录 计算机辅助药物设计AIDD【小分子专题】AIDD概述及药物综合数据库学习机器学习辅助药物设计图神经网络辅助药物设计自然语言处理辅助药物设计药物设计与分子生成 计算机辅助药物设计【蛋白质专题】蛋白质数据结构激酶-Kinase相似性学习基于序列的蛋白质属性预测基于结构…