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

       这一篇博客是为了实现温湿度的显示,温湿度传感器将数据穿给单片机,单片机又把数据送给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);elseHAL_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 12char 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 位置为1UART1_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 位置为1UART1_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)延时 15msHAL_Delay(15);
//(2)写指令 38H(不检测忙信号) Write_Cmd_Func(0x38);
//(3)延时 5msHAL_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.mzph.cn/news/197098.shtml

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

相关文章

Windows server——部署DHCP服务(2)

作者简介&#xff1a;一名云计算网络运维人员、每天分享网络与运维的技术与干货。 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a;网络豆的主页​​​​​​ 目录 前言 一.配置DHCP服务 1.DHCP安装的要求 安装DHCP服务器需要满足如下要求&#…

python pyaudio显示音频波形图

python pyaudio显示音频波形图 代码如下&#xff1a; import numpy as np import matplotlib.pylab as plb import wave# 读取 wav wf wave.open("./output.wav", "rb")# 获取音频相关参数&#xff1a;声道数、量化位数、采样频率、采样帧数 nchannels,…

2023全网最新-免杀方法大集结

目录 00. 概述 01. 简介 02. 静态免杀 1. 怎么找特征码 工具查找 手工查找 其他 2. 怎么免杀&#xff1f; 手工修改 非源码 工具免杀&#xff08;盲免杀&#xff09; 03. 行为动态免杀 行为拦截原理 如何进行行为免杀呢&#xff1f; 总结 注意/技巧 00. 概述 …

分享全球顶尖的AIGC文生图资源

1 引言 人工智能正在改变许多行业的格局&#xff0c;而其中改变最直观和影响最大的就是AIGC领域的图像创作。文生图技术作为AIGC的一个重要分支&#xff0c;展现了人工智能在视觉创作领域的巨大潜力。发展至今已经有很多AI文生图平台&#xff0c;这是一次革命性的突破&#xf…

ENVI植被指数阈值法

植被指数阈值法提取纯净像元 首先用ENVI打开无人机遥感影像 1. 假彩色显示 打开数据管理工具&#xff0c;无人机的4波段为红边波段 2. 波段计算 打开band math&#xff0c;输入 float(b1-b2)/(b1b2) 选择对应波段 3. 阈值筛选 阈值按经验值选的0.7&#xff0c;ndvi…

Vue3引入markdown编辑器--Bytemd

字节跳动开源了一款markdown编辑器&#xff0c;bytemd&#xff0c;项目地址&#xff1a;GitHub - bytedance/bytemd: ByteMD v1 repository 安装 npm i bytemd/vue-next 引入方式如下&#xff0c;再main.js中引入样式 import bytemd/dist/index.css 直接封装一个Markdown编…

Windows 10安装FFmpeg详细教程

Windows 10安装FFmpeg详细教程 0. 背景 在搭建之前的项目环境时&#xff0c;需要安装ffmpeg&#xff0c;在此记录下过程 1. 官网下载 点击进入官网&#xff1a;ffmpeg&#xff0c;官网地址&#xff1a;https://ffmpeg.org/download.html 如图所示&#xff0c;点击Windows图标…

Python中判定列表是否包含某个元素的方法

更多Python学习内容&#xff1a;ipengtao.com 大家好&#xff0c;我是彭涛&#xff0c;今天为大家分享 Python中判定列表是否包含某个元素的方法&#xff0c;全文4000字&#xff0c;阅读大约10分钟。 在Python编程中&#xff0c;判定一个列表是否包含特定元素是一项常见任务。本…

大模型技术的发展与实践

一、大模型的概念 大型语言模型&#xff0c;也称大语言模型、大模型&#xff08;Large Language Model&#xff0c;LLM&#xff1b;Large Language Models&#xff0c;LLMs) 。 大语言模型是一种深度学习模型&#xff0c;特别是属于自然语言处理&#xff08;NLP&#xff09;的…

类和对象——(6)友元

归纳编程学习的感悟&#xff0c; 记录奋斗路上的点滴&#xff0c; 希望能帮到一样刻苦的你&#xff01; 如有不足欢迎指正&#xff01; 共同学习交流&#xff01; &#x1f30e;欢迎各位→点赞 &#x1f44d; 收藏⭐ 留言​&#x1f4dd; 没有存储汗水&#xff0c;就无法支取成…

【LeetCode】每日一题 2023_12_1 找出叠涂元素(读题/数组/哈希)

文章目录 刷题前唠嗑题目&#xff1a;找出叠涂元素题目描述代码与解题思路 结语 刷题前唠嗑 LeetCode&#xff1f;启动&#xff01;&#xff01;&#xff01; 新的一个月开始啦&#xff01;这个月也要继续蝉联月度刷题&#xff01; 题目&#xff1a;找出叠涂元素 题目链接&a…

SD-WAN组网中的CPE及云服务CPE部署方法

什么是CPE&#xff1f; CPE全称为Customer Premises Equipment&#xff0c;即客户端设备&#xff0c;在SD-WAN中通常为路由器&#xff0c;部署在中心点和分支上&#xff0c;提供连接和路由、协议转换、流量监控等功能。一般可分为硬件CPE和虚拟化CPE&#xff08;virtual CPE&a…

python结构数据类型【侯小啾python基础领航计划 系列(六)】

python结构数据类型【侯小啾python领航计划 系列(六)】 大家好,我是博主侯小啾, 🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ�…

关于使用百度开发者平台处理语音朗读问题排查

错误信息&#xff1a;"convert_offline": false, "err_detail": "16: Open api characters limit reach 需要领取完 识别和合成都要有

vscode里面使用vue的一些插件,方便开发

1、vue 2 Snippets &#xff08;vue语法提示&#xff09; vue提示这个也可以 1.1 Vue VSCode Snippets 2、vetur Vetur支持.vue文件的语法高亮显示&#xff0c;除了支持template模板以外 3、Element UI Snippets(饿了么的提示) 4、indent-rainbow&#xff08;缩进高亮提示) 5…

SQL Server 数据库,创建数据表

2.3表的基本概念 表是包含数据库中所有数据的数据库对象。数据在表中的组织方式与在电子表格中相似&#xff0c;都是 按行和列的格式组织的&#xff0c;每行代表一条唯一的记录&#xff0c;每列代表记录中的一个字段.例如&#xff0c;在包含公 司员工信息的表中&#xff0c;每行…

日期类 - Java

知道怎么查&#xff0c;怎么用即可&#xff0c;不用每个方法都背 日期类 第一代日期类方法演示 第二代日期类方法演示 第三代日期类前面两代日期类的不足分析第三代日期类常见方法方法演示 第一代日期类 Date类&#xff1a;精确到毫秒&#xff0c;代表特定的瞬间SimpleDateFor…

Redis缓存——Spring Cache入门学习

Spring Cache 介绍 Spring Cache 是一个框架&#xff0c;实现了基于注解的缓存功能&#xff0c;只需要简单地加一个注解&#xff0c;就能实现缓存功能。 Spring Cache 提供了一层抽象&#xff0c;底层可以切换不同的缓存实现&#xff0c;例如&#xff1a; EHCacheCaffeineR…

程序员世界破破烂烂,低代码总在缝缝补补

在经历了十几年的发展后&#xff0c;前端开发变得越来越复杂&#xff0c;门槛也越来越高&#xff0c;要使用当下流行的 UI 组件库&#xff0c;你必须懂 npm、webpack、react/vue&#xff0c;必须熟悉 ES6 语法&#xff0c;最好还了解状态管理&#xff0c;比如 Redux&#xff0c…

【IPv6】IPv6协议

一、IPv6数据报格式 这是与v4报头的对比 1.8bit的版本保留了&#xff0c;v4版本就是4&#xff0c;v6就是6。 2.v6去除了v4的首部长度字段&#xff0c;因为v6的首部长是固定的40字节。 3.服务类型&#xff08;Type of Service, ToS&#xff09;和通信类型&#xff08;Traffi…