温湿度LCD显示并上传服务器

news2024/10/5 13:40:46

项目需求

通过温湿度传感器将值传到LCD1602,并实时通过蓝牙透传到手机。

硬件介绍

温湿度传感器 DHT11温湿度传感器 DHT11_温湿度传感器数据格式-CSDN博客

LCD1602LCD1602-CSDN博客

HC-01

继电器模块

硬件接线

LCD1602
  • D0~D7 --> A0~A7
  • VDD, A --> 5v
  • VSS, VO, K --> GND
  • RS --> B1
  • RW --> B2
  • E --> B10
DHT11
  • VCC --> 5v
  • GND --> GND
  • DATA --> B7
HC-01(也可不接,和电脑串口显示一样的,透传模式)
  • VCC --> 5v
  • GND --> GND
  • RXD --> TX1
  • TXD --> RX1

 各个硬件在先前学习了,就不再一一讲述,此项目仅做代码的移植

 CubeMX

1.常规配置

SYS->Debug->Serial Wire

RCC->High Speed Clock(HSE)->Crystal/Ceramic Resonator

时钟树HSE、PLLCLK打开,HCLK设置成72MHz

打开GPIO口

打开uart1

框内的是在CubeMx重定义的引脚名称,会在mian.h中显示

其中,DHT11的DATA线既作为输入也作为输出,因此不能在CubeMX中进行配置!

为了方便阅读与编写,可在main.h文件重定义引脚

2.时钟

由于hal_delay()只是ms级别的延时,而DHT11中需要us的延时,则需要重新写延时函数,这里我们可以使用软件延时或者硬件延时

软件延时 
void delay_us(uint16_t cnt)
{
	uint8_t i;
	while(cnt)
	{
		for (i = 0; i < 10; i++)
		{
			
		}
		cnt--;
	}
}
硬件延时:打开定时器

计数一次经过的时间是 (PSC + 1) / Tclk , 因此如果我想要计数1微秒,即0.000001s, 已知Tclk = 72 000 000, 那么PSC就应该设置为 71。然后在main.c中就可以定义出一个实现微秒级延时的函数: 

STM32的HAL库开发各函数意义、笔记_hal_tim_set_counter-CSDN博客

void TIM1_Delay_us(uint16_t n_us) //使用TIM1来做us级延时函数  一个基于STM32 HAL库的TIM1(定时器1)进行微秒级延时的功能。
{
/* 使能定时器1计数 */
	__HAL_TIM_ENABLE(&htim1);
	__HAL_TIM_SetCounter(&htim1, 0);
	while(__HAL_TIM_GetCounter(&htim1) < ((1 * n_us)-1) );
/* 关闭定时器1计数 */
	__HAL_TIM_DISABLE(&htim1);
}

 3.生成代码

keil

1. 打开MICRO-LIB

2. 编写代码:

 关于上面提到的DHT的DATA引脚,由于有时需要作为输入,有时需要输出,所以不能在Cube中进行定义,而是在Keil中自己写代码定义,可以直接参考main函数中main.c的MX_GPIO_Init()函数,经过跳转可以看到详细信息:

如图,需要:

  • 定义一个结构体
  • 使能时钟
  • 赋初值(这步可省略)
  • 对于结构体的成员变量进行赋值,分别是GPIO_InitStruct.Pin; GPIO_InitStruct.Mode; 
  • GPIO_InitStruct.Speed,其中GPIO_InitStruct.Mode就是需要根据情况修改的
  • 调用HAL_GPIO_Init 函数
    void DHT11_Init(uint32_t Mode)
    {
    	GPIO_InitTypeDef GPIO_InitStruct = {0};
    	__HAL_RCC_GPIOB_CLK_ENABLE();
    	GPIO_InitStruct.Pin = GPIO_PIN_7;
    	GPIO_InitStruct.Mode = Mode;
    	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    	HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
    
    }
    
    

    然后,

    就可以在需要往DATA写数据的时候写:DHT_GPIO_Init(GPIO_MODE_OUTPUT_PP);

    在需要从DATA读数据的时候写:DHT_GPIO_Init(GPIO_MODE_INPUT);

并且,由于89C52和STM32的硬件差别,使用STM32来驱动LCD1602时,是不需要检测BUSY信号的!!!

但是32驱动LCD的时候,在写命令或内容时,需要用到us级的延时,故要重新编写延时函数

 分文件编写,要将相应的.c.h文件分别添加到incsrc文件中,在新添加的文件在CubeMx重新更改的配置重新生成的文件并不会消失。

main.h

#define RS_GPIO_Pin GPIO_PIN_1
#define RS_GPIO_GPIO_Port GPIOB
#define RW_GPIO_Pin GPIO_PIN_2
#define RW_GPIO_GPIO_Port GPIOB
#define EN_GPIO_Pin GPIO_PIN_10
#define EN_GPIO_GPIO_Port GPIOB

/* USER CODE BEGIN Private defines */
#define DHT_11_GPIO GPIOB
#define DHT_11_PIN GPIO_PIN_7

#define DHT_11_LOW  HAL_GPIO_WritePin(DHT_11_GPIO,DHT_11_PIN,GPIO_PIN_RESET)
#define DHT_11_HIGH HAL_GPIO_WritePin(DHT_11_GPIO,DHT_11_PIN,GPIO_PIN_SET)
#define DHT_11_VALUE HAL_GPIO_ReadPin(DHT_11_GPIO,DHT_11_PIN)

#define RS_HIGH HAL_GPIO_WritePin(RS_GPIO_GPIO_Port,RS_GPIO_Pin,GPIO_PIN_SET)
#define RS_LOW  HAL_GPIO_WritePin(RS_GPIO_GPIO_Port,RS_GPIO_Pin,GPIO_PIN_RESET)
#define RW_HIGH HAL_GPIO_WritePin(RW_GPIO_GPIO_Port,RW_GPIO_Pin,GPIO_PIN_SET)
#define RW_LOW  HAL_GPIO_WritePin(RW_GPIO_GPIO_Port,RW_GPIO_Pin,GPIO_PIN_RESET)
#define EN_HIGH HAL_GPIO_WritePin(EN_GPIO_GPIO_Port,EN_GPIO_Pin,GPIO_PIN_SET)
#define EN_LOW  HAL_GPIO_WritePin(EN_GPIO_GPIO_Port,EN_GPIO_Pin,GPIO_PIN_RESET)

main.c

#include "stdio.h"
#include "lcd1602.h"
#include "dht11.h"

extern char datas[5];
char temperature[9];
char humidity[9];

void Build_datas()
{
	humidity[0] = 'H';
	humidity[1] = ':';
	humidity[2] = datas[0]/10 + 0x30;
	humidity[3] = datas[0]%10 + 0x30;
	humidity[4] = '.';
	humidity[5] = datas[1]/10 + 0x30;
	humidity[6] = datas[1]%10 + 0x30;
	humidity[7] = '%';
	humidity[8] = '\0';
	
	temperature[0] = 'T';
	temperature[1] = ':';
	temperature[2] = datas[2]/10 + 0x30;
	temperature[3] = datas[2]%10 + 0x30;
	temperature[4] = '.';
	temperature[5] = datas[3]/10 + 0x30;
	temperature[6] = datas[3]%10 + 0x30;
	temperature[7] = 'C';
	temperature[8] = '\0';
}


int fputc(int a, FILE *f) //一个字符一个字符发送
{
	unsigned char temp[1] = {a};
	HAL_UART_Transmit(&huart1, temp, 1, 0xffff);
	return a;
}



	printf("code hhh\r\n");
	LCD1602_Init();
 
	LCD1602_ShowLine(1,5,"shion");
	LCD1602_ShowLine(2,5,"114514");
	HAL_Delay(2000);

  while (1)
  {
		Read_data_From_DHT();
		printf("Temp ; %d,%d\t",datas[2],datas[3]);
		printf("Humi ; %d,%d\r\n",datas[0],datas[1]);
		
		Build_datas();
		printf("%s\t",humidity);
		printf("%s",temperature);
		
		LCD1602_ShowLine(1,2,humidity);
		LCD1602_ShowLine(2,2,temperature);
		HAL_Delay(1000);
  }

}

 LCD1602.h

#ifndef __LCD1602_H
#define __LCD1602_H


void Write_cmd_Func(char cmd);//写入指令的函数


void Write_data_Func(char dataShow);//写入数据的函数

void LCD1602_Init(void);

void LCD1602_ShowLine(char row,char col,char *string);


#endif

LCD1602.c

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

void Write_cmd_Func(char cmd)//写入指令的函数
{
	
	RS_LOW;//写指令
	RW_LOW;
	EN_LOW;
	HAL_Delay(5);
	GPIOA->ODR = cmd;
	EN_HIGH;
	HAL_Delay(5);
	EN_LOW;
}

void Write_data_Func(char dataShow)//写入数据的函数
{
	RS_HIGH;//写内容
	RW_LOW;
	EN_LOW;
	HAL_Delay(5);
	GPIOA->ODR = dataShow;
	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;	
		}
	/*
		char pos;
	
	if(hang == 0){//如果第一行
			pos = 0x80 + 0x00 + lie; 
		}else if(hang == 1){//如果第二行
			pos = 0x80 + 0x40 + lie;
		}
		Check_Busy();
		Write_data_Func(*string);
	
	while(*string != '\0'){
		Check_Busy();
		Write_data_Func(*string);
		string++;
	}
		*/
}

 DHT11.h

#ifndef __DHT11_H
#define __DHT11_H

void Read_data_From_DHT();

#endif

 dht11.c

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


uint8_t datas[5];


void delay_us(uint16_t cnt)
{
	uint8_t i;
	while(cnt)
	{
		for (i = 0; i < 10; i++)
		{
			
		}
		cnt--;
	}
}

void DHT11_Init(uint32_t Mode)
{
	GPIO_InitTypeDef GPIO_InitStruct = {0};
	__HAL_RCC_GPIOB_CLK_ENABLE();
	GPIO_InitStruct.Pin = GPIO_PIN_7;
	GPIO_InitStruct.Mode = Mode;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
	HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

}


void DHT_Start()
{
	DHT11_Init(GPIO_MODE_OUTPUT_PP);//设置为输出模式!!

	DHT_11_HIGH;
	DHT_11_LOW;
	
	HAL_Delay(30);
	
	DHT_11_HIGH;
	
	DHT11_Init(GPIO_MODE_INPUT);//设置为输入模式!!
	while(DHT_11_VALUE == 1);//不断读取直到DHT再次变低,跳出循环,说明模块响应
	while(DHT_11_VALUE == 0);//不断读取直到DHT再次拉高,80us之后,再经过50us后DHT变成低电平,就代表要开始变高并开始传输数据了
	while(DHT_11_VALUE == 1);//等待数据传输,不断读取直到DHT再次变低,如退出循环说明数据传输前的50us低电平开始了
    
	
}

void Read_data_From_DHT()
{
	int i;//轮
	int j;//每一轮读多少次
	char temp;
	char flag;
	
	DHT_Start();

	
	for(i = 0;i < 5;  i++)
	{//5组数据
		for(j =0;j<8;j++)
		{//每组数据8位
			while(!DHT_11_VALUE);//等待上拉  dht = 1 退出循环
			delay_us(40);//高电平持续26-28us是‘0’,高电平持续70us是'1',所以delay40us之后观察还是否是高电平
			if(DHT_11_VALUE == 1)
			{
				flag = 1;
				while(DHT_11_VALUE);//不断读取下拉的一瞬间,因为在开始传输数据之前要延迟80us,如果提前结束,下一次开始传输数据就会出错,因为“开始传输数据”是从判断上拉开始的

			}
			else
			{
				flag = 0;
			}
			temp =  temp << 1;//temp左移一位,例如temp= 10101011  左移之后变成-》01010110(第一个数移出去,最后一位补零)
			temp |= flag;//假如flag=1,temp=01010111
		}
		datas[i] = temp;
	}
	
}

 效果显示

 

 

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

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

相关文章

Java基础教程(3)-Java变量和数组

变量&#xff1a; 变量是Java程序的一个基本存储单元。变量由一个标识符&#xff0c;类型及一个可选初始值的组合定义。此外&#xff0c;所有的变量都有一个作用域&#xff0c;定义变量的可见性&#xff0c;生存期。 定义一个变量 定义一个整型变量num: int num 10; num是标…

解决“ImportError: DLL load failed while importing _rust: 找不到指定的程序的问题

运行 scrapy startproject wikiSpider 报错&#xff1a;ImportError: DLL load failed while importing _rust: 找不到指定的程序。 经过尝试 可以更换Python解释器版本来解决 1、点击crtlalts打开设置 点击项目>解释器 选择3.11解释器 &#xff08;我原来报错用的3.9的解…

AI大模型日报#0421:「个性化」图像Gen4Gen框架、吴恩达亲授智能体设计模式、国内14大LLM最新评测报告

导读&#xff1a; 欢迎阅读《AI大模型日报》&#xff0c;内容基于Python爬虫和LLM自动生成。目前采用“文心一言”生成了每条资讯的摘要。 标题: 小冰徐元春&#xff1a;AIGC已经让普通人开始赚钱 | 中国AIGC产业峰会 摘要: 要点提炼&#xff1a; 在中国AIGC产业峰会上&…

冷却塔的选型方法介绍

冷却塔形式冷却塔形式冷却塔形式 冷却塔有开式冷却塔、闭式冷却塔 闭式冷却塔与开式冷却塔的区别 1)开式冷却塔的冷却原理就是&#xff0c;通过将循环水以喷雾方式&#xff0c;喷淋到玻璃纤维的填料上&#xff0c;通过水与空气的接触&#xff0c;达到换热&#xff0c;再有风机…

【001_音频开发-基础篇-专业术语】

001_音频开发-基础篇-专业术语 文章目录 001_音频开发-基础篇-专业术语创作背景术语表常见音源HDMI相关声音系统立体声2.1 声音系统5.1 环绕声系统5.1.2 环绕声系统7.1 环绕声系统7.1.4 环绕声系统9.1.4 环绕声系统 音质等级定义QQ音乐网易云音乐 创作背景 学历代表过去、能力…

【论文笔记】RS-Mamba for Large Remote Sensing Image Dense Prediction(附Code)

论文作者提出了RS-Mamba(RSM)用于高分辨率遥感图像遥感的密集预测任务。RSM设计用于模拟具有线性复杂性的遥感图像的全局特征&#xff0c;使其能够有效地处理大型VHR图像。它采用全向选择性扫描模块&#xff0c;从多个方向对图像进行全局建模&#xff0c;从多个方向捕捉大的空间…

PyTorch深度学习入门到精通指南AI写作一键生成

首先&#xff0c;这篇文章是基于笔尖AI写作进行文章创作的&#xff0c;喜欢的宝子&#xff0c;也可以去体验下&#xff0c;解放双手&#xff0c;上班直接摸鱼~ 按照惯例&#xff0c;先介绍下这款笔尖AI写作&#xff0c;宝子也可以直接下滑跳过看正文~ 笔尖Ai写作&#xff1a;…

虚拟机VMware安装与Ubuntu

1.虚拟机安装 链接&#xff1a;百度网盘 请输入提取码 提取码&#xff1a;2fr6 CG54H-D8D0H-H8DHY-C6X7X-N2KG6 2.Ubuntu下载 Download Ubuntu Desktop | Ubuntu 3.设置 如后续要下一些软件越大越好

关于Jetson空间不足的解决问题(sd卡挂载和conda更改环境安装路径)

文章目录 问题描述挂载sd卡到指定目录查看conda路径更改环境路径指定路径安装conda虚拟环境 问题描述 因为在做毕设的时候&#xff0c;用到了Jetson&#xff0c;发现这个空间太小了&#xff0c;如果下conda的包根本不够用&#xff0c;所以就想挂载sd卡&#xff0c;然后把环境安…

cesium sampleHeightMostDetailed 取高度

//通过经纬度异步拾取模型的高度&#xff0c;当模型还没下载&#xff0c;并不在屏幕范围内时&#xff0c;先下载模型&#xff0c;再拾取高度let c3 Cesium.Cartesian3.fromDegrees(120.134766, 30.188376, 0);let position Cesium.Cartographic.fromCartesian(c3);let promis…

spring版本介绍

Spring Framework 是一个广泛使用的 Java 平台&#xff0c;用于构建企业级应用程序。它提供了一个全面的编程和配置模型&#xff0c;支持现代 Java 应用程序的最佳实践&#xff0c;如依赖注入、面向切面编程以及基于注解的编程模型。自从 Spring 1.0 发布以来&#xff0c;已经经…

构建代理IP池并自动测试可用性的爬虫实现

目录 前言 一、认识代理IP 1. 隐藏真实IP地址 2. 提高爬虫效率 二、爬取代理IP 三、测试代理IP可用性 1. 发起HTTP请求 2. 超时检测 3. 循环请求 四、构建代理IP池 五、总结 前言 随着互联网的发展&#xff0c;网络爬虫在数据采集、搜索引擎、信息监控等领域发挥着…

Electron+Vue3整合-开发时整合-全部ts开发 + 一条命令启动vue3和electron两个服务

说明 本文介绍一下 Electron Vue3 的整合的中级操作。实现的效果是 &#xff1a; 1、一个正常的Vue3项目&#xff1b; 2、整合加入 Electron 框架 &#xff1a;开发时只执行一条命令&#xff0c;启动 vue 项目 后 再启动 electron&#xff1b;electron 的开发使用 typescript…

经典机器学习算法——决策树

优质博文&#xff1a;IT-BLOG-CN 树模型是机器学习中最常用的一类模型&#xff0c;包括随机森林、AdaBoost、GBDT&#xff08;XGBoost和Lightgbm&#xff09;等&#xff0c;基本原理都是通过集成弱学习器的即式来进一步提升准确度。这里的弱学习器包括线性模型和决策树模型&…

DC30V36V60V100V转9V、12V/1.5A方案 车灯驱动芯片IC H5028L ,高性价比,皮实耐抗

DC24V、30V、36V、60V、100V转9V、12V/1.5A方案&#xff0c;以及车灯驱动芯片IC&#xff0c;这通常涉及到电源转换和驱动电路的设计。这些方案的目标是将一个较高的直流电压&#xff08;如24V、30V、36V、60V或100V&#xff09;转换为较低但稳定的直流电压&#xff08;如9V或12…

EigenLayer生态全解析:再质押与AVS崛起的序章

基于以太坊网络的再质押协议EigenLayer提出了利用为以太坊网络验证而质押的ETH来与其他协议共享安全性和资本效率&#xff0c;同时为协议参与者提供额外利息。在AVS、再质押、积分系统等概念的推动下&#xff0c;逐渐形成一个庞大的生态系统&#xff0c;从2024年初到现在EigenL…

[前端]NVM管理器安装、nodejs、npm、yarn配置

NVM管理器安装、nodejs、npm、yarn配置 NVM管理器安装 nvm(Node.js version manager) 是一个命令行应用&#xff0c;可以协助您快速地 更新、安装、使用、卸载 本机的全局 node.js 版本。 nvm下载地址&#xff1a;https://github.com/coreybutler/nvm-windows/releases 1.全部…

分类预测 | Matlab实现CNN-LSTM-SAM-Attention卷积长短期记忆神经网络融合空间注意力机制的数据分类预测

分类预测 | Matlab实现CNN-LSTM-SAM-Attention卷积长短期记忆神经网络融合空间注意力机制的数据分类预测 目录 分类预测 | Matlab实现CNN-LSTM-SAM-Attention卷积长短期记忆神经网络融合空间注意力机制的数据分类预测分类效果基本描述程序设计参考资料 分类效果 基本描述 1.Mat…

模电期末复习(四)功率放大电路

功率放大电路 4.1 功率放大电路的主要特点4.1.1 对放大电路的要求4.1.2 放大电路中三极管的工作状态4.1.3 放大电路的分析方法 4.2 互补对称式功率放大电路4.2.1 电路的组成和工作原理4.2.2 互补对称电路主要参数的估算 4.3 采用复合管的互补对称式放大电路4.3.1 复合管的接法及…

【计算机毕业设计】理发店管理系统产品功能说明——后附源码

&#x1f389;**欢迎来到我的技术世界&#xff01;**&#x1f389; &#x1f4d8; 博主小档案&#xff1a; 一名来自世界500强的资深程序媛&#xff0c;毕业于国内知名985高校。 &#x1f527; 技术专长&#xff1a; 在深度学习任务中展现出卓越的能力&#xff0c;包括但不限于…