UART0串口編程系列(五)

(UART0) UC/OS (二)

 

---------------------------------------------------------編程

Author             :tiger-john
WebSite            :blog.csdn.net/tigerjb
併發

Email               jibo.tiger@gmail.comapp

Update-Time   : 2011129日星期六異步

Tiger聲明:本人鄙視直接複製本人文章而不加出處的我的或團體,但不排斥別人轉載tiger-john的文章,只是請您註明出處並和本人聯繫或留言給我3Q函數

---------------------------------------------------------工具

 

 

一.串口接收數據在UC/OS設計中應注意的問題ui

1.    串口通訊的數據接收過程:spa

1>  UART 接收FIFO接收到預約字節後觸發中斷.net

2>  ISR讀取接收到的內容並保存設計

3>  通過一次或若干次ISR完成一個通訊幀的接收(拼裝通訊幀)

4>  處理和解釋通訊內容

5>  根據處理結果觸發其餘任務

2.    串口數據接收程序設計時,應該考慮的問題:

1>即便以上的操做過程很簡單,也最好不要把它所有安排在ISR中完成,若是放在一塊兒的話,就會給UART0通訊帶來危機(此處具體請看前面的文章)。

2>因此要安排一個與ISR關聯的「串口接收任務來完成後面的工做。再建立一個幀緩衝區。在接收的過程當中,將接收到的內容寫入幀緩衝區。接收完一幀後,處理和解釋過程須要讀幀緩衝區的內容。

3>將寫幀緩衝區的操做安排在ISR中完成,讀幀緩衝去的操做安排在串口接收任務中完成。

4>因爲ISR和串口接收任務是併發程序單元,存在資源同步問題,故須要對幀緩衝區進行互斥訪問。

二.設計ISR與串口接收任務之間的通訊方法:

1. ISR的主要功能是響應異步事件,該異步事件將觸發一系列操做。ISR設計的基本原則是:儘量簡短。

2.ISR與關聯任務的通訊方式有兩種類型:信號型和數據型。

1>當使用信號量進行通訊時,ISR只完成發送信號量的工做,表示事件已經發生,經過信號量的同步功能觸發關聯任務。

2>當使用數據進行通訊時,ISR須要完成對異步事件的信息進行採集工做,而後使用消息郵箱(或消息隊列)將數據發送給關聯任務,由關聯任務完成後續數據處理工做。

3>作項目時常見的三種狀況:

Ø  觸發ISR的事件不包含數據:不須要對事件進行信息採集。此時,ISR使用信號量與關聯任務進行通訊。

Ø  觸發ISR的事件是包含數據的低頻事件:將數據採集的工做放在關聯任務中完成,(產生的時刻延遲與採樣週期相比能夠忽略不計,對採集數據的質量沒有影響。此時,ISR使用信號量與關聯任務進行通訊,從而簡化了ISR

Ø  觸發ISR的事件是包含數據的中高頻事件:數據採集的工做放在關聯任務中完成時,產生的時延與採樣週期相比不能忽略不計時,對採樣數據的質量有影響。此時,關聯任務從消息郵箱中獲得消息的數據,並完成後續處理工做。

Ø  觸發ISR的事件是包含數據的非週期高頻率事件:對於非週期高頻事件,其最短事件間隔可能小於一個事件數據處理的耗時,若是使用消息郵箱進行通訊,就可能會出現數據丟失現象。此時,數據採集的工做應該在ISR中完成,由ISR使用具備數據緩衝功能的消息隊列與關聯任務進行通訊。關聯任務從消息隊列中獲得消息的數據,並完成後續處理工做。

Tiger-John說明:

具體採用那一種方式來實現ISR與串口接收任務之間的通訊要視具體狀況而定。

如下用信號量和消息隊列兩種方式來實現串口接收編程

 

三.   UC/OS串口接收數據編程

經過一個程序來分析UC/OS串口接收數據設計和實現

程序設計目標:

用串口中斷接收上位機發送的8字節數據,再把它們傳送給上位機。

u 用信號量的方式

1.系統有那些任務組成

1>  啓動任務

2>  接收任務

3>  接收中斷服務例程

4>  發送任務

2.各任務之間的關係

 

 

 

3.啓動任務流程:

l  定義各類通訊工具(例如:信號量)

l  系統硬件初始化

l  初始化UART0

l  建立各個任務

l  建立各類通訊工具

l  刪除本身

 

 

 

程序:

/********************************************************************

**                            Task0(啓動任務)

********************************************************************/

void Task0    (void *pdata)

{

       pdata = pdata;              

       TargetInit();                         //硬件初始化                                                

       UART0_Init(115200);                 //初始化串口

       Sem_SendFlag   =  OSSemCreate(0);  //建立發送信號量

       Sem_StartFlag  =  OSSemCreate(1);   //建立開始信號量

       OSTaskCreate(Task1,(void *)0, &TaskStk1[TaskStkLengh - 1],4);  //建立接收任務

       OSTaskCreate(Task2,(void *)0, &TaskStk2[TaskStkLengh - 1],5);  //建立發送任務

       OSTaskDel(OS_PRIO_SELF);           //刪除本身

      

}

4.接收任務流程

l  等待開始信號量

l  處理和解釋通訊內容(本程序較簡單,不涉及)

 

 

程序:

/********************************************************************

                           Task1(接收任務)

********************************************************************/

void Task1     (void *pdata)

{

uint8 err;

pdata = pdata;

while(1)

        {

               OSSemPend(Sem_StartFlag,0,&err);  //等帶開始信號量

               //如下能夠根據具體業務來編寫處理和解釋通訊內容

                       

        }

}

5.串口中斷接收流程:

l  關中斷

l  清除串口中斷標誌位

l  清除中斷控制寄存器

l  接收數據放入緩衝區

l  開中斷

l  發送發送信號量

 

 

程序:

/**********************************************************

*     稱:           UART0_Exception

*     能:           串口接收中斷

* 入口參數:          

* 出口參數:       

**********************************************************/

void  UART0_Exception(void)

{

       uint8 i;

       uint32 data;

       OS_ENTER_CRITICAL();

       data = U0IIR;                            //清除中斷表示寄存器標誌

       VICVectAddr = 0;                         //清除中斷

        for(i=0; i<8; i++)

          {

             rcv_buf[i] = U0RBR;        // 讀取FIFO的數據

          }

   OS_EXIT_CRITICAL();

    OSSemPost(Sem_SendFlag);          //發送發送信號量

}

6.發送任務流程

l  等待發送信號量

l  發送數據

l  發送開始信號量

程序:

/**********************************************************

**                            Task2(發送任務)

**********************************************************/

void Task2    (void *pdata)

{

       uint8 i,err;

       pdata = pdata;

       while(1)

       {

              OSSemPend(Sem_SendFlag,0,&err);       //等待發送信號量

              for(i = 0;i < 8; i++)

              UART0_SendByte(rcv_buf[i]);    //經過輪訓方式來發送串口數據

              OSSemPost(Sem_StartFlag);           //發送開始信號量

       }                   

}

 

發送數據函數:

 

/**********************************************************

*     稱:            UART0_SendByte

*     能:            向串口發送字節數據,並等待發送完畢。

* 入口參數:            data              要發送的數據

* 出口參數:           

**********************************************************/

void   UART0_SendByte(uint8 data)

{

              U0THR = data;                

              while(0 == (U0LSR & 0x40));

}

u 用消息隊列接收數據的方式

1.    系統有那些任務組成

1>啓動任務

2>接收任務(中調用一個接受處理函數)

3>接收中斷服務例程

4>發送任務

2.    各任務之間的關係

3.啓動任務流程:

l  定義各類通訊工具(例如:信號量)

l  系統硬件初始化

l  初始化UART0

l  建立各個任務

l  建立各類通訊工具

l  刪除本身

程序:

/********************************************************************

                           Task0(啓動任務)

********************************************************************/

void Task0    (void *pdata)

{

pdata = pdata;              

TargetInit();                            //硬件初始化                                               

UART0_Init(115200);                    //初始化串口

Sem_SendFlag   =  OSSemCreate(0);     //建立發送信號量

Sem_StartFlag  =  OSSemCreate(1);      //建立開始信號量

ReMsg_Qeue = OSQCreate(&MsgGrp_Buf[0],10);    //建立消息隊列

OSTaskCreate(Task1,(void *)0, &TaskStk1[TaskStkLengh - 1],4); //建立接收任務

OSTaskCreate(Task2,(void *)0, &TaskStk2[TaskStkLengh - 1],5); //建立發送任務

OSTaskDel(OS_PRIO_SELF);                           //刪除本身

      

}

4.接收任務流程

l  等待開始信號量

l  處理接收數據

l  發送發送信號量

 

 

程序:

/********************************************************************

**                            Task1(接收任務)

********************************************************************/

void Task1    (void *pdata)

{

       uint8 err;

       pdata = pdata;

       while(1)

              {

                     OSSemPend(Sem_StartFlag,0,&err);  //等待開始信號量

                  UART0_RcvData(rcv_buf,2);        //接收數據

                  OSSemPost(Sem_SendFlag);         //發送發送信號量

              }

}

處理接收數據函數

/********************************************************************

*     稱:           Rcv_Data

*     能:           rcv_buf:接收中斷返回後的數據   count :控制中斷次數

* 入口參數:          

* 出口參數:          

********************************************************************/

void UART0_RcvData(uint8 *rcv_buf,uint8 count)

{

       uint8 i;

       uint8 j;

       uint32 rcv_data;

       uint8 err;

       for(j = 0;j < count;j++)

              {

                     //等待消息隊列

                     rcv_data = (uint32)(uint32 *)OSQPend(ReMsg_Qeue,0,&err);

                     if(0x11223344 == rcv_data)                     

                            {

                                   rcv_data = 0x12345678;

                            }     

                     //將每條消息分解爲4字節,存入幀緩衝區

                     for(i = 0;i < 4;i++)

                            {

                                   rcv_buf[4*j+3-i] = (uint8)(rcv_data&0xff);

                                    rcv_data >>= 8;

                            }

      

             }

} 

5.串口中斷接收流程:

l  關中斷

l  清除串口中斷標誌位

l  清除中斷控制寄存器

l  接收4字節數據拼裝成32爲地址

l  發送消息郵箱

l  開中斷

程序:

/********************************************************************

*     稱:           UART0_Exception

*     能:           串口接收中斷

* 入口參數:          

* 出口參數:     

********************************************************************/

void  UART0_Exception(void)

{

       uint8 i;

       uint32 data;

       OS_ENTER_CRITICAL();

       data = U0IIR;                                                 //清除中斷表示寄存器標誌

       VICVectAddr = 0;                                       //清除中斷

    for(i = 0;i < 4;i++)

       {

              data = (data << 8) | U0RBR;        //將接受四字節數據拼裝成32位地址

       }

   if(0x00000000 == data)

   {

           data = 0x11223344;                 //防止00000000地址不能發送

   }

   OSQPost(ReMsg_Qeue,(void *)data);          //發送該地址到消息郵箱

   OS_EXIT_CRITICAL();

 }

6.發送任務流程

l  等待發送信號量

l  發送數據

l  發送開始信號量

程序:

/**********************************************************

**                            Task2(發送任務)

**********************************************************/

void Task2    (void *pdata)

{

       uint8 i,err;

       pdata = pdata;

       while(1)

       {

              OSSemPend(Sem_SendFlag,0,&err);       //等待發送信號量

              for(i = 0;i < 8; i++)

              UART0_SendByte(rcv_buf[i]);    //經過輪訓方式來發送串口數據

              OSSemPost(Sem_StartFlag);           //發送開始信號量

       }                   

}

 

發送數據函數:

/**********************************************************

*     稱:            UART0_SendByte

*     能:            向串口發送字節數據,並等待發送完畢。

* 入口參數:            data              要發送的數據

* 出口參數:           

**********************************************************/

void   UART0_SendByte(uint8 data)

{

              U0THR = data;                

              while(0 == (U0LSR & 0x40));

}

相關文章
相關標籤/搜索