> 文章列表 > [STM32F103C8T6]基于LCD和DHT11、HC08的温湿度检测系统并上传服务器

[STM32F103C8T6]基于LCD和DHT11、HC08的温湿度检测系统并上传服务器

[STM32F103C8T6]基于LCD和DHT11、HC08的温湿度检测系统并上传服务器

项目实际图

本次项目需要整合LCD1602、DHT11、HC08、继电器

1.首先是LCD1602显示程序

封装管脚,这样的话写时序的时候不用随时都在哪儿HAL_GPIO_WritePin

#define RS_GPIO_Port GPIOB
#define RW_GPIO_Port GPIOB
#define EN_GPIO_Port GPIOB
#define RS_Pin GPIO_PIN_1
#define RW_Pin GPIO_PIN_2
#define EN_Pin GPIO_PIN_10
#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)

 STM32不同于51,STM32的管脚比如PA0-PA7不能以此向直接写入一个字节的数据,必须操作寄存器

GPIOA->ODR = cmd;

 根据时序图写操作(stm32可以不检查忙)

LCD.c

#define RS_GPIO_Port GPIOB
#define RW_GPIO_Port GPIOB
#define EN_GPIO_Port GPIOB
#define RS_Pin GPIO_PIN_1
#define RW_Pin GPIO_PIN_2
#define EN_Pin GPIO_PIN_10
#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)void Write_Cmd_Func(uint8_t cmd)
{RS_LOW;RW_LOW;EN_LOW;GPIOA->ODR = cmd;EN_HIGH;HAL_Delay(5);EN_LOW;HAL_Delay(5);
}void Write_Data_Func(uint8_t dataShow)
{RS_LOW;RW_LOW;EN_LOW;GPIOA->ODR = dataShow;EN_HIGH;HAL_Delay(5);EN_LOW;HAL_Delay(5);
}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 0:Write_Cmd_Func(0x80+0x00+col);while(*string != '\\0'){Write_Data_Func(*string++);}break;case 1:Write_Cmd_Func(0x80+0x40+col);while(*string != '\\0'){Write_Data_Func(*string++);}break;   }}

2.DHT11温湿度检测程序

具体关于DHT11的硬件结构以及说明可以查看51章节的文章

https://blog.csdn.net/weixin_63303786/article/details/128692300?spm=1001.2014.3001.5502https://blog.csdn.net/weixin_63303786/article/details/128692300?spm=1001.2014.3001.5502

 IO口的几种输入输出状态

 GPIO_MODE_INPUT 输入

 GPIO_MODE_OUTPUT_PP 推挽输出

 GPIO_MODE_OUTPUT_OD 开漏输出

 GPIO_Mode_AF_OD 复用开漏输出模式

 GPIO_Mode_AF_PP 复用推挽输出模式

 GPIO_MODE_AF_INPUT 模拟输入(AD用)

1. 四种输入模式

    GPIO_Mode_IN_FLOATING 浮空输入模式
    GPIO_Mode_IPU 上拉输入模式
    GPIO_Mode_IPD 下拉输入模式
    GPIO_Mode_AIN 模拟输入模式

2. 四种输出模式

    GPIO_Mode_Out_OD 开漏输出模式
    GPIO_Mode_Out_PP 推挽输出模式
    GPIO_Mode_AF_OD 复用开漏输出模式
    GPIO_Mode_AF_PP 复用推挽输出模式

根据时序图写出DHT11的读操作

DHT11.c

//首先检查DHT11是否存在,时序图黑色部分需要我们写程序实现,棕色部分则是读IO口实现
//所以DHT11所用IO口有两种状态:输入和输出,所以cubeMX中不配置IO口状态,用程序配置/*封装引脚*/
#define DHT_HIGHT 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)unsigned char datas[5]={0};//接收温湿度数据的数组//可以现在cubeMX中随意配置一个管脚如PA1,然后去工程里找到GPIO初始化程序,模仿写出DHT_GPIO_Init
void DHT_GPIO_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);
}//根据时序图写出strat(检查DHT11是否存在),读温度
void delay_us(uint16_t cnt)
{uint8_t i;while(cnt){for (i = 0; i < 10; i++){}cnt--;}}void DHT11_Start()
{DHT_GPIO_Init((GPIO_MODE_OUTPUT_PP);//推挽输出DHT_LOW;HAL_Delay(20);DHT_HIGHT;DHT_GPIO_Init(GPIO_MODE_INPUT);while(DHT_VALUE);//卡d点while(!DHT_VALUE);//卡e点while(DHT_VALUE);//卡f点
}void Read_Data_From_DHT()
{unsigned char flag,temp,i=0,j=0;DHT11_Start();DHT_GPIO_Init(GPIO_MODE_INPUT);while(!DHT_VALUE);//卡g点,因为判断读0还是读1的时序图是IO口自己实现,不需要写程序拉低或者释放delay_us(40);for(i=0;i<5;i++)//总共接收5个数据,第0,第1是湿度的整数和小数,第2,第3是温度的整数和小数,第4是校验位{for(=0;j<8;j++)//一个数据八位,每次接收一位,接收八次{if(DHT_VALUE == 1)flag = 1;else if(DHT_VALUE == 0)flag = 0;temp <<= 1;temp |= flag;//如果读0,最低位则为0(因为出初始化temp = 0000 0000),如果读1,则最低位为1,8次左移过后原本的最低位成最高位}  datas[i] = temp; }
}

总和LCD1602和DHT11代码完成项目要求

main.c

extern buf;//重定向printf
int fputc(int ch,FILE*f)
{unsigned char temp[1] = {ch};HAL_UART_Transmit(&huart1,temp,strlen(temp),0xffff);return ch;
}void main()
{unsigned char mssage[10];while(1){HAL_UART_Receive_IT(&huart1, &buf, 1)//开启串口中断Read_Data_From_DHT();if(datas[1] >= 30)//如果温度超过30度,继电器闭合HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_RESET);elseHAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,GPIO_PIN_SET);memset(message, 0, sizeof(message));sprintf(mssage,"T:%d.%d",(unsigned int)datas[2],(unsigned int)datas[3]);LCD1602_showLine(1,0,message);memset(message, 0, sizeof(message));sprintf(mssage,"H:%d.%d",(unsigned int)datas[0],(unsigned int)datas[1]);LCD1602_showLine(2,0,message);printf("T:%d.%d",(unsigned int)datas[2],(unsigned int)datas[3]);printf("H:%d.%d",(unsigned int)datas[0],(unsigned int)datas[1]);HAL_Delay(100);}
}

uart.c

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;//串口接收标志位
//重写串口回调函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{//判断是不是串口1产生的中断if(huart->Instance == USART1){//判断中断是否接收完成,接收完成USART_RX_STA最高位会置1if((UART1_RX_STA & 0x8000) == 0)//如果没有接收完成就进入接收流程{//如果接收到回车:0X0Dif(UART1_RX_STA & 0x4000)//出现的问题!!为真不一定是1 {if(buf == 0x0a)//如果接收到换行//如果换行和回车都收到了就说明接收完成,那么手动将USART_RX_STA最高位置1UART1_RX_STA |= 0x8000;elseUART1_RX_STA = 0;	//如果没有收到换行就置0重新来过}else//如果没有收到回车{//先判断这个字符是不是回车if(buf == 0x0d){UART1_RX_STA |= 0x4000;//如果是回车,就手动将bit14置1// 继电器控制指令if(!strcmp((uint8_t *)UART1_RX_Buffer, "L-1"))HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_RESET);if(!strcmp((uint8_t *)UART1_RX_Buffer, "L-0"))HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_SET);memset(UART1_RX_Buffer, 0, UART1_REC_LEN);UART1_RX_STA = 0;}else{UART1_RX_Buffer[UART1_RX_STA & 0x3fff] = buf;UART1_RX_STA++;if(UART1_RX_STA > UART1_REC_LEN - 1)//如果光标到最后一位那么就光标返回,200-1是因为字符数组最后一位是'\\0'{UART1_RX_STA = 0;}}	} }		HAL_UART_Receive_IT(&huart1, &buf, 1);//重新开启中断接收}
}

HC08只需要连接一个IO口,然后手机连接蓝牙,就可以通过手机端app发送接收指令,蓝牙传输就是串口传输

注意:

1.HC08的波特率是9600,工程的波特率记得改为9600

2.printf重定向必须勾选