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

项目需求

通过温湿度传感器将值传到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;
	}
	
}

 效果显示

 

 

  • 15
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值