1. 程式人生 > 實用技巧 >使用STM32F1控制ESP8266

使用STM32F1控制ESP8266

ESP8266:

  本次STM32控制ESP8266使用的ESP晶片版本是ESP8266-01S,主機MCU使用的是STM32F1C8T6。

  ESP8266是樂鑫公司的一款WIFI晶片(Soc),並且可以被當作MCU使用。實際上,ESP系列晶片是一款發行量巨大,價效比極高的晶片。

  本次我想要實現的功能是獲取網路時間供MCU使用,所以選擇結構簡單的一款封裝——ESP01S,ESP01S的具體引數如下(圖源:安信可ESP8266開發手冊)

  

  與STM32 C8T6的連線方式如下:(圖源:安信可ESP8266開發手冊)

  

  ESP8266的通訊方式是串列埠通訊,由於個人開發需求,我選擇的是USART2介面,實際串列埠可自主選擇。

程式初始化(usart2.c):

  需要初始化的片上外設有USART2,具體如下:

void USART2_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);  //GPIO時鐘    
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);  //
串列埠外設時鐘 GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP; //推輓複用輸出 GPIO_InitStructure.GPIO_Pin=GPIO_Pin_2; GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOA,&GPIO_InitStructure); GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING; //浮空輸入
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_3; GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_Init(GPIOA,&GPIO_InitStructure); USART_InitStructure.USART_BaudRate = 115200 ; //波特率,這裡改為115200與ESP8266通訊 USART_InitStructure.USART_WordLength=USART_WordLength_8b; //資料幀字長 8位 USART_InitStructure.USART_StopBits=USART_StopBits_1; //配置停止位 1個 USART_InitStructure.USART_Parity=USART_Parity_No; //校驗位,無校驗位 USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None; //不使用用硬體流控制 USART_InitStructure.USART_Mode=USART_Mode_Tx|USART_Mode_Rx; //收發一體 USART_Init(USART2,&USART_InitStructure); //完成初始化 USART_Cmd(USART2,ENABLE); //使能串列埠 USART_ITConfig(USART2,USART_IT_RXNE,ENABLE); //使能串列埠中斷 //優先順序配置 NVIC_InitStructure.NVIC_IRQChannel=USART2_IRQn; NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0; NVIC_InitStructure.NVIC_IRQChannelSubPriority=0; NVIC_Init(&NVIC_InitStructure); }

  因為我們需要傳送,接收ESP晶片的資訊,所以這裡需重定向printf函式到串列埠,並定義接收中斷函式(接收中斷函式部分參考網上大佬思路)

//輸出重定向
int fputc(int ch, FILE *f)
{      
    while((USART2->SR&0X40)==0);//迴圈傳送,直到傳送完畢   
    USART2->DR = (u8) ch;      
    return ch;
}

//接收中斷
void USART2_IRQHandler(void)
{
    u8 Res;

    if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)
        {
        Res =USART_ReceiveData(USART2);    //讀取接收到的資料
        
        if((USART_RX_STA2&0x8000)==0)//接收未完成
            {
            if(USART_RX_STA2&0x4000)//接收到了0x7D}
                {
                if(Res!=0x7D)USART_RX_STA2=0;//接收錯誤,重新開始
                else USART_RX_STA2|=0x8000;    //接收完成了 
                }
            else //還沒收到0X7D }
                {    
                if(Res==0x7D)USART_RX_STA2|=0x4000;
                else
                    {
                    USART_RX_BUF2[USART_RX_STA2&0X3FFF]=Res ;
                    USART_RX_STA2++;
                    if(USART_RX_STA2>(1024-1))USART_RX_STA2=0;//接收資料錯誤,重新開始接收      
                    }         
                }
            }            
    } 

} 

  在接收中斷中,有兩個變數在函式頭進行全域性宣告,並在標頭檔案中進行extern宣告,方便其他函式使用。

  其中USART_RX_BUF2[512]用於接收資料,長度自定。

//usart2.c函式頭
#include "stm32f10x.h" #include "stm32f10x_usart.h" #include "usart2.h" #include <stdio.h> u8 USART_RX_BUF2[512]; u16 USART_RX_STA2;

向ESP8266傳送資訊

  接下來,進行ESP01.c檔案的構建,首先想要獲得時間,必須先連線網際網路。

void ESP01_Getweb(void)
{
    delay_ms(50);
    
    printf("AT+CWMODE=1");
    delay_ms(50);
    RST_ON;
    delay_ms(100);
    RST_OFF;
    delay_ms(50);
    
    USART_RX_STA2=0x0000;
    printf("AT+CWJAP=\"WIFI name\",\"password\"");
    delay_ms(1000);  //注意delay時間限制
    delay_ms(1000);
    delay_ms(1000);
    delay_ms(1000);
    delay_ms(1000);
}

  這裡延時情況由具體情況而定,可適當縮短。ESP的連線僅需一次即可,下次在同樣的環境下可自主登入。

  然後是獲取網路時間,這裡需要呼叫一個網路API介面,這個介面會返回標準網路時間。

void ESP01_Gettime(void)
{
    printf("AT+CIPMUX=0\r\n");
    delay_ms(500);
    
    printf("AT+CIPSTART=\"TCP\",\"api.k780.com\",80\r\n");
    delay_ms(1600);
    
    printf("AT+CIPMODE=1\r\n");
    delay_ms(500);
    
    printf("AT+CIPSEND\r\n");
    delay_ms(500);
    USART_RX_STA2=0x0000;  //使資料從陣列頭開始記錄
    printf("GET http://api.k780.com:88/?app=life.time&appkey=10003&sign=b59bc3ef6191eb9f747dd4e83c99f2a4&format=json&HTTP/1.1\r\n");
    delay_ms(1600);
}

  這裡延時可以根據自身情況而定,實際上在每次傳送指令後,ESP都會返回資料,可以由此判斷是否接收成功資料。

  接收完成後,資料會儲存在USART_RX_BUF2這個陣列中,通過提取有效資訊,即可獲取時間,自此,通過ESP獲取時間就完成了(實測成功)。

  

  (由於個人水平有限,在程式中,可能會出現錯誤或低效的地方,請注意) =)