UART0串口編程(三)
一:中斷方式的串口編程
1.用中斷方式編寫串口程序由那幾部分組成
2.硬件上的支持
1>UART0 發(fā)送FIFO緩沖區(qū)
A.UART0含有1個16字節(jié)的發(fā)送FIFO緩沖區(qū)
B.U0THR是UART0發(fā)送FIFO的最高字節(jié)
C.UART的發(fā)送FIFO是一直使能的
2>UART0接收FIFO緩沖區(qū)
A. UART0含有一個16字節(jié)的接收FIFO緩沖區(qū)。
B.?軟件設(shè)置接收FIFO緩沖區(qū)的觸發(fā)字節(jié)。
3> 中斷接口:UART0的中斷接口包含中斷使能寄存器(U0IER)和中斷標(biāo)識寄存器(U0IIR)。
第一:U0IIR:提供狀態(tài)碼用于指示一個掛起中斷的中斷源和優(yōu)先級。
第二:U0IER可以控制UART0的4個中斷源。
4> UART0有4個中斷源:
A. RLS(接收線狀態(tài))中斷:
(1) 優(yōu)先級最高
(2) 它在以下條件發(fā)生時產(chǎn)生錯誤
第一:幀錯誤(FE)
第二:溢出錯誤(OE)
第三:奇偶錯誤(PE)
第四:間隔中斷(BI)
注:可以通過查看U0LSR[4:1]中的值看到產(chǎn)生該中斷的錯誤條件,讀取U0LSR寄存器時清除該中斷。
B. RDA(接收數(shù)據(jù)可用)中斷:
(1)與CTI中斷并列第二優(yōu)先級。
(2)在以下情況觸發(fā)中斷:
第一:當(dāng)接收的有效數(shù)據(jù)到達(dá)接收FIFO設(shè)置寄存器(U0FCR)中設(shè)置的觸發(fā)點(diǎn)時,RDA被激活。當(dāng)接收FIFO中的有效數(shù)據(jù)少于觸發(fā)點(diǎn)時,RDA復(fù)位。
第二:中斷過程:
1> ?移位寄存器(U0RSR)從RxD引腳接收串行數(shù)據(jù)后,送入接收FIFO中
2> ?當(dāng)接收FIFO中的有效數(shù)據(jù)數(shù)量達(dá)到預(yù)定的觸發(fā)點(diǎn)時,置位RDA中斷。
3> ?從U0RBR寄存器中讀取FIFO中最早到達(dá)的數(shù)據(jù),當(dāng)FIFO中的有效數(shù)據(jù)小于觸發(fā)點(diǎn)時,清零RDA中斷。
C. ?CTI(字符超時指示)中斷
(1) 優(yōu)先級為2.
(2) 在以下情況發(fā)生中斷:
當(dāng)接收FIFO中的有效數(shù)據(jù)少于預(yù)定的觸發(fā)點(diǎn)數(shù)量時,如果在一定時間內(nèi)仍沒有接收到新的數(shù)據(jù),那將觸發(fā)該中斷。
(3) 上面的時間指的是:3.5~4.5個字節(jié)所需要的時間。
(4) ?對接收FIFO的任何操作都會清零該中斷標(biāo)志。
(5) 中斷過程:
第一:移位寄存器(U0RSR)從RxD0引腳接收串行數(shù)據(jù)后,送入接收FIFO中。
第二:當(dāng)接收FIFO中的有效數(shù)據(jù)少于觸發(fā)個數(shù),但如果長時間沒有數(shù)據(jù)到達(dá),則觸發(fā)CTI中斷。
第三:從U0RBR中讀取接收FIFO中的數(shù)據(jù),或者有新的數(shù)據(jù)送入接收FIFO,都將清零CTI中斷。
注:3.5~4.5個字節(jié)的時間:指在串口當(dāng)前的波特率下,發(fā)送3.5~4.5個字節(jié)所需要的時間。
當(dāng)接收FIFO中存放多個數(shù)據(jù),從U0RBR讀取數(shù)據(jù),但是沒有讀完所有數(shù)據(jù),那么在經(jīng)過3.5~4.5個字節(jié)的時間后觸發(fā)CTI中斷。
D. ?THRE(發(fā)送)中斷
(1) 優(yōu)先級為第三級優(yōu)先級。
(2) 當(dāng)FIFO為空并且在以下情況觸發(fā)中斷:
第一:系統(tǒng)啟動時,雖然發(fā)送FIFO為空,但不會產(chǎn)生THRE中斷。
第二:在上一次發(fā)生THRE中斷后,向發(fā)送FIFO中寫入1個字節(jié)數(shù)據(jù),將在一個字節(jié)加上一個停止位后發(fā)生THRE中斷
(because:如果發(fā)送移位寄存器為空,那么寫入發(fā)送FIFO的數(shù)據(jù)將直接進(jìn)入發(fā)送移位寄存器。此時發(fā)送FIFO仍然為空,如果立即產(chǎn)生THRE中斷,就會影響緊接著寫入發(fā)送FIFO的數(shù)據(jù)。所以在發(fā)送完該一個字節(jié)以及一個停止位后,才產(chǎn)生THRE中斷。)
如果在發(fā)送FIFO中有過兩個字節(jié)以上的數(shù)據(jù),但是現(xiàn)在發(fā)送FIFO為空時,將立即觸發(fā)THRE中斷。當(dāng)THRE中斷為當(dāng)前有效的最高優(yōu)先級中斷時,往U0THR寫數(shù)或者對U0IIR的讀操作,將使THRE中斷復(fù)位
我們來看看這些中斷源與存儲器之間的關(guān)系:
注:由上圖可知:UART0有4個中斷源:分別是RLS(線狀態(tài))中斷,RDA(接收數(shù)據(jù))中斷,CTI(字符超時)中斷,THRE(發(fā)送數(shù)據(jù))中斷。4個中斷源的優(yōu)先級如下圖所示:
?
3.串口中斷接收初始化
1>串口中斷接收初始化流程
l ?設(shè)置I/O引腳連接到UART0
l ?置位除數(shù)鎖存位,配置UART0幀數(shù)據(jù)格式
l ?根據(jù)波特率計算分頻值
l ?設(shè)置波特率
l ?清除除數(shù)鎖存位,并設(shè)置工作模式
l ?使能FIFO,并設(shè)置觸發(fā)點(diǎn)
l ?允許RBR中斷
注:我們可以發(fā)現(xiàn)與輪訓(xùn)方式相比,中斷方式只是增加了使能FIFO,并設(shè)置中斷觸發(fā)點(diǎn)和允許RBR中斷兩步。
2>中斷串口初始化需要配置的寄存器
?????(與輪循方式配置方法相同的寄存器在此處不在涉及)
l ?U0FCR(FIFO控制寄存器):U0FCR控制UART0 Rx和Tx FIFO的操作。
l ?U0IER(中斷使能寄存器):U0IER用于使能4個UART0中斷源。
3>具體寄存器的配置
(1) U0FCR
A作用:控制UART0 Rx和Tx的操作。
B長度:8位寄存器。
C:每一位的含義:
l ?第0位:表示FIFO使能
置1:表示使能對UART0 Rx和Tx的FIFO以及U0FCR[7:1]的訪問。
置0:表示不能使用Rx和Tx的FIFO以及步能對U0FCR[7:1]的訪問。
注:該位的任何變化都將使UART0 FIFO清空。
l ?第1位:表示Rx FIFO的復(fù)位。
置1:會清零UART0 RxFIFO中的所有字節(jié)并復(fù)位指針邏輯。該位自動清零。
l ?第2位:表示Tx FIFO的復(fù)位。
置1:會清零UART0 TxFIFO中的所有字節(jié)并復(fù)位指針邏輯。改位自動清零。
l ?第[5:3]位:保留位,用戶不能對其進(jìn)行操作。從保留位讀出的值未被定義。
l ?第[7:6]位:表示Rx觸發(fā)選擇
00:觸發(fā)點(diǎn)為0(默認(rèn)為1字節(jié))
01:觸發(fā)點(diǎn)為1(默認(rèn)為4字節(jié))
10:觸發(fā)點(diǎn)為2(默認(rèn)為8字節(jié))
11: 觸發(fā)點(diǎn)為3(默認(rèn)為14字節(jié))
注:這兩個位決定在激活中斷之前,接收UART0 FIFO必須寫入個字符。
(2) U0IER(中斷使能寄存器)
A 作用:U0IER用于使能4個UART0中斷源
B 長度:8位寄存器
C每一位的含義:
l ?第0位:表示RBR中斷使能
置1:使能RDA中斷
置0:禁止RDA中斷
注:U0IEER 第零位使能UART0接收數(shù)據(jù)可用中斷。它還控制(CTI)字符接收超時中斷。
l ?第1位:表示THRE中斷使能
置1:使能THRE中斷
置0:禁止THRE中斷
l ?第2位:表示Rx線狀態(tài)中斷使能
置1:使能Rx線狀態(tài)中斷
置0:禁止RX線狀態(tài)中斷
注:U0IER第二位使能UART0 Rx線狀態(tài)中斷。該中斷的狀態(tài)可從U0LSR[4:1]讀出
l ?第[7:3]位:是保留位
注:用戶不能向其寫入1.
4>串口初始化程序:void ??UART0_Init(uint32 bps)
4. ?中斷初始化
先來看一下UART0和VIC之間的關(guān)系:
1>中斷初始化流程:
l ?選擇中斷為向量中斷或快速中斷
l ?分配中斷通道
l ?設(shè)置UART0向量地址
l ?使能UART0中斷
2>關(guān)于ARM中斷編程方法和寄存器的使用在此不做涉及(如果想知道的話,可以看這篇文章http://blog.csdn.net/tigerjb/archive/2010/11/30/6045409.aspx
3>中斷初始化程序:void Interrupt_Init (void)
5.用中斷編寫接收函數(shù)
1> ?中斷服務(wù)函數(shù)流程
l ?清除串口中斷標(biāo)識寄存器(U0IIR)
l ?清除中斷標(biāo)志
l ?讀取接收FIFO中的數(shù)據(jù)
2> ?中斷函數(shù)服務(wù)函數(shù)中需要配置的寄存器
(1) U0IIR中斷標(biāo)識寄存器。
l ?第0位:表示中斷掛起
置1:表示沒有掛起的中斷
置0:表示至少有一個中斷掛起
l ?第[3:1]位:中斷標(biāo)識,這三位表示了對應(yīng)UART0 Rx FIFO的中斷。
001:表示發(fā)送中斷(THRE)
010: ?表示接收數(shù)據(jù)可用中斷(RDA)
011: ?表示接收線狀態(tài)中斷(RLS)
110: ?表示字符超時中斷(CTI)
l ?第[7:4]:是保留位
注:
1. ???U0IIR提供的狀態(tài)碼可用于指示一個掛起中斷的中斷源和優(yōu)先級。
2. ???在訪問U0IIR過程中,中斷被凍結(jié)
3. ???如果在訪問U0IIR時,產(chǎn)生了中斷,該中斷被記錄。在下次訪問U0IIR時可以讀出,避免中斷的丟失。
3> ?中斷服務(wù)函數(shù)程序:void ??__irq IRQ_UART0(void)
6. 總程序:通過上位機(jī)給串口發(fā)送8字節(jié)數(shù)據(jù),ARM2200接收到串口數(shù)據(jù)后,把數(shù)據(jù)又發(fā)送回上位機(jī)。
(在用中斷的時候在Startup.S文件中的InitStack子程序中,修改設(shè)置系統(tǒng)模式堆棧處的代碼為"MSR CPSR_c,#0x5f", 測試成功 ,在上面上發(fā)送16進(jìn)制數(shù)時,每個之間用空格隔開不加前綴。)
#include "config.h"
uint8 recver_buffer[8];
uint8 rcv_new;
/**********************************************************
* 名稱: UART0_Init()
* 功能: UART0初始化(通訊波特率115200,8位數(shù)據(jù)位,1位停止位,無奇偶校驗)
* 入口參數(shù): bps 串口波特率
* 出口參數(shù): 無
**********************************************************/
void UART0_Init(uint32 bps)
{ uint16 Fdiv;PINSEL0 = 0x00000005; //設(shè)置串口引腳U0LCR = 0x83; //置為除數(shù)鎖存位,進(jìn)行配置Fdiv = (Fpclk >> 4) / bps; // 設(shè)置波特率U0DLM = Fdiv >> 8; U0DLL = Fdiv & 0xff; U0LCR = 0x03; //清除除數(shù)鎖存位,并設(shè)置工作模式模式U0FCR = 0x81; // 使能FIFO,并設(shè)置觸發(fā)點(diǎn)為8字節(jié)U0IER = 0x01; // 允許RBR中斷,即接收中斷}
/*********************************************************
* 名 稱: IRQ_UART0
* 功 能: 串口UART0中斷接收8個字節(jié)的數(shù)據(jù)
* 入口參數(shù): 無
* 出口參數(shù): 無
**********************************************************/
void __irq IRQ_UART0(void)
{ uint8 i;if( 0x04 == (U0IIR&0x0F) ) {rcv_new = 1; // 設(shè)置接收到新的數(shù)據(jù)標(biāo)志,并清除中斷標(biāo)志位for(i=0; i<8; i++){recver_buffer[i] = U0RBR; // 讀取FIFO的數(shù)據(jù)}VICVectAddr = 0;} //清除中斷
}
/**********************************************************
* 名稱: Interrupt_Init
* 功能: 初始化串口中斷,給串口中斷選擇為向量中斷,
* 分配向量通道號1給串口
* 入口參數(shù): 無
* 出口參數(shù): 無
**********************************************************/
void Interrupt_Init (void)
{VICIntSelect = 0x00000000; // 設(shè)置所有通道為IRQ中斷VICVectCntl0 = 0x26; // UART0中斷通道分配到IRQ slot 0,即優(yōu)先級最高VICVectAddr0 = (int)IRQ_UART0; // 設(shè)置UART0向量地址VICIntEnable = 0x00000040; // 使能UART0中斷}
/**********************************************************
* 名 稱: UART0_SendByte
* 功 能: 向串口發(fā)送字節(jié)數(shù)據(jù),并等待發(fā)送完畢。
* 入口參數(shù): data 要發(fā)送的數(shù)據(jù)
* 出口參數(shù): 無
**********************************************************/
void UART0_SendByte(uint8 data)
{U0THR = data; while(0 == (U0LSR & 0x40));
}
/**********************************************************
* 名稱: UART0_SendBuf()
* 功能: 通過串口發(fā)送一幀數(shù)據(jù)
* 入口參數(shù): *buffer 存放一幀數(shù)據(jù)
* 出口參數(shù): 無
**********************************************************/
void UART0_SendBuf(uint8 *buffer)
{uint8 *pbuffer;uint8 i;for(pbuffer = buffer,i = 0;i < 8; i++)UART0_SendByte(*(pbuffer++));
}/**********************************************************
* 名稱: main()函數(shù)
* 功能: 上位機(jī)接收的數(shù)據(jù)開頭兩個字符為0x10,0x11,
* 則原樣輸出,否次輸出0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27
* 入口參數(shù): *buffer 存放一幀數(shù)據(jù)
* 出口參數(shù): 無
**********************************************************/int main (void)
{ uint8 send_buffer[8] ={0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27}; //定義發(fā)送幀緩沖區(qū)UART0_Init(115200);Interrupt_Init();while(1){if(1 == rcv_new) // 是否已經(jīng)接收到8 Bytes的數(shù)據(jù){ rcv_new = 0; // 清除標(biāo)志if(0x10 ==recver_buffer[0] && 0x11 == recver_buffer[1]){UART0_SendBuf(send_buffer);}else{UART0_SendBuf(recver_buffer);}} } return 0;
}
二.用中斷編寫發(fā)送函數(shù) 1.中斷初始化 同上和用中斷接收函數(shù)時的中斷初始化是一樣的2.串口初始化 ?1>串口初始化流程: l ?設(shè)置I/O引腳連接到UART0 l ?置位除數(shù)鎖存位,配置UART0幀格式 l ?根據(jù)波特率計算分頻值 l ?設(shè)置波特率 l ?清除除數(shù)鎖存位,并設(shè)置工作模式 l ?使能FIFO,并使TxFIFO復(fù)位 l ?使能THRE中斷 ? 2>串口初始化函數(shù):void ? UART0_Init(uint32 bps)3.中斷服務(wù)函數(shù): ? 1>中斷服務(wù)函數(shù)流程: l ?清除串口中斷標(biāo)識寄存器 l ?清除中斷控制標(biāo)識寄存器 ? 2>中斷發(fā)送服務(wù)函數(shù)程序:void ? __irq IRQ_UART0(void)4.用串口中斷發(fā)送函數(shù)的總程序:通過上位機(jī)給串口發(fā)送8字節(jié)數(shù)據(jù),ARM2200接收到串口數(shù)據(jù)后,用中斷方式把數(shù)據(jù)又發(fā)送回上位機(jī)。
#include "config.h"
uint8 recver_buffer[8];
uint8 rcv_new;
/****************************************************************************
* 名稱: UART0_Init
* 功能: UART0初始化 通訊波特率115200,8位數(shù)據(jù)位,1位停止位,無奇偶校驗
* 使能TxFIFO,和THRE中斷
* 入口參數(shù): bps 串口波特率
* 出口參數(shù): 無
****************************************************************************/
void UART0_Init(uint32 bps)
{uint16 Fdiv;PINSEL0 = (PINSEL0 & ~(0xf) | 0x05) ; //設(shè)置UART0的引腳U0LCR = 0x83; //置位除數(shù)鎖存位,配置UART0幀格式Fdiv = (Fpclk>>4)/bps; //根據(jù)波特率計算分頻值U0DLM = Fdiv>>8; //設(shè)置波特率U0DLL = Fdiv%256;U0LCR = 0x03; // 清除除數(shù)鎖存位,并設(shè)置工作模式U0FCR = 0x05; // 使能TxFIFO,并使TxFIFO復(fù)位U0IER = 0x02; // 使能THRE中斷}
/****************************************************************************
* 名 稱: UART0_Exception
* 功 能: 串口發(fā)送中斷
* 入口參數(shù): 無
* 出口參數(shù): data 發(fā)送的數(shù)據(jù)
****************************************************************************/
void __irq IRQ_UART0(void)
{ uint32 data;data = U0IIR; //清除中斷表示寄存器標(biāo)志VICVectAddr = 0; //清除中斷}
/**********************************************************
* 名稱: Interrupt_Init
* 功能: 初始化串口中斷,給串口中斷選擇為向量中斷,
* 分配向量通道號1給串口
* 入口參數(shù): 無
* 出口參數(shù): 無
**********************************************************/
void Interrupt_Init (void)
{VICIntSelect = 0x00000000; // 設(shè)置所有通道為IRQ中斷VICVectCntl0 = 0x26; // UART0中斷通道分配到IRQ slot 0,即優(yōu)先級最高VICVectAddr0 = (int)IRQ_UART0; // 設(shè)置UART0向量地址VICIntEnable = 0x00000040; // 使能UART0中斷}
/**********************************************************
* 名 稱: UART0_RcvByte
* 功 能: 用查詢方式接收一字節(jié)的數(shù)據(jù)
* 入口參數(shù): 無
* 出口參數(shù): data 要接收的數(shù)據(jù)
**********************************************************/
uint8 UART0_RcvByte(void)
{uint8 rcv_data ;while((U0LSR&0X01)==0); //等待數(shù)據(jù)到達(dá)rcv_data = U0RBR; //從U0RBR中讀出接收到的數(shù)據(jù)return rcv_data; //返回接收到的數(shù)據(jù)}
/**********************************************************
* 名稱: UART0_RecBuf()
* 功能: 接收串口發(fā)送過來的幀數(shù)據(jù),
* 入口參數(shù): *buffer 存放一幀數(shù)據(jù)
* 出口參數(shù): 無
**********************************************************/
void UART0_RecBuf (uint8 *buffer)
{uint8 *pbuffer;uint8 i;for(pbuffer = buffer, i = 0;i < 8; i++){*(pbuffer++) = UART0_RcvByte();}
}
/**********************************************************
* 名稱: main()函數(shù)
* 功能: 上位機(jī)接收的數(shù)據(jù)開頭兩個字符為0x10,0x11,
* 則原樣輸出,否次輸出0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27
* 入口參數(shù): *buffer 存放一幀數(shù)據(jù)
* 出口參數(shù): 無
**********************************************************/int main (void)
{ uint8 i; uint8 send_buffer[8] ={0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27}; //定義發(fā)送幀緩沖區(qū)UART0_Init(115200);Interrupt_Init();while(1){UART0_RecBuf(recver_buffer); //接收8字節(jié)數(shù)據(jù)if(0x10 ==recver_buffer[0] && 0x11 == recver_buffer[1]){ for(i = 0;i < 8 ;i++){U0THR = send_buffer[i]; //用中斷發(fā)送每次8字節(jié)} }else{for(i = 0;i < 8;i++) //用中斷發(fā)送每次8字節(jié){U0THR = recver_buffer[i];}} } return 0;
}
《新程序員》:云原生和全面數(shù)字化實踐 50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀
總結(jié)
以上是生活随笔 為你收集整理的UART0串口编程(三):中断方式的串口编程;用中断编写发送函数 的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔 推薦給好友。