基于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);
		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连接就可以使用了。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Linux20.04-qt5.12.4软件安装与初步使用-qt在Linux使用-记录-笔记】

【Linux-qt软件安装与初步使用-qt在Linux使用-记录-笔记】 1、概述2、环境说明3、步骤总结1、了解并选择自己想要安装的版本2、访问 Qt 官方网站3、在 Qt 网站上找到下载部分&#xff08;自己想下载&#xff09;4、下载完成后&#xff0c;给安装程序文件赋予执行权限。5、自动配…

单显卡插槽安装英伟达Tesla P4 AI加速卡

Tesla P4是专业AI显卡&#xff0c;只有70瓦功耗&#xff0c;可以作为AI入门使用。 安装时碰到的几个问题&#xff1a; 首先因为单显卡插槽&#xff0c;就需要先安装好机器&#xff0c;然后ssh登录进行相关配置。安装的时候来回插拔了好多次&#xff01; 其次就是安装驱动时&a…

微信聊天记录年度报告

记忆恢复 若运行代码&#xff0c;执行下列命令安装 git clone https://github.com/LC044/WeChatMsg cd WeChatMsg pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple一、登录微信 切记需要先登录要提取的微信号的微信。 手机端使用聊天记录迁移功…

【电路笔记】-电阻器额定功率

电阻器额定功率 文章目录 电阻器额定功率1、概述2、电阻功率&#xff08;P&#xff09;3、功率电阻器4、电阻器额定功率示例15、电阻器额定功率示例2 电能被电阻吸收&#xff0c;因为它是电压和电流的乘积&#xff0c;一些电阻将这种电能转化为热量。 1、概述 当电流由于电阻器…

基础堆溢出原理与DWORD SHOOT实现

堆介绍 堆的数据结构与管理策略 程序员在使用堆时只需要做三件事情&#xff1a;申请一定大小的内存&#xff0c;使用内存&#xff0c;释放内存。 对于堆管理系统来说&#xff0c;响应程序的内存使用申请就意味着要在"杂乱"的堆区中"辨别"出哪些内存是正在…

实用篇 | 利用Flask+Postman为深度学习模型进行快速测试(超详细)

利用FlaskPostman为深度学习模型进行快速测试&#xff0c;以及算法中的一些实例&#xff0c;以后会更新一些新的模板~~ #本文环境&#xff1a;服务器Ubuntu20.04(docker) 目录 1.下载postrman 2.编写flas的app文件 3.在postrman发送请求 4.实例 在服务器创建app.py文件 …

12月2号作业

#include <iostream>using namespace std; class Sofa{ private:string setting;string *lying new string;public:Sofa(){cout << "Sofa::无参构造函数" << endl;}Sofa(string setting,string lying):setting(setting),lying(new string (lying)…

【shell】

shell 一、shell简介二、shell脚本的执行方式三、shell变量3.1 shell变量介绍3.2 shell变量的定义3.1.1 基本语法3.2.2 定义变量的规则3.2.3 将命令的返回值赋予变量 四、环境变量的设置4.1 基本语法&#xff1a; 五、位置参数变量5.1 基本介绍5.2 基本语法 六、预定义变量6.1 …

金蝶云星空表单插件单据体批量删除,序号自增

文章目录 金蝶云星空表单插件单据体批量删除&#xff0c;序号自增字段标识说明表单插件获取单据体数据包移除物料为空的行其他移除物料为空的行的方式&#xff0c;但是测试不通过&#xff0c;不建议使用序号重新生成测试 金蝶云星空表单插件单据体批量删除&#xff0c;序号自增…

新的 BLUFFS 攻击导致蓝牙连接不再私密

蓝牙是一种连接我们设备的低功耗无线技术&#xff0c;有一个新的漏洞需要解决。 中间的攻击者可以使用新的 BLUFFS 攻击轻松窥探您的通信。 法国研究中心 EURECOM 的研究员 Daniele Antonioli 演示了六种新颖的攻击&#xff0c;这些攻击被定义为 BLUFFS&#xff08;蓝牙转发和…

合并两个有序链表[简单]

优质博文&#xff1a;IT-BLOG-CN 一、题目 将两个升序链表合并为一个新的升序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 示例 1&#xff1a; 输入&#xff1a;l1 [1,2,4], l2 [1,3,4] 输出&#xff1a;[1,1,2,3,4,4] 示例 2&#xff1a; 输入&#…

java常用知识点记忆

类的继承与多态 类的继承不支持多重继承非private 方法才可以被覆盖覆盖的方法要求&#xff0c;子类中的方法的名字&#xff0c;参数列表&#xff0c;返回类型与父类相同方法的重载是在一个类中定义方法名字相同&#xff0c;但是参数列表不同的方法要是在子类中定义了与父类名字…

IDEA 下载mysql驱动下载在不下来

结合一下 https://www.cnblogs.com/dadian/p/11936056.htmlhttps://www.cnblogs.com/dadian/p/11936056.html并且下载的 在idea改名 加入 加入到库 等待一会就要你输入sql的root和密码了,就OK

深入理解强化学习——马尔可夫决策过程:蒙特卡洛方法-[基础知识]

分类目录&#xff1a;《深入理解强化学习》总目录 蒙特卡洛方法&#xff08;Monte-Carlo Methods&#xff09;也被称为统计模拟方法&#xff0c;是一种基于概率统计的数值计算方法。运用蒙特卡洛方法时&#xff0c;我们通常使用重复随机抽样&#xff0c;然后运用概率统计方法来…

整数的立方和

系列文章目录 进阶的卡莎C++_睡觉觉觉得的博客-CSDN博客数1的个数_睡觉觉觉得的博客-CSDN博客双精度浮点数的输入输出_睡觉觉觉得的博客-CSDN博客足球联赛积分_睡觉觉觉得的博客-CSDN博客大减价(一级)_睡觉觉觉得的博客-CSDN博客小写字母的判断_睡觉觉觉得的博客-CSDN博客纸币(…

在线直线度测量仪在圆形轧钢中的重要性

在线直线度测量仪在圆形轧钢中的重要性 在现代轧钢生产中&#xff0c;在线直线度测量仪是一种非常重要的工具&#xff0c;它可以帮助工人和产线进行高精度的直线度和直径测量&#xff0c;从而保证产品质量的稳定性和精度。以下是详细介绍直线度测量仪的重要性和应用。 一、测…

【Java基础】几种拼接字符串的方法

几种拼接字符串的方法 1.使用 "" 运算符拼接字符串2.使用 StringBuilder 或 StringBuffer 类3.使用 StringJoiner 类4.使用 String 类 join 方法5.使用 StringUtils 类6.使用 String 类 concat 方法7.使用 String.format() 方法格式化字符串8.使用 Stream 实现9.总结…

http代理如何设置手机上网?http代理起到了哪些作用

本文将详细介绍如何设置手机上网使用HTTP代理&#xff0c;以及HTTP代理所起到的作用。 一、HTTP代理是什么&#xff1f; HTTP代理是一种网络协议&#xff0c;它允许客户端与服务器之间进行数据传输。它是一种常用的代理服务&#xff0c;可以帮助用户通过HTTP协议访问被封锁的网…

蓝桥杯物联网竞赛_STM32L071_10_温度传感器扩展模块

原理图&#xff1a; 温度传感器原理图&#xff1a; 其中芯片可以通过SCL和SDA引脚通过I2C通信向温度传感器指定地址获取温度的模拟量 再利用公式将模拟量转换成相应温度即可 实验板接口原理图&#xff1a; 模拟量转相应温度公式&#xff1a; CubMx配置&#xff1a; Keil配置&…

手把手教你做基于stm32的红外、语音、按键智能灯光控制(上)

目录&#xff1a; 1.系统实现目标2.硬件选型和软件准备2.1. 硬件选型2.2 软件准备 3. 硬件IO表4.各个模块的驱动函数4.1. 红外遥控模块4.2. 按键模块4.3. LED灯4.4. BH1750光照度传感器4.5. 红外检测模块 1.系统实现目标 本文所设计的基于单片机的灯光控制系统主要由模式选择功…