我使用的AT固件是支持MQTT的定制固件,除了可以支持官方的AT指令外还支持定制的MQTT的AT指令。
首先定义一个结构体,用于串口中断数据的传输。
typedef struct {
char USART_BUFF[100];
int USART_Length;
int flag;
}Usart_Struct;
Usart_Struct struct_usart2;
串口中断函数:
void USART2_IRQHandler(void)
{
uint8_t ch;
#ifdef SYSTEM_SUPPORT_OS
OSIntEnter();
#endif
if(USART_GetITStatus(USART2,USART_IT_RXNE) != RESET)
{
USART_ClearITPendingBit(USART2,USART_IT_RXNE);
ch = USART_ReceiveData(USART2);
struct_usart2.USART_BUFF[struct_usart2.USART_Length++] = ch;
struct_usart2.flag = 1;
}
if( USART_GetITStatus( USART2, USART_IT_IDLE ) == SET )
{
USART_ClearITPendingBit(USART2,USART_IT_IDLE);
struct_usart2.flag = 1;
ch = USART_ReceiveData(USART2);
}
#ifdef SYSTEM_SUPPORT_OS
OSIntExit();
#endif
}
自己常用的串口工具函数:
/*******************************************************************************
* 函 数 名 : uart2_send_char
* 函数功能 : 串口2发送一字节
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void uart2_send_char(u8 temp)
{
USART_SendData(USART2,(u8)temp);
while(USART_GetFlagStatus(USART2,USART_FLAG_TXE)==RESET);
}
/*******************************************************************************
* 函 数 名 : uart2_send_buff
* 函数功能 : 串口2发送一字符串
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void uart2_send_buff(u8 buf[],u32 len)
{
u32 i;
for(i=0;i// 字符串末尾发送回车换行
uart2_send_char('\r');
uart2_send_char('\n');
}
发送AT指令并接受回显的函数是最核心的,如下。
/**
*
* [ESP8266_SendCmd 发送命令到ESP8266]
* @param cmd [需要发送的AT指令]
* @param reply [期望模块回显的内容]
* @param wait [等待的时间(ms)]
* @return [期望内容等于实际回显内容返回1,否则0]
*
*/
int ESP8266_SendCmd(char* cmd, char* reply, int wait)
{
struct_usart2.USART_Length = 0;
printf("[ESP8266_SendCmd] %s\r\n", cmd);
uart2_send_buff((u8*)cmd, strlen(cmd));
delay_ms(wait);
if (strcmp(reply, "") == 0)
{
return 0;
}
if (struct_usart2.USART_Length != 0)
{
struct_usart2.USART_BUFF[struct_usart2.USART_Length] = '\0';
if (strstr((char*)struct_usart2.USART_BUFF, reply))
{
printf("\r\n%s+++YES\r\n", struct_usart2.USART_BUFF);
return 1;
}
else if (strstr((char*)struct_usart2.USART_BUFF, "busy"))
{
printf("busy...\r\n");
delay_ms(3000);
return 0;
}
else
{
printf("\r\n%s+++NO\r\n", struct_usart2.USART_BUFF);
return 0;
}
}
}
两个基础的使用函数
/**
* [ESP8266_Init 模块初始化]
* @return [成功为1,否则为0]
*/
int ESP8266_Init()
{
int ret = 0;
ret = ESP8266_SendCmd("AT+CWMODE=1","OK", 1000);
ESP8266_SendCmd("AT+RST","", 1000);
if (!ret)
{
printf("Cannot initialize ESP module");
return 0;
}
return ret;
}
/**
* [ESP8266_JoinAP 连接WiFi]
* @param ssid [WiFi名]
* @param psd [WiFi密码]
* @return [成功为1,否则为0]
*/
int ESP8266_JoinAP(char* ssid, char* psd)
{
int ret = 0;
char ssid_psd[120] = {0};
sprintf(ssid_psd,"AT+CWJAP_CUR=\"%s\",\"%s\"",ssid, psd);
ret = ESP8266_SendCmd(ssid_psd,"WIFI CONNECTED", 5000);
return ret;
}
支持MQTT的库,,使用的函数:
注意:官方库不支持!!
/**
* [ESP8266_JoinMqttSrv 连接MQTT服务器]
* @param server [MQTT服务器的域名或IP地址]
* @param port [MQTT服务器的端口]
* @return [成功为1,否则为0]
*/
int ESP8266_JoinMqttSrv(char* server, int port)
{
int ret = 0;
int ret2 = 0;
int ret3 = 0;
char temp_cmd[120] = {0};
char temp_cmd2[120] = {0};
char temp_cmd3[120] = {0};
sprintf(temp_cmd, "AT+MQIPPORT=\"%s\",%d\r\n", server, port);
strcpy(temp_cmd2, "AT+MQUSERPWD=\"\",\"\"\r\n");
strcpy(temp_cmd3, "AT+MQSTART\r\n");
ret = ESP8266_SendCmd(temp_cmd, "OK", 1000);
ret2 = ESP8266_SendCmd(temp_cmd2, "OK", 1000);
ret3 = ESP8266_SendCmd(temp_cmd3, "MQTT CONNECTED", 3000);
if (ret && ret2 && ret3)
{
return 1;
}
else
{
return 0;
}
}
/**
* [MQTT_Publish 推送主题消息]
* @param topic [需推送消息的主题]
* @param payload [消息的内容]
* @param qos [消息质量]
* @return [成功为1,否则为0]
*/
int MQTT_Publish(char* topic, char* payload, int qos)
{
int ret = 0;
char pub_src[120] ={0};
sprintf(pub_src, "AT+MQPUBLISH=\"%s\",\"%s\",%d", topic, payload, qos);
ret = ESP8266_SendCmd(pub_src, "OK", 500);
if (ret)
{
printf("publish success to:%s\r\n", topic);
return 1;
}
printf("Failed publishing to:%s\r\n", topic);
return ret;
}
/**
* [MQTT_Subscribe 订阅MQTT主题(topic)]
* @param topic [订阅的主题]
* @param qos [消息质量]
* @return [成功为1,否则0]
*/
int MQTT_Subscribe(const char* topic, int qos)
{
int ret = 0;
char sub_str[120] = {0};
sprintf(sub_str, "AT+MQSUBSCRIBE=\"%s\",%d",topic, qos);
ret = ESP8266_SendCmd(sub_str, "OK", 1000);
if (ret)
{
printf("subscriber success to:%s\r\n", topic);
return ret;
}
printf("Failed subscriber to:%s\r\n", topic);
return ret;
}
最后还有一个问题,当订阅的消息到来时该怎么处理呢?在任务中,检测是否有符合规定的推送消息的格式的串口数据包,有就选出来然后解析数据。
void mqtt_task(void *p_arg)
{
...
while(1)
{
...
uart_event_handler();
...
}
}
void uart_event_handler()
{
//+MQD,3,"/mcu":"123"
if (struct_usart2.USART_Length != 0)
{
if (strstr(struct_usart2.USART_BUFF, "+MQD")) // 符合推送的消息的格式的串口数据包就选出来
{
// 解析
printf("\r\nsubscrbe message>>>");
struct_usart2.USART_BUFF[struct_usart2.USART_Length] = '\0';
printf("%s<<<<\r\n", struct_usart2.USART_BUFF);
struct_usart2.USART_Length = 0;
}
}
}