UART0串口編程系列(五)
一.串口接收數(shù)據(jù)在UC/OS設計中應注意的問題
1.串口通信的數(shù)據(jù)接收過程:
1>UART接收FIFO接收到預定字節(jié)后觸發(fā)中斷
2>ISR讀取接收到的內(nèi)容并保存
3>經(jīng)過一次或若干次ISR完成一個通信幀的接收(拼裝通信幀)
4>處理和解釋通信內(nèi)容
5>根據(jù)處理結果觸發(fā)其他任務
2.串口數(shù)據(jù)接收程序設計時,應該考慮的問題:
1>即使以上的操作過程很簡單,也最好不要把它全部安排在ISR中完成,如果放在一起的話,就會給UART0通信帶來危機(此處具體請看前面的文章)。
2>所以要安排一個與ISR關聯(lián)的“串口接收”任務來完成后面的工作。再創(chuàng)建一個幀緩沖區(qū)。在接收的過程中,將接收到的內(nèi)容寫入幀緩沖區(qū)。接收完一幀后,處理和解釋過程需要讀幀緩沖區(qū)的內(nèi)容。
3>將寫幀緩沖區(qū)的操作安排在ISR中完成,讀幀緩沖去的操作安排在串口接收任務中完成。
4>由于ISR和串口接收任務是并發(fā)程序單元,存在資源同步問題,故需要對幀緩沖區(qū)進行互斥訪問。
二.設計ISR與串口接收任務之間的通信方法:
1. ISR的主要功能是響應異步事件,該異步事件將觸發(fā)一系列操作。ISR設計的基本原則是:盡可能簡短。
2.ISR與關聯(lián)任務的通信方式有兩種類型:信號型和數(shù)據(jù)型。
1>當使用信號量進行通信時,ISR只完成發(fā)送信號量的工作,表示事件已經(jīng)發(fā)生,通過信號量的同步功能觸發(fā)關聯(lián)任務。
2>當使用數(shù)據(jù)進行通信時,ISR需要完成對異步事件的信息進行采集工作,然后使用消息郵箱(或消息隊列)將數(shù)據(jù)發(fā)送給關聯(lián)任務,由關聯(lián)任務完成后續(xù)數(shù)據(jù)處理工作。
3>做項目時常見的三種情況:
?觸發(fā)ISR的事件不包含數(shù)據(jù):不需要對事件進行信息采集。此時,ISR使用信號量與關聯(lián)任務進行通信。
?觸發(fā)ISR的事件是包含數(shù)據(jù)的低頻事件:將數(shù)據(jù)采集的工作放在關聯(lián)任務中完成,(產(chǎn)生的時刻延遲與采樣周期相比可以忽略不計,對采集數(shù)據(jù)的質(zhì)量沒有影響。此時,ISR使用信號量與關聯(lián)任務進行通信,從而簡化了ISR。
?觸發(fā)ISR的事件是包含數(shù)據(jù)的中高頻事件:數(shù)據(jù)采集的工作放在關聯(lián)任務中完成時,產(chǎn)生的時延與采樣周期相比不能忽略不計時,對采樣數(shù)據(jù)的質(zhì)量有影響。此時,關聯(lián)任務從消息郵箱中得到消息的數(shù)據(jù),并完成后續(xù)處理工作。
?觸發(fā)ISR的事件是包含數(shù)據(jù)的非周期高頻率事件:對于非周期高頻事件,其最短事件間隔可能小于一個事件數(shù)據(jù)處理的耗時,如果使用消息郵箱進行通信,就可能會出現(xiàn)數(shù)據(jù)丟失現(xiàn)象。此時,數(shù)據(jù)采集的工作應該在ISR中完成,由ISR使用具有數(shù)據(jù)緩沖功能的消息隊列與關聯(lián)任務進行通信。關聯(lián)任務從消息隊列中得到消息的數(shù)據(jù),并完成后續(xù)處理工作。
Tiger-John說明:
具體采用那一種方式來實現(xiàn)ISR與串口接收任務之間的通信要視具體情況而定。
以下用信號量和消息隊列兩種方式來實現(xiàn)串口接收編程
三.UC/OS串口接收數(shù)據(jù)編程
通過一個程序來分析UC/OS串口接收數(shù)據(jù)設計和實現(xiàn)
程序設計目標:
用串口中斷接收上位機發(fā)送的8字節(jié)數(shù)據(jù),再把它們傳送給上位機。
u用信號量的方式
1.系統(tǒng)有那些任務組成
1>啟動任務
2>接收任務
3>接收中斷服務例程
4>發(fā)送任務
2.各任務之間的關系
3.啟動任務流程:
l定義各種通信工具(例如:信號量)
l系統(tǒng)硬件初始化
l初始化UART0
l創(chuàng)建各個任務
l創(chuàng)建各種通信工具
l刪除自己
程序:
/********************************************************************
**Task0(啟動任務)
********************************************************************/
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)建接收任務
OSTaskCreate(Task2,(void *)0, &TaskStk2[TaskStkLengh - 1],5);//創(chuàng)建發(fā)送任務
OSTaskDel(OS_PRIO_SELF);//刪除自己
}
4.接收任務流程
l等待開始信號量
l處理和解釋通信內(nèi)容(本程序較簡單,不涉及)
程序:
/********************************************************************
Task1(接收任務)
********************************************************************/
void Task1(void *pdata)
{
uint8 err;
pdata = pdata;
while(1)
{
OSSemPend(Sem_StartFlag,0,&err);//等帶開始信號量
//以下可以根據(jù)具體業(yè)務來編寫處理和解釋通信內(nèi)容
}
}
5.串口中斷接收流程:
l關中斷
l清除串口中斷標志位
l清除中斷控制寄存器
l接收數(shù)據(jù)放入緩沖區(qū)
l開中斷
l發(fā)送發(fā)送信號量
程序:
/**********************************************************
*名稱:UART0_Exception
*功能:串口接收中斷
*入口參數(shù):無
*出口參數(shù):無
**********************************************************/
voidUART0_Exception(void)
{
uint8 i;
uint32 data;
OS_ENTER_CRITICAL();
data = U0IIR;//清除中斷表示寄存器標志
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ā)送任務流程
l等待發(fā)送信號量
l發(fā)送數(shù)據(jù)
l發(fā)送開始信號量
程序:
/**********************************************************
**Task2(發(fā)送任務)
**********************************************************/
void Task2(void *pdata)
{
uint8 i,err;
pdata = pdata;
while(1)
{
OSSemPend(Sem_SendFlag,0,&err);//等待發(fā)送信號量





