2010-06-11 98 views
2

考慮以下代碼我的微控制器單元(MCU)上運行:如何接收MCU串口上的數據包?

while(1){ 

do_stuff; 
if(packet_from_PC) 
    send_data_via_gpio(new_packet); //send via general purpose i/o pins 
else 
    send_data_via_gpio(default_packet); 
do_other_stuff; 

} 

該MCU經由UART.Whenever也連接到PC,PC機將數據發送到MCU,所述new_packet被髮送, 否則發送default_packet.每個分組可以是5個或更多個字節,並具有預定義的分組結構。

我的問題是:

1.Should我使用UART interrut服務程序(ISR)內接收來自PC的整個數據包?在這種情況下,我必須在ISR內部實現一個狀態機 來組裝數據包(if-else或switch-case塊可能會很長)。

    OR 

2.具有PC機發送某種請求命令(一個字節)的,檢測它在我的ISR設置一個標誌,禁止UART單獨中斷和我同時(1)循環通過檢查形成的包對於標誌和輪詢UART?在這種情況下,在整個數據包形成後,在while(1)循環中,UART中斷將被重新啓用。

回答

1

這些不是唯一的兩種選擇,第二種選擇似乎不理想。

我的第一種方法是對一個簡單的循環隊列,並從ISR中將字節壓入,並從主循環中讀取字節。這樣你就可以擁有一個小而簡單的ISR,並且可以在主循環中執行處理而不會禁止中斷。

假設您可以對ISR進行合理編碼,第一種選擇是可能的。處理構造數據包時,您可能希望超時;你需要能夠在你的ISR中正確處理。這取決於線速度,MCU的速度以及您需要做什麼。

更新:

在ISR中做它肯定是合理的。然而,使用循環隊列非常簡單,在你的一攬子技巧中使用標準實現。這是一個循環隊列實現;讀者和作者可以獨立運作。

#ifndef ARRAY_ELEMENTS 
#define ARRAY_ELEMENTS(x) (sizeof(x)/sizeof(x[0])) 
#endif 

#define QUEUE_DEFINE(name, queue_depth, type) \ 
     struct queue_type__##name { \ 
      volatile size_t m_in; \ 
      volatile size_t m_out; \ 
      type m_queue[queue_depth]; \ 
     } 

#define QUEUE_DECLARE(name) struct queue_type__##name name 

#define QUEUE_SIZE(name) ARRAY_ELEMENTS((name).m_queue) 

#define QUEUE_CALC_NEXT(name, i) \ 
     (((name).i == (QUEUE_SIZE(name) - 1)) ? 0 : ((name).i + 1)) 

#define QUEUE_INIT(name) (name).m_in = (name).m_out = 0 

#define QUEUE_EMPTY(name) ((name).m_in == (name).m_out) 

#define QUEUE_FULL(name) (QUEUE_CALC_NEXT(name, m_in) == (name).m_out) 

#define QUEUE_NEXT_OUT(name) ((name).m_queue + (name).m_out) 
#define QUEUE_NEXT_IN(name) ((name).m_queue + (name).m_in) 

#define QUEUE_PUSH(name) ((name).m_in = QUEUE_CALC_NEXT((name), m_in)) 
#define QUEUE_POP(name) ((name).m_out = QUEUE_CALC_NEXT((name), m_out)) 

使用方法如下:

QUEUE_DEFINE(bytes_received, 64, unsigned char); 
QUEUE_DECLARE(bytes_received); 

void isr(void) 
{ 
    /* Move the received byte into 'c' */ 
    /* This code enqueues the byte, or drops it if the queue is full */ 
    if (!QUEUE_FULL(bytes_received)) { 
     *QUEUE_NEXT_IN(bytes_received) = c; 
     QUEUE_PUSH(bytes_received); 
    } 
} 

void main(void) 
{ 
    QUEUE_INIT(bytes_received); 

    for (;;) { 
     other_processing(); 
     if (!QUEUE_EMPTY(bytes_received)) { 
      unsigned char c = *QUEUE_NEXT_OUT(bytes_received); 
      QUEUE_POP(bytes_received); 
      /* Use c as you see fit ... */ 
     } 
    } 
} 
+0

我想我的第一選擇。在程序中,環形緩衝區看起來像是很多工作中的頭部/尾部簿記... 我在主循環中沒有做太多計算。 MCU的時鐘頻率爲4MHz,線路波特率爲9600bps – itisravi 2010-06-11 12:07:52