宏定义配置
串口通信配置
消息解析及数据发送
ESP8266初始化
注意事项
完整工程文件
经过基础教程使用AT指令连接阿里云后,大家应该对设备连接云平台的基本流程有所了解。接下来,我们将深入探讨如何通过STM32微控制器来配置和优化连接阿里云的过程。
STM32提供了广泛的控制和定制选项,能够灵活应对复杂的物联网应用需求。利用STM32,我们能够实现高效且可靠的设备与阿里云之间的通信,支持各种复杂的数据传输和设备管理功能。
宏定义配置
当使用STM32微控制器连接到阿里云时,通过宏定义可以显著提升代码的可读性和灵活性。在开始配置和编写代码之前,通常会定义一些初始宏来简化代码的编写和调试过程。
//WIFI配置
#define ESP8266_WIFI_INFO "AT+CWJAP=\"ALIYUN\",\"12345678\"\r\n"
//阿里云证书配置
#define MQTT_CLIENT_ID "j07fRDwyQJM.STM32D|securemode=2\\,signmethod=hmacsha256\\,timestamp=1720052943739|"
#define MQTT_USER_NAME "STM32D&j07fRDwyQJM"
#define MQTT_PASSWD "5c7858f8ec839caddb835afc8c9ea8351b1aa7867c05e8d84c8df4eaf9e88ae6"
#define ESP8266_CERT_INFO "AT+MQTTUSERCFG=0,1,\""MQTT_CLIENT_ID"\",\""MQTT_USER_NAME"\",\""MQTT_PASSWD"\",0,0,\"\"\r\n"
//阿里云域名配置
#define MQTT_HOSTURL "iot-06z00iurioijdlq.mqtt.iothub.aliyuncs.com"
#define ESP8266_ALIYUN_INFO "AT+MQTTCONN=0,\""MQTT_HOSTURL"\",1883,0\r\n"
//数据下行
#define SUB_TOPIC "/sys/j07fRDwyQJM/STM32D/thing/service/property/set"
#define ESP8266_SUBTOPIC_INFO "AT+MQTTSUB=0,\""SUB_TOPIC"\",0\r\n"
//数据上行
#define PUB_TOPIC "/sys/j07fRDwyQJM/STM32D/thing/event/property/post"
//上行数据
#define JSON_FORMAT "{\\\"params\\\":{\\\"temp\\\":%d\\,\\\"humi\\\":%d\\}\\,\\\"version\\\":\\\"1.0.0\\\"}"
串口通信配置
当配置STM32与阿里云通信时,串口数据处理函数是至关重要的一部分,用于处理从Wi-Fi模块或其他外设接收到的数据,并与阿里云进行通信。
unsigned char esp8266_buf[256];
unsigned short esp8266_cnt = 0, esp8266_cntPre = 0;
//==========================================================
// 函数名称: ESP8266_Clear
//
// 函数功能: 清空缓存
//
// 入口参数: 无
//
// 返回参数: 无
//
// 说明:
//==========================================================
void ESP8266_Clear(void)
{
memset(esp8266_buf, 0, sizeof(esp8266_buf));
esp8266_cnt = 0;
}
//==========================================================
// 函数名称: ESP8266_WaitRecive
//
// 函数功能: 等待接收完成
//
// 入口参数: 无
//
// 返回参数: REV_OK-接收完成 REV_WAIT-接收超时未完成
//
// 说明: 循环调用检测是否接收完成
//==========================================================
_Bool ESP8266_WaitRecive(void)
{
if(esp8266_cnt == 0) //如果接收计数为0 则说明没有处于接收数据中,所以直接跳出,结束函数
return REV_WAIT;
if(esp8266_cnt == esp8266_cntPre) //如果上一次的值和这次相同,则说明接收完毕
{
esp8266_cnt = 0; //清0接收计数
return REV_OK; //返回接收完成标志
}
esp8266_cntPre = esp8266_cnt; //置为相同
return REV_WAIT; //返回接收未完成标志
}
//==========================================================
// 函数名称: ESP8266_SendCmd
//
// 函数功能: 发送命令
//
// 入口参数: cmd:命令
// res:需要检查的返回指令
//
// 返回参数: 0-成功 1-失败
//
// 说明:
//==========================================================
_Bool ESP8266_SendCmd(char *cmd, char *res)
{
unsigned char timeOut = 200;
Usart_SendString(USART2, (unsigned char *)cmd, strlen((const char *)cmd));
while(timeOut--)
{
if(ESP8266_WaitRecive() == REV_OK) //如果收到数据
{
if(strstr((const char *)esp8266_buf, res) != NULL) //如果检索到关键词
{
ESP8266_Clear(); //清空缓存
return 0;
}
}
delay_ms(10);
}
return 1;
}
消息解析及数据发送
当处理来自阿里云平台的下行数据以及上行数据时,需要实现消息解析和向阿里云发送数据的功能,具体涉及MQTT消息的解析和处理。
//==========================================================
// 函数名称: Json_Analysis
//
// 函数功能: JSON数据解析
//
// 入口参数: json_data:待解析数据
//
// 返回参数: 无
//
// 说明:
//==========================================================
void Json_Analysis(unsigned char *json_data)
{
cJSON *JSON_Value;
cJSON* root = cJSON_Parse((const char*)json_data);
if(root == NULL)
{
UsartPrintf(USART_DEBUG,"cJSON_Error!\r\n");
}
else
{
cJSON* items = cJSON_GetObjectItem(root,"items");
cJSON* lighting = cJSON_GetObjectItem(items,"lighting");
JSON_Value = cJSON_GetObjectItem(lighting,"value");
if(JSON_Value ->valueint)
{
UsartPrintf(USART_DEBUG,"OPEN_LED!\r\n");
LED0 = 0;
}
else
{
UsartPrintf(USART_DEBUG,"CLOSE_LED!\r\n");
LED0 = 1;
}
}
cJSON_Delete(root);
}
//==========================================================
// 函数名称: ESP8266_SendData
//
// 函数功能: 发送数据
//
// 入口参数: 无
//
//
// 返回参数: 无
//
// 说明:
//==========================================================
void ESP8266_SendData(void)
{
unsigned char cmdBuf[256];
ESP8266_Clear(); //清空接收缓存
sprintf((char *)cmdBuf,"AT+MQTTPUB=0,\""PUB_TOPIC"\",\""JSON_FORMAT"\",0,0\r\n",temp,humi); //发送命令
while(ESP8266_SendCmd((char *)cmdBuf, "OK"));
UsartPrintf(USART1,"temp:%d, humi:%d\r\n",temp,humi); //调试串口打印
}
//==========================================================
// 函数名称: ESP8266_ReceiveData
//
// 函数功能: 接收数据
//
// 入口参数: timeOut:等待时间
//
// 返回参数: 无
//
// 说明:
//==========================================================
void ESP8266_ReceiveData(unsigned short timeOut)
{
char *ptrMQT = NULL;
unsigned int msg_len=0;
unsigned char msg_body[256] = {0};
do
{
if(ESP8266_WaitRecive() == REV_OK) //如果接收完成
{
ptrMQT = strstr((char *)esp8266_buf, "+MQTTSUBRECV:0"); //搜索“MQT”头
if(ptrMQT == NULL) //如果没找到,可能是MQT头的延迟,还是需要等待一会,但不会超过设定的时间
{
UsartPrintf(USART_DEBUG, "\"MQT\" not found\r\n");
}
else
{
sscanf((const char *)ptrMQT,"+MQTTSUBRECV:0,\""SUB_TOPIC"\",%d,%s",&msg_len,msg_body);
//UsartPrintf(USART_DEBUG,"len:%d,msg:%s\r\n",msg_len,msg_body);
Json_Analysis(msg_body);
}
}
delay_ms(5);
timeOut--;
} while(timeOut >0);
}
ESP8266初始化
最后对ESP8266模块进行初始化,以确保它能够与STM32微控制器实现通信,为两者之间稳定的数据交换建立必要的基础。
//==========================================================
// 函数名称: ESP8266_Init
//
// 函数功能: 初始化ESP8266
//
// 入口参数: 无
//
// 返回参数: 无
//
// 说明:
//==========================================================
void ESP8266_Init(void)
{
ESP8266_Clear();
UsartPrintf(USART_DEBUG, "0. RST\r\n");
while(ESP8266_SendCmd("AT+RST\r\n", "OK"))
delay_ms(500);
UsartPrintf(USART_DEBUG, "1. AT\r\n");
while(ESP8266_SendCmd("AT\r\n", "OK"))
delay_ms(500);
UsartPrintf(USART_DEBUG, "2. CWMODE\r\n");
while(ESP8266_SendCmd("AT+CWMODE=1\r\n", "OK"))
delay_ms(500);
UsartPrintf(USART_DEBUG, "3. CWDHCP\r\n");
while(ESP8266_SendCmd("AT+CWDHCP=1,1\r\n", "OK"))
delay_ms(500);
UsartPrintf(USART_DEBUG, "4. CWJAP\r\n");
while(ESP8266_SendCmd(ESP8266_WIFI_INFO, "OK"))
delay_ms(500);
UsartPrintf(USART_DEBUG, "5. CONFIG CERT INFO\r\n");
while(ESP8266_SendCmd(ESP8266_CERT_INFO, "OK"))
delay_ms(500);
UsartPrintf(USART_DEBUG, "6. CONFIG ALIYUN NETWORK\r\n");
while(ESP8266_SendCmd(ESP8266_ALIYUN_INFO, "OK"))
delay_ms(500);
UsartPrintf(USART_DEBUG, "7. SUBSCRIBE TOPIC\r\n");
while(ESP8266_SendCmd(ESP8266_SUBTOPIC_INFO, "OK"))
delay_ms(500);
UsartPrintf(USART_DEBUG, "8. ESP8266 Init OK\r\n");
}
注意事项
此外,当处理大量的JSON数据时,如果未调整栈的大小,可能会导致栈溢出问题,进而影响程序的运行结果,甚至导致程序崩溃。在这种情况下,需要手动调整栈的大小,以确保程序能够正常运行。