UART0串口编程(六):串口(UART0)之UC/OS(二)UC/OS下的串口接收任务编程
串口(UART0)之UC/OS(二)
一.串口接收數據在UC/OS設計中應注意的問題
1. ???串口通信的數據接收過程:
1> ?UART 接收FIFO接收到預定字節后觸發中斷
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使用具有數據緩沖功能的消息隊列與關聯任務進行通信。關聯任務從消息隊列中得到消息的數據,并完成后續處理工作。
注意:具體采用那一種方式來實現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));}?
?
?
總結
以上是生活随笔為你收集整理的UART0串口编程(六):串口(UART0)之UC/OS(二)UC/OS下的串口接收任务编程的全部內容,希望文章能夠幫你解決所遇到的問題。
                            
                        - 上一篇: UART0串口编程(五):串口编程(UA
 - 下一篇: QT5中实现多窗口切换,并从子窗口返回数