STM32实现温湿度数据管理系统

目录

1、实验内容:

2、具体代码

1.Led1602显示屏操作代码

 这里注意#ifndef,#define,#endif的作用和用法

 2.DHt11温湿度传感器操作代码

3.串口文件,重定向printf

4.主函数代码

显示效果 

1、实验内容:

通过HT11温湿传感器模块,检测温度和湿度,通过串口将数据传输到电脑,通过蓝牙无线透穿传输到 手机,通过lcd1602显示出来,然后可以根据温度对舵机的角度进行控制,也可以通过串口控制舵机

对于有模块忘记这么使用的可以去看我之前的文章

SG90舵机:STM32之定时器--PWM控制SG90舵机

lcd1602:C51单片机与LCD1602

DHT11:51单片机与DHT11温湿传感器

2、具体代码

1.Led1602显示屏操作代码

STM32如何将一个字节的数据按位一次性发送到GPIOA8个管脚?

GPIOA -> ODR = cmd ;

 lcd1602.c文件

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

#define RS_GPIO_Port GPIOB
#define RW_GPIO_Port GPIOB
#define EN_GPIO_Port GPIOB
#define RS_Pin  GPIO_PIN_0
#define RW_Pin  GPIO_PIN_1
#define EN_Pin  GPIO_PIN_2
#define RS_HIGH HAL_GPIO_WritePin(RS_GPIO_Port, RS_Pin, GPIO_PIN_SET)
#define RS_LOW  HAL_GPIO_WritePin(RS_GPIO_Port, RS_Pin, GPIO_PIN_RESET)
#define RW_HIGH HAL_GPIO_WritePin(RW_GPIO_Port, RW_Pin, GPIO_PIN_SET)
#define RW_LOW  HAL_GPIO_WritePin(RW_GPIO_Port, RW_Pin, GPIO_PIN_RESET)
#define EN_HIGH HAL_GPIO_WritePin(EN_GPIO_Port, EN_Pin, GPIO_PIN_SET)
#define EN_LOW  HAL_GPIO_WritePin(EN_GPIO_Port, EN_Pin, GPIO_PIN_RESET)

#define Data_0 HIGH HAL_GPIO_ReadPin(CPIOA,GPIO_PIN_0);
#define Data_1 HIGH HAL_GPIO_ReadPin(CPIOA,GPIO_PIN_1);
#define Data_2 HIGH HAL_GPIO_ReadPin(CPIOA,GPIO_PIN_2);
#define Data_3 HIGH HAL_GPIO_ReadPin(CPIOA,GPIO_PIN_3);
#define Data_4 HIGH HAL_GPIO_ReadPin(CPIOA,GPIO_PIN_4); 
#define Data_5 HIGH HAL_GPIO_ReadPin(CPIOA,GPIO_PIN_5);
#define Data_6 HIGH HAL_GPIO_ReadPin(CPIOA,GPIO_PIN_6);
#define Data_7 HIGH HAL_GPIO_ReadPin(CPIOA,GPIO_PIN_7);

//这里如果你的引脚不是连续的你就可以通过按位传输的方式来给lcd显示屏传递你想要显示的数据
//void DHT11_Wdata(uint8_t Data)
//{
//	HAL_GPIO_WritePin(GPIOA,GPIO_PIN_0,Data & 0x00000001);
//	HAL_GPIO_WritePin(GPIOA,GPIO_PIN_1,Data & 0x02);
//	HAL_GPIO_WritePin(GPIOA,GPIO_PIN_2,Data & 0x04);
//	HAL_GPIO_WritePin(GPIOA,GPIO_PIN_3,Data & 0x08);
//	HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,Data & 0x10);
//	HAL_GPIO_WritePin(GPIOA,GPIO_PIN_5,Data & 0x20);
//	HAL_GPIO_WritePin(GPIOA,GPIO_PIN_6,Data & 0x40);
//	HAL_GPIO_WritePin(GPIOA,GPIO_PIN_7,Data & 0x80);
//}

void WriteOrder(char order)//写指令也就是输入字符的位置
{
	//Detection_busy();
	RS_LOW;
	RW_LOW;
	EN_LOW;
	//DHT11_Wdata(order);
	GPIOA->ODR  = order;

	HAL_Delay(1);
	EN_HIGH;

	HAL_Delay(1);	
	EN_LOW;
}

void WriteDate(char date)//写数据
{
	//Detection_busy();
	RS_HIGH;
	RW_LOW;
	EN_LOW;
	//DHT11_Wdata(date);
	GPIOA->ODR  = date;

	HAL_Delay(1);
	EN_HIGH;

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

void LCD1602_showLine(char row, char col, char *string)
{
	switch(row)
	{
		case 1:
		WriteOrder(0x80+col);
		while(*string){
			WriteDate(*string);
			string++;
		}
		break;
		case 2:
		WriteOrder(0x80+0x40+col);
		while(*string){
			WriteDate(*string);
			string++;
		}
	}
}

 lcd1602.h文件

#ifndef __LCD1602_H__
#define __LCD1602_H__
void InitializeLcd1602(void);
void LCD1602_showLine(char row, char col, char *string);
#endif

 这里注意#ifndef,#define,#endif的作用和用法

ifndef/define/endif”主要目的是防止头文件的重复包含和编译

用法:

.h文件,如下:
#ifndef __XX_H__
#define __XX_H__
...
#endif

这样如果有两个地方都包含这个头文件,就不会出现两次包含的情况 

因为在第二次包含时 XX_H 已经有定义了,所以就不再 include了

 2.DHt11温湿度传感器操作代码

dht11.c文件

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

//将GPIO口的操作进行封装
#define DHT_HIGHT HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_SET)
#define DHT_LOW	 HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_RESET)
#define DHT_VALUE HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_6)
//接收传递过来的数据
char datas[5];
void delay_us(uint16_t cnt)
{
	uint8_t i;
	while(cnt)
	{
	for (i = 0; i < 10; i++)
	{
	}
	cnt--;
	}
}
//GPIO的初始化
void DHT11_GPIO_Init(uint32_t mode)
{
/*mode
	GPIO_MODE_INPUT                    
	GPIO_MODE_OUTPUT_PP
	*/
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  __HAL_RCC_GPIOB_CLK_ENABLE();
  GPIO_InitStruct.Pin = GPIO_PIN_6;
  GPIO_InitStruct.Mode = mode;
 // GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
}


//检测信号代码
void DHT11_DSR()
{
	DHT11_GPIO_Init(GPIO_MODE_OUTPUT_PP);
	DHT_HIGHT;
	//HAL_Delay(1);
	DHT_LOW;
	HAL_Delay(30);
	DHT_HIGHT;
	DHT11_GPIO_Init(GPIO_MODE_INPUT);
	while(DHT_VALUE);
	while(!DHT_VALUE);
	while(DHT_VALUE);
}

//读取数据
void DHT11TransferData(void)
{
	int i = 0;
	int j = 0;
	char cmd = 0;
	DHT11_DSR();
	for(i = 0;i<5 ;i++)
	{
		for(j = 0;j<8;j++)
		{
			while(!DHT_VALUE);
			delay_us(40);
			if(DHT_VALUE == 1)
			{
				cmd <<=1;
				cmd |= DHT_VALUE;
				while(DHT_VALUE);
			}else
			{
				cmd <<=1;
				cmd |= DHT_VALUE;
			}
			
		}
		datas[i] = cmd;
	}
}

dht11.h文件

#ifndef __DHT11_H__
#define __DHT11_H__
void DHT11TransferData(void);
#endif

3.串口文件,重定向printf

记得打开Use MicroLIB

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

4.主函数代码

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

//舵机状态控制
#define OFF_1 1
#define OFF_2 2
#define ON_0  0

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

//串口接收缓存(1字节)
uint8_t buf=0;
 
//接收缓冲, 串口接收到的数据放在这个数组里,最大UART1_REC_LEN个字节
uint8_t	UART1_RX_Buffer[UART1_REC_LEN];
// 接收状态
// bit15, 接收完成标志
// bit14, 接收到0x0d
// bit13~0, 接收到的有效字节数目
uint16_t UART1_RX_STA=0;
 
// 接收完成回调函数,收到一个数据后,在这里处理
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)//属于接收数据
{
	// 判断中断是由哪个串口触发的
	if(huart->Instance == USART1 || huart->Instance == USART3){
		// 判断接收是否完成(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((char*)UART1_RX_Buffer,"OPEN_S")){
									__HAL_TIM_SetCompare(&htim4,TIM_CHANNEL_3,25);
							}
							if(!strcmp((char*)UART1_RX_Buffer,"OPEN_W")){
									__HAL_TIM_SetCompare(&htim4,TIM_CHANNEL_3,5);
							}
							if(!strcmp((char*)UART1_RX_Buffer,"CLOSE")){
									__HAL_TIM_SetCompare(&htim4,TIM_CHANNEL_3,15);
							}
							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++;//这里传输一次就会加一,一个可以传输2的13次方个字节
						// 如果接收数据大于UART1_REC_LEN(200字节),则重新开始接收
						if(UART1_RX_STA > UART1_REC_LEN - 1)
						UART1_RX_STA = 0;
						}	
				}
			}
				// 重新开启中断。调用 这个函数的时候会关闭中断,存储完一个数据的时候得重新开启中断
				HAL_UART_Receive_IT(&huart1, &buf, 1);
		}	
}

//main里面

	HAL_NVIC_SetPriority(SysTick_IRQn,0,0);
	//串口
	HAL_UART_Receive_IT(&huart1,&buf,1);
	HAL_UART_Receive_IT(&huart3,&buf,1);
	//PWM
		HAL_TIM_PWM_Start(&htim4,TIM_CHANNEL_3);
	__HAL_TIM_SetCompare(&htim4,TIM_CHANNEL_3,15);
	i = ON_0;
	InitializeLcd1602();
//	LCD1602_showLine(1, 2, "wqaetg");
//	LCD1602_showLine(2, 2, "asdghd");
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
//这里一定要加延时不然温湿传感器会卡住
		HAL_Delay(1000); 
		
		DHT11TransferData();
		//先判断
		if(datas[2]>25){
			if(i != OFF_2){
			__HAL_TIM_SetCompare(&htim4,TIM_CHANNEL_3,5);
				i = OFF_2;
			}
		}
		else if(datas[2]>25 && datas[0] >90 ){
			if(i != OFF_1){
			__HAL_TIM_SetCompare(&htim4,TIM_CHANNEL_3,25);
				i = OFF_1;
			}
		}else{
			if(i != ON_0){
			__HAL_TIM_SetCompare(&htim4,TIM_CHANNEL_3,15);
				i = ON_0;
			}
		}
		//把数据传给蓝牙
		memset(Tdata,'\0',12);
		sprintf(Tdata,"S %d.%d",datas[0],datas[1]);
		HAL_UART_Transmit(&huart3,(uint8_t*)Tdata,sizeof(Tdata),100);
		//把数据在lcd显示
		LCD1602_showLine(1,0,Tdata);
		
		memset(Tdata,'\0',12);
		sprintf(Tdata,"W %d.%d",datas[2],datas[3]);
		HAL_UART_Transmit(&huart3,(uint8_t*)Tdata,sizeof(Tdata),100);
		//把数据在lcd显示
		LCD1602_showLine(2,0,Tdata);
		//把数据传给串口
		printf("湿度:%d.%d\r\n",datas[0],datas[1]);
		printf("温度:%d.%d\r\n",datas[2],datas[3]);

}

显示效果 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值