UART0串口编程(六):串口(UART0)之UC/OS(二)UC/OS下的串口接收任务编程
串口(UART0)之UC/OS(二)
一.串口接收數(shù)據(jù)在UC/OS設(shè)計(jì)中應(yīng)注意的問題
1. ???串口通信的數(shù)據(jù)接收過程:
1> ?UART 接收FIFO接收到預(yù)定字節(jié)后觸發(fā)中斷
2> ?ISR讀取接收到的內(nèi)容并保存
3> ?經(jīng)過一次或若干次ISR完成一個(gè)通信幀的接收(拼裝通信幀)
4> ?處理和解釋通信內(nèi)容
5> ?根據(jù)處理結(jié)果觸發(fā)其他任務(wù)
2. ???串口數(shù)據(jù)接收程序設(shè)計(jì)時(shí),應(yīng)該考慮的問題:
1>即使以上的操作過程很簡單,也最好不要把它全部安排在ISR中完成,如果放在一起的話,就會(huì)給UART0通信帶來危機(jī)(此處具體請看前面的文章)。
2>所以要安排一個(gè)與ISR關(guān)聯(lián)的“串口接收”任務(wù)來完成后面的工作。再創(chuàng)建一個(gè)幀緩沖區(qū)。在接收的過程中,將接收到的內(nèi)容寫入幀緩沖區(qū)。接收完一幀后,處理和解釋過程需要讀幀緩沖區(qū)的內(nèi)容。
3>將寫幀緩沖區(qū)的操作安排在ISR中完成,讀幀緩沖去的操作安排在串口接收任務(wù)中完成。
4>由于ISR和串口接收任務(wù)是并發(fā)程序單元,存在資源同步問題,故需要對幀緩沖區(qū)進(jìn)行互斥訪問。
二.設(shè)計(jì)ISR與串口接收任務(wù)之間的通信方法:
1. ISR的主要功能是響應(yīng)異步事件,該異步事件將觸發(fā)一系列操作。ISR設(shè)計(jì)的基本原則是:盡可能簡短。
2.ISR與關(guān)聯(lián)任務(wù)的通信方式有兩種類型:信號型和數(shù)據(jù)型。
1>當(dāng)使用信號量進(jìn)行通信時(shí),ISR只完成發(fā)送信號量的工作,表示事件已經(jīng)發(fā)生,通過信號量的同步功能觸發(fā)關(guān)聯(lián)任務(wù)。
2>當(dāng)使用數(shù)據(jù)進(jìn)行通信時(shí),ISR需要完成對異步事件的信息進(jìn)行采集工作,然后使用消息郵箱(或消息隊(duì)列)將數(shù)據(jù)發(fā)送給關(guān)聯(lián)任務(wù),由關(guān)聯(lián)任務(wù)完成后續(xù)數(shù)據(jù)處理工作。
3>做項(xiàng)目時(shí)常見的三種情況:
? ?觸發(fā)ISR的事件不包含數(shù)據(jù):不需要對事件進(jìn)行信息采集。此時(shí),ISR使用信號量與關(guān)聯(lián)任務(wù)進(jìn)行通信。
? ?觸發(fā)ISR的事件是包含數(shù)據(jù)的低頻事件:將數(shù)據(jù)采集的工作放在關(guān)聯(lián)任務(wù)中完成,(產(chǎn)生的時(shí)刻延遲與采樣周期相比可以忽略不計(jì),對采集數(shù)據(jù)的質(zhì)量沒有影響。此時(shí),ISR使用信號量與關(guān)聯(lián)任務(wù)進(jìn)行通信,從而簡化了ISR。
? ?觸發(fā)ISR的事件是包含數(shù)據(jù)的中高頻事件:數(shù)據(jù)采集的工作放在關(guān)聯(lián)任務(wù)中完成時(shí),產(chǎn)生的時(shí)延與采樣周期相比不能忽略不計(jì)時(shí),對采樣數(shù)據(jù)的質(zhì)量有影響。此時(shí),關(guān)聯(lián)任務(wù)從消息郵箱中得到消息的數(shù)據(jù),并完成后續(xù)處理工作。
? ?觸發(fā)ISR的事件是包含數(shù)據(jù)的非周期高頻率事件:對于非周期高頻事件,其最短事件間隔可能小于一個(gè)事件數(shù)據(jù)處理的耗時(shí),如果使用消息郵箱進(jìn)行通信,就可能會(huì)出現(xiàn)數(shù)據(jù)丟失現(xiàn)象。此時(shí),數(shù)據(jù)采集的工作應(yīng)該在ISR中完成,由ISR使用具有數(shù)據(jù)緩沖功能的消息隊(duì)列與關(guān)聯(lián)任務(wù)進(jìn)行通信。關(guān)聯(lián)任務(wù)從消息隊(duì)列中得到消息的數(shù)據(jù),并完成后續(xù)處理工作。
注意:具體采用那一種方式來實(shí)現(xiàn)ISR與串口接收任務(wù)之間的通信要視具體情況而定。
以下用信號量和消息隊(duì)列兩種方式來實(shí)現(xiàn)串口接收編程
三. ??UC/OS串口接收數(shù)據(jù)編程
通過一個(gè)程序來分析UC/OS串口接收數(shù)據(jù)設(shè)計(jì)和實(shí)現(xiàn)
程序設(shè)計(jì)目標(biāo):
用串口中斷接收上位機(jī)發(fā)送的8字節(jié)數(shù)據(jù),再把它們傳送給上位機(jī)。
u 用信號量的方式
1.系統(tǒng)有那些任務(wù)組成
1> ?啟動(dòng)任務(wù)
2> ?接收任務(wù)
3> ?接收中斷服務(wù)例程
4> ?發(fā)送任務(wù)
2.各任務(wù)之間的關(guān)系
?
3.啟動(dòng)任務(wù)流程:
l ?定義各種通信工具(例如:信號量)
l ?系統(tǒng)硬件初始化
l ?初始化UART0
l ?創(chuàng)建各個(gè)任務(wù)
l ?創(chuàng)建各種通信工具
l ?刪除自己
?
程序:
?
/********************************************************************** Task0(啟動(dòng)任務(wù))********************************************************************/void Task0 (void *pdata){pdata = pdata; TargetInit(); //硬件初始化 UART0_Init(115200); //初始化串口Sem_SendFlag = OSSemCreate(0); //創(chuàng)建發(fā)送信號量Sem_StartFlag = OSSemCreate(1); //創(chuàng)建開始信號量OSTaskCreate(Task1,(void *)0, &TaskStk1[TaskStkLengh - 1],4); //創(chuàng)建接收任務(wù)OSTaskCreate(Task2,(void *)0, &TaskStk2[TaskStkLengh - 1],5); //創(chuàng)建發(fā)送任務(wù)OSTaskDel(OS_PRIO_SELF); //刪除自己 }?
?
4.接收任務(wù)流程
?
?
l ?等待開始信號量
l ?處理和解釋通信內(nèi)容(本程序較簡單,不涉及)
程序:
?
/********************************************************************Task1(接收任務(wù))********************************************************************/void Task1 (void *pdata){uint8 err;pdata = pdata;while(1){OSSemPend(Sem_StartFlag,0,&err); //等帶開始信號量//以下可以根據(jù)具體業(yè)務(wù)來編寫處理和解釋通信內(nèi)容}}?
?
5.串口中斷接收流程:
?
?
l ?關(guān)中斷
l ?清除串口中斷標(biāo)志位
l ?清除中斷控制寄存器
l ?接收數(shù)據(jù)放入緩沖區(qū)
l ?開中斷
l ?發(fā)送發(fā)送信號量
?
程序:
?
/*********************************************************** 名 稱: UART0_Exception* 功 能: 串口接收中斷* 入口參數(shù): 無* 出口參數(shù): 無**********************************************************/void UART0_Exception(void){uint8 i;uint32 data;OS_ENTER_CRITICAL();data = U0IIR; //清除中斷表示寄存器標(biāo)志VICVectAddr = 0; //清除中斷for(i=0; i<8; i++){rcv_buf[i] = U0RBR; // 讀取FIFO的數(shù)據(jù)}OS_EXIT_CRITICAL();OSSemPost(Sem_SendFlag); //發(fā)送發(fā)送信號量}?
?
6.發(fā)送任務(wù)流程
?
?
l ?等待發(fā)送信號量
l ?發(fā)送數(shù)據(jù)
l ?發(fā)送開始信號量
?
程序:
?
/************************************************************ Task2(發(fā)送任務(wù))**********************************************************/void Task2 (void *pdata){uint8 i,err;pdata = pdata;while(1){OSSemPend(Sem_SendFlag,0,&err); //等待發(fā)送信號量for(i = 0;i < 8; i++)UART0_SendByte(rcv_buf[i]); //通過輪訓(xùn)方式來發(fā)送串口數(shù)據(jù)OSSemPost(Sem_StartFlag); //發(fā)送開始信號量} }?
?
發(fā)送數(shù)據(jù)函數(shù):
?
?
?
/*********************************************************** 名 稱: UART0_SendByte* 功 能: 向串口發(fā)送字節(jié)數(shù)據(jù),并等待發(fā)送完畢。* 入口參數(shù): data 要發(fā)送的數(shù)據(jù)* 出口參數(shù): 無**********************************************************/void UART0_SendByte(uint8 data){U0THR = data; while(0 == (U0LSR & 0x40));}?
u 用消息隊(duì)列接收數(shù)據(jù)的方式
?
1. ???系統(tǒng)有那些任務(wù)組成
1>啟動(dòng)任務(wù)
2>接收任務(wù)(中調(diào)用一個(gè)接受處理函數(shù))
3>接收中斷服務(wù)例程
4>發(fā)送任務(wù)
2. ???各任務(wù)之間的關(guān)系
?
?
3.啟動(dòng)任務(wù)流程:
l ?定義各種通信工具(例如:信號量)
l ?系統(tǒng)硬件初始化
l ?初始化UART0
l ?創(chuàng)建各個(gè)任務(wù)
l ?創(chuàng)建各種通信工具
l ?刪除自己
?
程序:
?
/********************************************************************Task0(啟動(dòng)任務(wù))********************************************************************/void Task0 (void *pdata){pdata = pdata; TargetInit(); //硬件初始化 UART0_Init(115200); //初始化串口Sem_SendFlag = OSSemCreate(0); //創(chuàng)建發(fā)送信號量Sem_StartFlag = OSSemCreate(1); //創(chuàng)建開始信號量ReMsg_Qeue = OSQCreate(&MsgGrp_Buf[0],10); //創(chuàng)建消息隊(duì)列OSTaskCreate(Task1,(void *)0, &TaskStk1[TaskStkLengh - 1],4); //創(chuàng)建接收任務(wù)OSTaskCreate(Task2,(void *)0, &TaskStk2[TaskStkLengh - 1],5); //創(chuàng)建發(fā)送任務(wù)OSTaskDel(OS_PRIO_SELF); //刪除自己}?
?
4.接收任務(wù)流程
?
?
l ?等待開始信號量
l ?處理接收數(shù)據(jù)
l ?發(fā)送發(fā)送信號量
?
程序:
?
/********************************************************************** Task1(接收任務(wù))********************************************************************/void Task1 (void *pdata){uint8 err;pdata = pdata;while(1){OSSemPend(Sem_StartFlag,0,&err); //等待開始信號量UART0_RcvData(rcv_buf,2); //接收數(shù)據(jù)OSSemPost(Sem_SendFlag); //發(fā)送發(fā)送信號量}}?
?
處理接收數(shù)據(jù)函數(shù):
?
?
?
/********************************************************************* 名 稱: Rcv_Data* 功 能: rcv_buf:接收中斷返回后的數(shù)據(jù) count :控制中斷次數(shù)* 入口參數(shù): 無* 出口參數(shù): 無********************************************************************/void UART0_RcvData(uint8 *rcv_buf,uint8 count){uint8 i;uint8 j;uint32 rcv_data;uint8 err;for(j = 0;j < count;j++){//等待消息隊(duì)列rcv_data = (uint32)(uint32 *)OSQPend(ReMsg_Qeue,0,&err);if(0x11223344 == rcv_data) {rcv_data = 0x12345678;} //將每條消息分解為4字節(jié),存入幀緩沖區(qū)for(i = 0;i < 4;i++){rcv_buf[4*j+3-i] = (uint8)(rcv_data&0xff);rcv_data >>= 8;}}}?
?
5.串口中斷接收流程:
?
?
l ?關(guān)中斷
l ?清除串口中斷標(biāo)志位
l ?清除中斷控制寄存器
l ?接收4字節(jié)數(shù)據(jù)拼裝成32為地址
l ?發(fā)送消息郵箱
l ?開中斷
?
程序:
?
/********************************************************************* 名 稱: UART0_Exception* 功 能: 串口接收中斷* 入口參數(shù): 無* 出口參數(shù): 無********************************************************************/void UART0_Exception(void){uint8 i;uint32 data;OS_ENTER_CRITICAL();data = U0IIR; //清除中斷表示寄存器標(biāo)志VICVectAddr = 0; //清除中斷for(i = 0;i < 4;i++){data = (data << 8) | U0RBR; //將接受四字節(jié)數(shù)據(jù)拼裝成32位地址}if(0x00000000 == data){data = 0x11223344; //防止00000000地址不能發(fā)送}OSQPost(ReMsg_Qeue,(void *)data); //發(fā)送該地址到消息郵箱OS_EXIT_CRITICAL();}?
?
6.發(fā)送任務(wù)流程
?
?
l ?等待發(fā)送信號量
l ?發(fā)送數(shù)據(jù)
l ?發(fā)送開始信號量
?
?
程序:
?
/************************************************************ Task2(發(fā)送任務(wù))**********************************************************/void Task2 (void *pdata){uint8 i,err;pdata = pdata;while(1){OSSemPend(Sem_SendFlag,0,&err); //等待發(fā)送信號量for(i = 0;i < 8; i++)UART0_SendByte(rcv_buf[i]); //通過輪訓(xùn)方式來發(fā)送串口數(shù)據(jù)OSSemPost(Sem_StartFlag); //發(fā)送開始信號量} }?
?
發(fā)送數(shù)據(jù)函數(shù):
?
?
?
/*********************************************************** 名 稱: UART0_SendByte* 功 能: 向串口發(fā)送字節(jié)數(shù)據(jù),并等待發(fā)送完畢。* 入口參數(shù): data 要發(fā)送的數(shù)據(jù)* 出口參數(shù): 無**********************************************************/void UART0_SendByte(uint8 data){U0THR = data; while(0 == (U0LSR & 0x40));}?
?
?
總結(jié)
以上是生活随笔為你收集整理的UART0串口编程(六):串口(UART0)之UC/OS(二)UC/OS下的串口接收任务编程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: UART0串口编程(五):串口编程(UA
- 下一篇: QT5中实现多窗口切换,并从子窗口返回数