拋磚引玉----基於51串口通訊編程軟件架構剖析

前言:
串口通訊對於所有的嵌入式工程師十分常見,對於一個與外界交互的系統必須依賴一些手段,比如串口、USB、紅外、GPRS之類的數據通訊傳輸方式。而串口作爲一種廉價的短距離可靠的通訊方式得到了廣泛應用。
廢話少說了,就此打住,進入正題。
本文主要從軟件結構上講解如何在資源比較缺乏的系統上實現通訊協議的串口通訊編程,以及如何優化程序效率,從而使系統更快、更穩定運行。

正文:
      我們以51單片機爲例。51中一般針對串口通訊編程,通常採取中斷接受查詢發送的方式。中斷函數在接受數據到達時被重複調用,其實是個重複入棧的過程,所以不宜將函數寫的太長,函數太長一般會導致棧太深佔用系統資源,二是處理時間過長,可能導致通訊出錯。爲了防止在處理數據過程中不受干擾,通常在處理接受數據前關閉中斷,處理完後再開。
通常的的編程方式如下:
static void UartInterruptService(void) interrupt 4
{
    ES = 0;
    RI = 0;
    uart_process(SBUF);
    ES=1;
}
下面重點介紹數據處理函數 uart_process(SBUF);
其實很多時候,對於通訊傳輸的數據處理纔是關鍵,尤其對於設計通訊協議而言。筆者在剛剛做的一個系統上就碰到這樣的問題,當系統龐大了,資源十分有限的情況下,數據處理一旦佔用資源太多,效率太低將導致系統崩潰而無法運行。
到了這裏,很多工程師可能會考慮開個大的緩衝區FIFO將接收到的數據保存在緩衝區,然後對其進行解析、判斷進行下一步程序編寫,當然這在系統資源比較豐富的情況下是沒有問題的,ARM上採取的就是這樣的方式。但如何系統龐大呢,留給的資源缺乏則不行。這樣做的一個很大缺點必須是將數據幀接收完了才能夠判斷,降低了效率和運行速度。
其實還有另外的方式,可以採取在每接收一個字節就對其解析,解析完判斷轉到下一個狀態,並將其中的有用數據存儲在相應的數據結構中去,可以採取狀態機實現。

將狀態機設計爲兩個控制狀態,一是串口狀態——uart_state ,一是命令類型狀態——cmd_state .
(1)狀態機開始狀態:串口狀態爲CMD_NO
(2)接受到STX_CMD,狀態變爲CMD_START.
(3)接下來將自動進入接受命令幀的狀態,再開啓命令狀態的狀態機,對發送來的有用數據進行解析,保存,校驗等。處理完畢後將uart_state設爲CMD_END狀態進行下一步的接受完畢判斷,將cmd_state設置爲初始的NO_CMD狀態。
(4)最後進行ETX_CMD判斷,判斷數據接收是否完畢。


void uart_process(U8 u8)
{
     if(uart_state == CMD_NO)
     {
    if(u8 == STX_CMD)
      {
        uart_state = CMD_START;
      }

       }
    else if(uart_state == CMD_START)
    {
        switch(cmd_state)
        {
           case NO_CMD:
              cmd_state = u8;
              break;

           case COST_CMD:
                    //解析存儲有用數據到相應數據結構中
                    //進行CRC校驗
                    ……
                       uart_state = CMD_END;
                       cmd_state = NO_CMD;
                       CRC = 0;
                        break;
                        …… 
                   }
              ……
            }
        else if(uart_state == CMD_END)
         {
            uart_state = CMD_NO;
            if(u8 == ETX_CMD)
            {
              //接受完畢
              //可以考慮拋出一個消息main函數循環中進行響應處理。
             }

           }
}


接下來我們要討論解析後我們數據存儲的問題,其實在資源比較足夠的情況下或者能夠擠出data區的情況下可以考慮用結構體,我們構造好相應結構體,將接收到的數據存儲進去,要應用的時候就十分方便。但這也有個矛盾,一般c51定義的結構體都被存儲在data區,一般通訊的字節量大空間必然不夠,存在一個矛盾,可以採用聯合體union進行存儲效果會好一點。當然也可以在保存數據時採用定義在xdata區(片外)的buffer來存儲。這樣在一定程序上優化了程序的執行效率,在程序處理立即拋出消息處理,提高了通訊數據的處理速度。對於通常資源比較豐富的系統,比如ARM上一般採取的做法是這樣的,將數據存在緩衝區,接收完一幀數據後再轉換成相應的數據結構,再進行分析、校驗。    

總體來說,這種採取狀態機實時解析串口通訊數據的方式在一定程序提高了程序運行效率,使軟件架構清晰明瞭,程序可擴展性大,有利於後續開發。以上是筆者的一點愚見,歡迎指教。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章