UART0串口編程系列(五)
一.串口接收數(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>即使以上的操作過程很簡(jiǎn)單,也最好不要把它全部安排在ISR中完成,如果放在一起的話,就會(huì)給UART0通信帶來危機(jī)(此處具體請(qǐng)看前面的文章)。
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ā)程序單元,存在資源同步問題,故需要對(duì)幀緩沖區(qū)進(jìn)行互斥訪問。
二.設(shè)計(jì)ISR與串口接收任務(wù)之間的通信方法:
1. ISR的主要功能是響應(yīng)異步事件,該異步事件將觸發(fā)一系列操作。ISR設(shè)計(jì)的基本原則是:盡可能簡(jiǎn)短。
2.ISR與關(guān)聯(lián)任務(wù)的通信方式有兩種類型:信號(hào)型和數(shù)據(jù)型。
1>當(dāng)使用信號(hào)量進(jìn)行通信時(shí),ISR只完成發(fā)送信號(hào)量的工作,表示事件已經(jīng)發(fā)生,通過信號(hào)量的同步功能觸發(fā)關(guān)聯(lián)任務(wù)。
2>當(dāng)使用數(shù)據(jù)進(jìn)行通信時(shí),ISR需要完成對(duì)異步事件的信息進(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ù):不需要對(duì)事件進(jìn)行信息采集。此時(shí),ISR使用信號(hào)量與關(guān)聯(lián)任務(wù)進(jìn)行通信。
?觸發(fā)ISR的事件是包含數(shù)據(jù)的低頻事件:將數(shù)據(jù)采集的工作放在關(guān)聯(lián)任務(wù)中完成,(產(chǎn)生的時(shí)刻延遲與采樣周期相比可以忽略不計(jì),對(duì)采集數(shù)據(jù)的質(zhì)量沒有影響。此時(shí),ISR使用信號(hào)量與關(guān)聯(lián)任務(wù)進(jìn)行通信,從而簡(jiǎn)化了ISR。
?觸發(fā)ISR的事件是包含數(shù)據(jù)的中高頻事件:數(shù)據(jù)采集的工作放在關(guān)聯(lián)任務(wù)中完成時(shí),產(chǎn)生的時(shí)延與采樣周期相比不能忽略不計(jì)時(shí),對(duì)采樣數(shù)據(jù)的質(zhì)量有影響。此時(shí),關(guān)聯(lián)任務(wù)從消息郵箱中得到消息的數(shù)據(jù),并完成后續(xù)處理工作。
?觸發(fā)ISR的事件是包含數(shù)據(jù)的非周期高頻率事件:對(duì)于非周期高頻事件,其最短事件間隔可能小于一個(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ù)處理工作。
Tiger-John說明:
具體采用那一種方式來實(shí)現(xiàn)ISR與串口接收任務(wù)之間的通信要視具體情況而定。
以下用信號(hào)量和消息隊(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用信號(hào)量的方式
1.系統(tǒng)有那些任務(wù)組成
1>啟動(dòng)任務(wù)
2>接收任務(wù)
3>接收中斷服務(wù)例程
4>發(fā)送任務(wù)
2.各任務(wù)之間的關(guān)系
3.啟動(dòng)任務(wù)流程:
l定義各種通信工具(例如:信號(hào)量)
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ā)送信號(hào)量
Sem_StartFlag=OSSemCreate(1);//創(chuàng)建開始信號(hào)量
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等待開始信號(hào)量
l處理和解釋通信內(nèi)容(本程序較簡(jiǎn)單,不涉及)
程序:
/********************************************************************
Task1(接收任務(wù))
********************************************************************/
void Task1(void *pdata)
{
uint8 err;
pdata = pdata;
while(1)
{
OSSemPend(Sem_StartFlag,0,&err);//等帶開始信號(hào)量
//以下可以根據(jù)具體業(yè)務(wù)來編寫處理和解釋通信內(nèi)容
}
}
5.串口中斷接收流程:
l關(guān)中斷
l清除串口中斷標(biāo)志位
l清除中斷控制寄存器
l接收數(shù)據(jù)放入緩沖區(qū)
l開中斷
l發(fā)送發(fā)送信號(hào)量
程序:
/**********************************************************
*名稱:UART0_Exception
*功能:串口接收中斷
*入口參數(shù):無
*出口參數(shù):無
**********************************************************/
voidUART0_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ā)送信號(hào)量
}
6.發(fā)送任務(wù)流程
l等待發(fā)送信號(hào)量
l發(fā)送數(shù)據(jù)
l發(fā)送開始信號(hào)量
程序:
/**********************************************************
**Task2(發(fā)送任務(wù))
**********************************************************/
void Task2(void *pdata)
{
uint8 i,err;
pdata = pdata;
while(1)
{
OSSemPend(Sem_SendFlag,0,&err);//等待發(fā)送信號(hào)量