第一章链接
第二章开发环境
主控 | 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