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

项目实际图

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

本次项目需要整合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 ;

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

 根据时序图写操作(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)延时 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 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[STM32F103C8T6]基于LCD和DHT11、HC08的温湿度检测系统并上传服务器_第3张图片

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

[STM32F103C8T6]基于LCD和DHT11、HC08的温湿度检测系统并上传服务器_第5张图片 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);
        else
            HAL_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最高位会置1
		if((UART1_RX_STA & 0x8000) == 0)//如果没有接收完成就进入接收流程
		{
	//如果接收到回车:0X0D
			if(UART1_RX_STA & 0x4000)//出现的问题!!为真不一定是1 
			{
				if(buf == 0x0a)//如果接收到换行
				 //如果换行和回车都收到了就说明接收完成,那么手动将USART_RX_STA最高位置1
				UART1_RX_STA |= 0x8000;
				else
				UART1_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重定向必须勾选[STM32F103C8T6]基于LCD和DHT11、HC08的温湿度检测系统并上传服务器_第6张图片

 

你可能感兴趣的:(stm32,单片机,嵌入式硬件)