STM32串口如何代碼實現更高效的接收消息 原 薦

這段時間一直在研究多旋翼飛行器,以及其它的事情,博客好外沒更新,再不堅持怕真荒廢了哦。

在上篇簡單實現MAVLink協議的解析,並演示按照設計好的命令執行對應的事件處理,以及又加入 CRC校驗,實現更穩定的通信,但在上文結束時也提到當對一個包進行解析及對應事件處理時,是不能接收新的數據,直到事件處理完成,Msg_Rev.Get 狀態設置爲 RECEIVING 後方能再接收新的數據。這時,當事件處理需要一定時間,而又有新的數據不斷髮送過來時,很容易造成數據丟失現象。

如何提高串口通信效率,並避免丟包現象了?

爲提高效率,首先想到採用DMA方式,然而考慮下發現,接收的數據包是不固定的;並且即使採用DMA,若MAVLink接收緩存仍設計成只接收一條消息大小,丟包問題仍然還是會有滴。

這樣就想有沒方法軟件來實現,就相到如果開闢一個緩存空間,不斷接收的數據都放到那兒,而包的解析處理函數可從這裏面依次取出一定數據,來作處理。這樣只要設計比較合理,因軟件阻塞造成的丟包現象就容易解決了。那麼要設計一個怎樣的緩存呢 ? 其實很容易想到隊列(先進先出的特性),而爲了更有效且合理的利用空間,又就會想到環形隊列這種數據結構 。

首先是其數據結構設計,以及插入刪除操作,不多說,如下代碼:

#define MAX_QUEUE_LEN  (4096) // 4K
#define RW_OK   0
#define FULL_ERROR    1
#define EMPTY_ERROR   2

typedef uint8_t boolean;

typedef struct
{
    u16 MemFrontSendIndex ;
    u16 MemRearRecvIndex ;
    u16 MemLength ;
    u8  MemDataBuf[MAX_QUEUE_LEN];
} Queue_Mem_Struct , * Queue_Mem_Struct_p ;

Queue_Mem_Struct Queue_Recv ;

boolean QueueMemDataInsert(u8 data)
{
    if (MAX_QUEUE_LEN == Queue_Recv.MemLength)
    {
        return FULL_ERROR;
    }
    else
    {
        Queue_Recv.MemDataBuf[Queue_Recv.MemRearRecvIndex] = data ;
        //        if(++Queue_Recv.MemRearRecvIndex >= MAX_QUEUE_LEN){Queue_Recv.MemRearRecvIndex = 0;}
        Queue_Recv.MemRearRecvIndex = (Queue_Recv.MemRearRecvIndex + 1) % MAX_QUEUE_LEN;
        Queue_Recv.MemLength ++ ;
        return RW_OK;
    }
}

boolean QueueMemDataDel(u8 *data)
{
    if (0 == Queue_Recv.MemLength)
    {
        return EMPTY_ERROR;
    }
    else
    {
        *data = Queue_Recv.MemDataBuf[Queue_Recv.MemFrontSendIndex]  ;
        Queue_Recv.MemFrontSendIndex = (Queue_Recv.MemFrontSendIndex + 1) % MAX_QUEUE_LEN;
        Queue_Recv.MemLength -- ;
        return RW_OK;
    }
}

這樣,只需通過QueueMemDataInsert函數把串口接收的數據依次填充到緩衝區Queue_Recv.MemDataBuf中去。而在處理時調用QueueMemDataDel函數取出對應個數的數據來處理。這樣就避免整個處理過程中無法同時接收數據而產生丟包的問題。當然此時要保證緩衝區的數據及時處理完,否則,尤其當數據量很大時隊列填充滿後,又會造成數據無法再填充進來。

另外至此又會發現,如上設計可結合採用DMA方式。設計的好的話,可以進一步大幅度提升STM32利用率及系統運行效率!


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章