使用esp8266實現(xiàn)STM32聯(lián)網(wǎng)(最簡單USART方法)

上一篇

esp8266怎么配置
    esp8266和USB轉(zhuǎn)TTL連接
esp8266簡單介紹
esp8266連接路由器
esp8266通過路由器連接在同一局域網(wǎng)中的電腦,建立TCP連接
esp8266使用串口發(fā)送數(shù)據(jù)到電腦上的網(wǎng)絡調(diào)試助手
esp8266使用串口通過局域網(wǎng)發(fā)送到電腦上自己寫的Java程序
esp8266的透傳模式
esp8266使用透傳模式連接到電腦的網(wǎng)絡調(diào)試助手
esp8266使用透傳模式連接到電腦上的java程序

這一篇

esp8266與STM32連接,電腦通過STM32配置esp8266實現(xiàn)聯(lián)網(wǎng)發(fā)送數(shù)據(jù)
具體流程如下圖
2=

esp8266怎么和STM32連接(引腳連接)?

STM32CubeMx配置的usart2使用的PA2和PA3要與esp8266的TX和RX對應,但是得反過來接,要么根本發(fā)不出去,看來esp8266又印反了
3V3和EN得接到同一個3V上才可以,要不收到的老是error

STM32使用USART和電腦相互傳輸數(shù)據(jù)?

將STM32產(chǎn)生的數(shù)據(jù)發(fā)送到電腦的串口調(diào)試助手
    第一種方式:
        使用UASRT傳輸只需要重新定義fputc()函數(shù),直接使用Printf函數(shù)就可以將字符串打印到電腦(即通過串口輸出到電腦)
    第二種方式:
        使用HAL庫中封裝好的UASART函數(shù)  HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)也可以實現(xiàn)串口輸出
電腦要發(fā)送字符串給STM32,那么STM32怎么收到數(shù)據(jù),而且知道這個數(shù)據(jù)什么意思呢?
    第一種方式(只能接收定長字符串):
        HAL庫依舊有封裝好的函數(shù)HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout),但是使用這個函數(shù)有一個問題,這個函數(shù)的額第三個參數(shù)是收到的字符串的大小,可是我都沒有發(fā)送,怎么提前把這個字符串的大小寫入單片機呢?
            其實問題是STM32如何接收不定長的字符串?
        【STM32內(nèi)部產(chǎn)生的數(shù)據(jù)或者從傳感器中獲取的數(shù)據(jù),STM32如果要發(fā)送該數(shù)據(jù)可以直接使用sizeof獲得數(shù)據(jù)長度作為第三個參數(shù),但是當人為的發(fā)送給串口時,由于提前燒入的程序如果要使用HAL庫的USART接收函數(shù)的話,需要確定一個字符串長度,那么這個程序就只能接收指定長度的字符串了,那要如何實現(xiàn)不定長也能接收呢?】
    第二種方式:
        DMA+接收結(jié)束判斷。這接收結(jié)束判斷可以是字節(jié)的timeout,也可以是USART_IT_IDLE線路空閑的標志等。這種方式對于需要整幀接收,且通信速度較快或需要占用cpu較少的情況
        【詳細的處理方式可見串口USART 收發(fā)數(shù)據(jù)處理方式總結(jié)--DMA+USART+USART_Idle_Interrupt】

那么如何配置呢?

        既然是DMA和空閑接收中斷就需要設置DMA和UASRT的中斷(即在中斷處理函數(shù)中需要有DMA1 channel5 global interrupt和USART1 global interrupt)
        
        如果要使用printf輸出到串口的話,就需要重定義fputc函數(shù)(定義在usart.c中)
        
        如果要用線路空閑來觸發(fā)中斷來結(jié)束接收的話,需要有判斷線路是否空閑的函數(shù),這個函數(shù)最好還需要在結(jié)束接收時將收到的數(shù)據(jù)保存到自己定義的變量中

那么如何實現(xiàn)不定長接收呢,不還是得知道接受的字符串的長度嗎?

    是需要知道,這里使用一個結(jié)構(gòu)體來保存字符串和字符串的長度以及一個標記(用來表示一次接收完成,如果不放在結(jié)構(gòu)體里面,使用全局變量的話會比較麻煩)
    具體的方法是這樣的:在一開始接收的時候,將收到的字符串保存在結(jié)構(gòu)體中的字符串數(shù)組中,而函數(shù)要求的大小這個參數(shù)設置為比較大的數(shù)字(可以是一次接收數(shù)據(jù)長度的最大值,這里是1024),在判斷線路是否空閑的函數(shù)中,當線路空閑時(即一次接收完成時),將收到的字符串的長度保存到這個結(jié)構(gòu)體中的字符串長度變量中,這樣,當需要將收到的字符串再次發(fā)出時,就可以使用已知的長度進行發(fā)送了,由此實現(xiàn)了不定長接收。
    【其原理其實是用一個大空間去接收(看來接收空間夠大就行,不需要定長接收),在接收完成時計算收到的數(shù)據(jù)長度保存起來(和收到的數(shù)據(jù)要一一對應,這也是使用結(jié)構(gòu)體的好處),當需要再次發(fā)送出去時,就知道這個字符串的長度了,就可以定長發(fā)送了】
    
    結(jié)構(gòu)體
        #define RX_LEN 1024  
             
        typedef struct  
        {  
        uint8_t  RX_flag:1;        //IDLE receive flag
        uint16_t RX_Size;          //receive length
        uint8_t  RX_pData[RX_LEN]; //DMA receive buffer
        }USART_RECEIVETYPE; 
        
        extern USART_RECEIVETYPE UsartType;
        
下面是程序的流程
    
    首先在main函數(shù)中使用HAL_UART_Receive_DMA(&huart1, UsartType.RX_pData, RX_LEN); 開始接收,接收的數(shù)據(jù)放到結(jié)構(gòu)體中,長度為最大值
    然后打開中斷,__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);這個函數(shù)進行中斷使能,
    
    具體介紹:
    /** @brief  Enable the specified UART interrupt.
    * @param  __HANDLE__: specifies the UART Handle.
    *         UART Handle selects the USARTx or UARTy peripheral 
    *         (USART,UART availability and x,y values depending on device).
    * @param  __INTERRUPT__: specifies the UART interrupt source to enable.
    *          This parameter can be one of the following values:
    *            @arg UART_IT_CTS:  CTS change interrupt
    *            @arg UART_IT_LBD:  LIN Break detection interrupt
    *            @arg UART_IT_TXE:  Transmit Data Register empty interrupt
    *            @arg UART_IT_TC:   Transmission complete interrupt
    *            @arg UART_IT_RXNE: Receive Data register not empty interrupt
    *            @arg UART_IT_IDLE: Idle line detection interrupt
    *            @arg UART_IT_PE:   Parity Error interrupt
    *            @arg UART_IT_ERR:  Error interrupt(Frame error, noise error, overrun error)
        * @retval None
        * */
            #define __HAL_UART_ENABLE_IT(__HANDLE__, __INTERRUPT__)
    之后是否需要延時防止接收不到或者防止其他錯誤的發(fā)生不是很清楚。
    
    在stm32f1xx_it.c的DMA和USART的中斷函數(shù)中并沒有需要重寫的回調(diào)函數(shù)
    
    在usart.c中實現(xiàn)處理空閑的函數(shù)添加到USART的中斷函數(shù)中,那么當線路產(chǎn)生空閑時,就會觸發(fā)一個中斷,這個空閑處理的函數(shù),就會開始工作,先清空空閑標志以允許繼續(xù)接收,然后使用HAL_StatusTypeDef HAL_UART_DMAStop(UART_HandleTypeDef *huart)停止此次接收,接著獲得此次接收到的字符串的長度(這里比較深入,有寄存器的問題,不大理解),然后又調(diào)用了HAL_UART_Receive_DMA,這個應該和取得的長度是同一個結(jié)構(gòu)體,那么之前的HAL_UART_Receive_DMA又是再干什么呢?(或許是為了解決第一次的傳輸問題,學的不夠深入,還需要學的再深入)
    最后就可以使用獲得的長度和字符串將收到的字符串發(fā)送出去了,這樣就實現(xiàn)了不定長接收。
    
【問題】在結(jié)構(gòu)體中定義的是一個uint8_t類型的數(shù)組,那么可以按字符串輸出嗎?

        可以,
        HAL_UART_Transmit(&huart1, UsartType.RX_pData, UsartType.RX_Size, 0xFFFF);
        printf("\n%s\n",UsartType.RX_pData);
        上面兩句一樣的效果
    具體代碼:
        在usart.c中添加
            /* USER CODE BEGIN 1 */
            /**
              * @brief  Retargets the C library printf function to the USART.
              */
            int fputc(int ch,FILE *f)
            {
                HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);
                return ch;
            }
            
            /**
              * @brief  This function handles USART1 IDLE interrupt.
              */
            void UsartReceive_IDLE(UART_HandleTypeDef *huart)  
            {  
                uint32_t temp;  
              
                if((__HAL_UART_GET_FLAG(huart,UART_FLAG_IDLE) != RESET))  
                {   
                    __HAL_UART_CLEAR_IDLEFLAG(&huart1);  
                    HAL_UART_DMAStop(&huart1);  
                    temp = huart1.hdmarx->Instance->CNDTR;  
                    UsartType.RX_Size =  RX_LEN - temp;   
                    UsartType.RX_flag=1;  
                    HAL_UART_Receive_DMA(&huart1,UsartType.RX_pData,RX_LEN);  
                }  
            }  
            /* USER CODE END 1 */
    在usart.c中實例化結(jié)構(gòu)體
            /* USER CODE BEGIN 0 */
            USART_RECEIVETYPE UsartType; 
            /* USER CODE END 0 */
            
    在usart.h中定義結(jié)構(gòu)體
            /* USER CODE BEGIN Private defines */
            #define RX_LEN 1024  
                 
            typedef struct  
            {  
            uint8_t  RX_flag:1;        //IDLE receive flag
            uint16_t RX_Size;          //receive length
            uint8_t  RX_pData[RX_LEN]; //DMA receive buffer
            }USART_RECEIVETYPE;  
               
            extern USART_RECEIVETYPE UsartType; 
            /* USER CODE END Private defines */
    在stm32f1xx_it.c的中斷函數(shù)中添加
            void USART1_IRQHandler(void)
            {
              /* USER CODE BEGIN USART1_IRQn 0 */
                UsartReceive_IDLE(&huart1);  
              /* USER CODE END USART1_IRQn 0 */
              HAL_UART_IRQHandler(&huart1);
              /* USER CODE BEGIN USART1_IRQn 1 */
            
              /* USER CODE END USART1_IRQn 1 */
            }
    在main.c中main函數(shù)中基本的初始化函數(shù)后添加
              /* USER CODE BEGIN 2 */
                HAL_UART_Receive_DMA(&huart1, UsartType.RX_pData, RX_LEN);  
                __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE); 
                HAL_Delay(1000);
              /* USER CODE END 2 */

STM32如何給esp8266發(fā)送AT指令?

途徑就為通過串口
那么怎么使用串口,
    是直接使用HAL庫封裝的相關函數(shù)
    還是需要一些驅(qū)動代碼
電腦通過串口與STM32交流,STM32通過串口與esp8266交流
    既然上面實現(xiàn)了電腦與STM32使用USART相互傳輸數(shù)據(jù),即STM32可以接收電腦發(fā)來的不定長數(shù)據(jù),那么STM32也能接收esp8266返回的不定長數(shù)據(jù)(向esp8266發(fā)送不同的指令,返回消息不一樣,長度也不一樣)

對于接收esp8266返回的信息也使用DMA加空閑中斷的方式,那么向esp8266發(fā)送數(shù)據(jù)要怎么做呢?

        上面的代碼已經(jīng)可以接收來自電腦的不定長消息,然后再發(fā)給電腦,那么將這個消息直接發(fā)送給esp8266就可以了,兩個不同的串口有不同的實例,只需要指定好串口就可以向這個串口發(fā)送數(shù)據(jù)了?!就蝗挥X得自己寫的好亂,沒有條理,得改】
    其實具體的代碼就是在什么那個處理STM2與電腦使用USART通信的代碼上再增加一個STM與esp8266的USART交流流程就可以了,需要注意區(qū)分不同的串口,兩個流程的交匯點在main函數(shù)中,當STM32收到電腦發(fā)來的不定長信息后,通過空閑中斷處理函數(shù)獲得長度,將該消息直接使用串口發(fā)送到連接esp8266的串口即可,如果STM32收到來自esp8266串口的消息,一樣使用DMA加空閑中斷的方式獲得來自esp8266的不定長返回信息,在這里也是一樣通過這個串口的空閑中斷處理函數(shù)獲得返回信息的長度,將這個返回信息發(fā)送給與電腦相連的串口就可以了,這樣就完成了通過STM32配置esp8266的整個流程。

其意義是什么呢?

    這樣STM32本身就可以使用串口將獲取的傳感器信息通過esp8266發(fā)送到指定服務器,實現(xiàn)了STM32的聯(lián)網(wǎng),一樣也實現(xiàn)了通過網(wǎng)絡向STM32發(fā)送指令控制傳感器的功能。
最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容