STM32--ESP8266--AT指令使用例程

 我使用的AT固件是支持MQTT的定制固件,除了可以支持官方的AT指令外还支持定制的MQTT的AT指令。

前序

  • 单片机:STM32F103ZET6
  • 串口:uart2 / 串口中断
  • 操作系统:uCosIII

代码:

首先定义一个结构体,用于串口中断数据的传输。

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;
        }
    }
}

你可能感兴趣的:(C,STM32,MQTT,ESP8266)