ESP01S通过STM32控制阿里云云平台实现小灯的开关操作
目录
一、ESP01S与STM32的连接
ESP01S与STM32的通信方式为串口通信,连线方式ESP01S的TXD,RXD与STM32的TXD,RXD交叉互连,VCC接3V3,GND接GND。
二、接收阿里云平台发来的数据
在使用STM32代替串口调试助手给ESP01S传数据之前,先用串口调试助手来分析云平台给STM32所发的数据格式,附AT指令集(ESP-AT 系列: AT+MQTT 使用)。
首先通过AT指令连接到阿里云平台,这个指令在我的上一篇博客有写(ESP-01S通过AT MQTT连接阿里云),连接到云平台以后,在云平台中设置一个灯的属性。
然后添加设备,自己取一个设备名字。
之后查看设备的三元组信息,并将三元组信息在阿里云配置软件中赋值,生成相应的MQTT参数,此处不懂的可以参考我的上一篇博客。
创建产品并成功连接到阿里云以后,通过AT+MQTTSUB=0,”订阅的TOPIC“指令订阅一个具有set权限的TOPIC。
进入在线调试,通过在阿里云平台设置参数,观察串口调试助手中接收到的数据。
可以观察到,其实STM32就是要解析这个数据,并通过解析这个数据完成开关灯的设置。
三、解析数据
实验次数多以后会发现每次的id值不同,且位数也不相同,这就表明该数据是一个不定长的数据,而STM32接收不定长数据可以通过串口的接收中断和空闲中断来实现。以下是USART1的初始化配置。
void uart_init(u32 bound)
{
//GPIO端口设置
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); //使能USART1,GPIOA时钟
//USART1_TX GPIOA.9
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9
//USART1_RX GPIOA.10初始化
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10
//Usart1 NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
//USART 初始化设置
USART_InitStructure.USART_BaudRate = bound;//串口波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式
USART_Init(USART1, &USART_InitStructure); //初始化串口1
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接收中断
USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);//开启串口空闲中断
USART_Cmd(USART1, ENABLE); //使能串口1
}
重点是要开启USART1的接收中断和空闲中断。
当串口每接收到一个数据后就会进入USART1的接收中断,当一帧数据接收完成后,在没收到数据的这段期间,会进入空闲中断,在空闲中断中,就可以判断该数据的长度,并且在空闲中断中还可以判断该数据是不是阿里云发来的,而不是ESP01S收到数据后给STM32返回的OK。
char MQTT_Head[]="+MQTTSUBRECV";
void USART1_IRQHandler(void) //串口1中断服务程序
{
uint8_t uart1RecvFlag = 0; //接收完成标志位
static uint8_t uart1RecvLen = 0; //接收数据的长度
extern char MQTT_Receive_Data[176];
if(USART_GetITStatus(USART1, USART_IT_RXNE) == SET) //接收中断
{
USART_RX_BUF[uart1RecvLen] = USART1->DR;
USART_ClearITPendingBit(USART1, USART_IT_RXNE);
uart1RecvLen++;
}
else if(USART_GetITStatus(USART1,USART_IT_IDLE) ==SET) //空闲中断
{
USART1->SR;
USART1->DR; //作用是清除IDLE标志位, 根据规格要求, 清除IDLE是要先读取SR后读DR, 因为中断是IDLE, 所以从DR读出来的是没意思的数据,
for(int i=0;i<11;i++)
{
if( USART_RX_BUF[i] != MQTT_Head[i]) //接收到的数据不是云平台发来的
{
memset(USART_RX_BUF,0x00,sizeof(USART_RX_BUF));
uart1RecvFlag = 0;
break;
}
else uart1RecvFlag = 1; //接收到的数据是云平台发来的
}
if(uart1RecvFlag == 1 )
{
for(int i = 0;i < uart1RecvLen;i++)
{
MQTT_Receive_Data[i] = USART_RX_BUF[i]; //将缓冲区数据传给另一个数组
}
}
uart1RecvLen = 0;
}
判断完数据是云平台发出的以后,就可以在应用层层面来进行状态判断,从而实现灯的亮灭。
四、根据数据进行状态判断
void Receive_Deal(void)
{
int i = 0,index;
char MQTT_Power_State[]="powerstate";
char *p;
p = MQTT_Receive_Data; //指针p指向接受数组的第一个元素
for(i=0;i<sizeof(MQTT_Receive_Data);i++)
{
if(*(p+i)=='p' && *(p+i+1)=='a' && *(p+i+2) == 'r')
{
index = i+10;
break;
}
}
for(i=0;i<10;i++,index++)
{
ESP01SStruct.MQTT_Param[i] = MQTT_Receive_Data[index];
}
ESP01SStruct.MQTT_Param_Value = MQTT_Receive_Data[index+2];
//param_compare
for(i=0;i<10;i++)
{
if(ESP01SStruct.MQTT_Param[i] != MQTT_Power_State[i])
{
ESP01SStruct.Led_State_flag=0;
break;
}
else
ESP01SStruct.Led_State_flag=1;
}
//paramvalue_compare
if(ESP01SStruct.Led_State_flag==1)
{
switch (ESP01SStruct.MQTT_Param_Value)
{
case 0x30:
{
ESP01SStruct.Led_flag=0;
break;
}
case 0x31:
{
ESP01SStruct.Led_flag=1;
break;
}
}
}
//led_work
if(ESP01SStruct.Led_State_flag==1 && ESP01SStruct.Led_flag==1)
Led_ON();
if(ESP01SStruct.Led_State_flag==1 && ESP01SStruct.Led_flag==0)
Led_OFF();
}
由于要实现的不仅仅是灯的亮灭,还有其他一些功能待完善,如:温湿度的实时上报以及控制电机的转动等等。如果只用于点灯的话,状态判断部分的代码不必这么复杂,读者自行设计即可。
五、可视化界面的设计
登录阿里云IOT Studio平台,创建新的Web开发界面。
进入到页面以后,即可添加自己所需的组件,点击相应的组件,在右侧对应的交互中,配置数据与阿里云平台中的数据一致即可。
这样点击页面上方的预览,按一下按钮即可实现灯的打开啦!
后续将会把温湿度实时上报部分的数据处理也加上。
感谢你的耐心观看,本人水平有限,代码写的不一定最优,有其他方法也可以共同探讨。