基于STM32的homeassistant(采用FreeRTOS操作系统)【第二章:采集DHT11数据上传服务器;接收服务器指令执行对应操作】

第一章链接

第二章开发环境

主控 STM32F103C8T6
WIFI模块 ESP01S
传感器模块 DHT11温湿度传感器、LED灯
开发语言 C
开发编译器 KEIL
组网方式 WIFI
服务器协议 MQTT

本章要点

  • 根据DHT11工作特性编写触发代码
  • AT指令订阅服务器端口
  • STM32中断接收挂起Usart协议信息标志位
  • STM23任务过滤识别服务器发送的操作指令并执行

抽象理解

1、根据DHT11工作特性编写触发代码

DHT11采用单总线协议(DHT11-V1.3说明书(详细版).cdr (aosong.com)

数据格式: 8bit湿度整数数据+8bit湿度小数数据+8bit温度整数数据+8bit温度小数数据+8bit校验位

//主机发送开始信号
void DHT11_Start(void)
{
	DH11_GPIO_Init_OUT(); //输出模式
	
	dht11_high; //先拉高
	delay_us(30);
	
	dht11_low; //拉低电平至少18us,最高不能超过30us
	delay_us(20);
	
	dht11_high; //拉高电平20~40us
	delay_us(30);
	
	DH11_GPIO_Init_IN(); //输入模式
}
//获取一个字节
char DHT11_Rec_Byte(void)
{
	unsigned char i = 0;
	unsigned char data;
	
	for(i=0;i<8;i++) //1个数据就是1个字节byte,1个字节byte有8位bit
	{
		while( Read_Data == 0); //从1bit开始,低电平变高电平,等待低电平结束
		delay_us(30); //延迟30us是为了区别数据0和数据1,0只有26~28us
		
		data <<= 1; //左移
		if( Read_Data == 1 ) //如果过了30us还是高电平的话就是数据1
		{
			data |= 1; //数据+1
		}
		
		while( Read_Data == 1 ); //高电平变低电平,等待高电平结束
	}
	
	return data;
}

//获取数据

void DHT11_REC_Data(void)
{

	unsigned int R_H,R_L,T_H,T_L;
	unsigned char RH,RL,TH,TL,CHECK;

	DHT11_Start(); //主机发送信号
	dht11_high; //拉高电平
	if( Read_Data == 0 ) //判断DHT11是否响应
	{	
		while( Read_Data == 0); //低电平变高电平,等待低电平结束(83ms)
		while( Read_Data == 1); //高电平变低电平,等待高电平结束(87ms)
		R_H = DHT11_Rec_Byte();
		R_L = DHT11_Rec_Byte();
		T_H = DHT11_Rec_Byte();
		T_L = DHT11_Rec_Byte();
		CHECK = DHT11_Rec_Byte(); //接收5个数据
		dht11_low; //当最后一bit数据传送完毕后,DHT11拉低总线 50us,以此重置为输入模式
		delay_us(55); //这里延时55us
		dht11_high; //随后总线由上拉电阻拉高进入空闲状态。
		
		if(R_H + R_L + T_H + T_L == CHECK) //和检验位对比,判断校验接收到的数据是否正确
		{
			RH = R_H;
			RL = R_L;
			TH = T_H;
			TL = T_L;
		}
	}
	rec_data[0] = RH;
	rec_data[1] = RL;
	rec_data[2] = TH;
	rec_data[3] = TL;
}

二、AT指令订阅服务器端口

AT详情参考(AT 命令集 - ESP32 - — ESP-AT 用户指南 latest 文档 (espressif.com))、

AT+MQTTSUB=0,"TOESP01S",0

三、STM32中断接收挂起Usart协议信息标志位

AT回馈指令格式为 +数据\r\n 以此可以编写接收逻辑

 if (USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
        {
            uint8_t RxData = USART_ReceiveData(USART1);
            
            if (RxStare == 0) //状态1
            {
                if (RxData == '+' && Serial_RxFlag == 0)
                {
                    RxStare = 1;
                    pRxPacket = 0;
                }
                
            }
            else if (RxStare == 1) //状态2
            {
                if (RxData == '\r')
                {
                    RxStare =2;
                }
                else
                {
                    Serial_RxPacket[pRxPacket] = RxData;
                    pRxPacket ++;
                }
                
            }
            else if (RxStare == 2) //状态3
            {
                if (RxData == '\n')
                {
                    RxStare = 0;
                    Serial_RxPacket[pRxPacket] = '\0';
                    Serial_RxFlag = 1;
                }
            }
            USART_ClearITPendingBit(USART1, USART_FLAG_RXNE);
        }

四、STM23任务过滤识别服务器发送的操作指令并执行

针对上面要点三,对接收到的信息进行指令解析,解析的具体过程为数据比较,通过调用String库函数,运用strcmp比较字符串,将接收到的指令与设定的好的触发指令进行比较查看是否一致。后续再编写成功触发后的点灯的操作,实现远程开关灯。

#include <string.h>
if (strcmp(Serial_RxPacket, "MQTTSUBRECV:0,\"TOESP01S\",1,1") == 0)
  {
      LED1 = 1;
  }
else if (strcmp(Serial_RxPacket, "MQTTSUBRECV:0,\"TOESP01S\",1,2") == 0)
  {
      LED1 = 0;
   }

代码

这里代码我就只给出主函数以及对应的输出指令函数了,应该我的代码是基于FreeRTOS系统写的,要是不太懂的话可以到我之前的博客去简单入门一下(而且printf重定义也不放在这里面了)

main.c

#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "FreeRTOS.h"
#include "task.h"
#include "sys.h"
#include "Wifi.h"
#include "DHT11.h"
#include <string.h>
/***************
Jason:
STM32F103C8T6
FreeRTOS
2023/7/6
***************/

#define START_TASK_PRIO			1
#define START_STK_SIZE			128
TaskHandle_t StartTask_Handler;
void start_task(void *pvParameters);

#define DHT_TASK_PRIO			2
#define DHT_STK_SIZE				50
TaskHandle_t DHTTask_Handler;
void DHT_task(void *pvParameters);

#define CONTROL_TASK_PRIO			3
#define CONTROL_STK_SIZE				50
TaskHandle_t CONTROLTask_Handler;
void CONTROL_task(void *pvParameters);

int main(void)
{
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
	delay_init();
	uart_init(115200);
	LED_Init();
	Wifi_Init();
	xTaskCreate((TaskFunction_t		)start_task,
							(const char*			)"start_task",
							(uint16_t					)START_STK_SIZE,
							(void*						)NULL,
							(UBaseType_t			)START_TASK_PRIO,
							(TaskHandle_t*		)&StartTask_Handler);

	vTaskStartScheduler();
}

void start_task(void *pvParameters)
{
	taskENTER_CRITICAL();
	
	xTaskCreate((TaskFunction_t		)DHT_task,
							(const char*			)"DHT_task",
							(uint16_t					)DHT_STK_SIZE,
							(void*						)NULL,
							(UBaseType_t			)DHTTask_Handler,
							(TaskHandle_t*		)&DHTTask_Handler);
	xTaskCreate((TaskFunction_t		)CONTROL_task,
							(const char*			)"CONTROL_task",
							(uint16_t					)CONTROL_STK_SIZE,
							(void*						)NULL,
							(UBaseType_t			)CONTROLTask_Handler,
							(TaskHandle_t*		)&CONTROLTask_Handler);
	vTaskDelete(StartTask_Handler);
	taskEXIT_CRITICAL();

}

void DHT_task(void *pvParameters)
{
	while(1)
	{
		DHT11_REC_Data();
		printf("AT+MQTTPUB=0,\"office/sensor1\",\"{\\\"temperature\\\":\\\"%d\\\"\\,\\\"humidity\\\":\\\"%d\\\"}\",0,0\r\n",rec_data[2],rec_data[0]);
		vTaskDelay(5000);
	
	}
}

void CONTROL_task(void *pvParameters)
{
	while(1)
	{
		if(Serial_RxFlag == 1)
        {
            //调用String库函数,运用strcmp比较字符串
            if (strcmp(Serial_RxPacket, "MQTTSUBRECV:0,\"TOESP01S\",1,1") == 0)
            {
                LED1 = 1;
            }
			else if (strcmp(Serial_RxPacket, "MQTTSUBRECV:0,\"TOESP01S\",1,2") == 0)
            {
                LED1 = 0;
            }
			Serial_RxFlag = 0;
		}
		vTaskDelay(100); //将终端对ESP01S的CONTROL指令用任务触发,此时间为响应间隔为100ms
	}
}

DHT11.c

#include "stm32f10x.h"                  // Device header
#include "FreeRTOS.h"
#include "task.h"
#include  "DHT11.h"
#include  "delay.h"

//数据

unsigned int rec_data[4];

//对于stm32来说,是输出
void DH11_GPIO_Init_OUT(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	
	GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP; //推挽输出
	GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_12;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	
	GPIO_Init(GPIOB, &GPIO_InitStructure);

}

//对于stm32来说,是输入
void DH11_GPIO_Init_IN(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	
	GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_IN_FLOATING; //浮空输入
	GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_12;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	
	GPIO_Init(GPIOB, &GPIO_InitStructure);

}



//主机发送开始信号
void DHT11_Start(void)
{
	DH11_GPIO_Init_OUT(); //输出模式
	
	dht11_high; //先拉高
	delay_us(30);
	
	dht11_low; //拉低电平至少18us,最高不能超过30us
	delay_us(20);
	
	dht11_high; //拉高电平20~40us
	delay_us(30);
	
	DH11_GPIO_Init_IN(); //输入模式
}


//获取一个字节
char DHT11_Rec_Byte(void)
{
	unsigned char i = 0;
	unsigned char data;
	
	for(i=0;i<8;i++) //1个数据就是1个字节byte,1个字节byte有8位bit
	{
		while( Read_Data == 0); //从1bit开始,低电平变高电平,等待低电平结束
		delay_us(30); //延迟30us是为了区别数据0和数据1,0只有26~28us
		
		data <<= 1; //左移
		if( Read_Data == 1 ) //如果过了30us还是高电平的话就是数据1
		{
			data |= 1; //数据+1
		}
		
		while( Read_Data == 1 ); //高电平变低电平,等待高电平结束
	}
	
	return data;
}

//获取数据

void DHT11_REC_Data(void)
{

	unsigned int R_H,R_L,T_H,T_L;
	unsigned char RH,RL,TH,TL,CHECK;

	DHT11_Start(); //主机发送信号
	dht11_high; //拉高电平
	if( Read_Data == 0 ) //判断DHT11是否响应
	{	
		while( Read_Data == 0); //低电平变高电平,等待低电平结束(83ms)
		while( Read_Data == 1); //高电平变低电平,等待高电平结束(87ms)
		R_H = DHT11_Rec_Byte();
		R_L = DHT11_Rec_Byte();
		T_H = DHT11_Rec_Byte();
		T_L = DHT11_Rec_Byte();
		CHECK = DHT11_Rec_Byte(); //接收5个数据
		dht11_low; //当最后一bit数据传送完毕后,DHT11拉低总线 50us,以此重置为输入模式
		delay_us(55); //这里延时55us
		dht11_high; //随后总线由上拉电阻拉高进入空闲状态。
		
		if(R_H + R_L + T_H + T_L == CHECK) //和检验位对比,判断校验接收到的数据是否正确
		{
			RH = R_H;
			RL = R_L;
			TH = T_H;
			TL = T_L;
		}
	}
	rec_data[0] = RH;
	rec_data[1] = RL;
	rec_data[2] = TH;
	rec_data[3] = TL;
}

如果要整个第二章项目的工程文件,可以直接到百度网盘提取(解压密码同下)

链接:https://pan.baidu.com/s/1TdbV6onom705sWwMgxgjwA?pwd=1016 
提取码:1016

 本文为作者独立编写

 本BLOG上所有的原创文章未经本人许可,不得用于商业用途及传统媒体。网络媒体转载请注明出处,否则属于侵权行为。

特别鸣谢:77

猜你喜欢

转载自blog.csdn.net/weixin_61908666/article/details/131608922