1、UART串口簡介
在單片機(jī)應(yīng)用開發(fā)中,串口可以說是最常用的外設(shè)之一了。
串口最重要的功能就是能夠讓單片機(jī)和外部設(shè)備進(jìn)行數(shù)據(jù)交互。例如在我們學(xué)習(xí)敏矽微電子的cortex m0時(shí),可以將開發(fā)板與電腦相連,通過串口調(diào)試助手來調(diào)試程序、觀察程序運(yùn)行結(jié)果。還有很多其他的串口模塊,比如藍(lán)牙、 NBIOT、GPRS、4G 等模組,都是使用的串口來進(jìn)行驅(qū)動(dòng)的,因此掌握串口是嵌入式工程師必備的技能。
接下來我們就來學(xué)習(xí)如何驅(qū)動(dòng)ME32F030上的串口。
在正式學(xué)習(xí)之前,我們先對(duì)UART串口的通信格式做一個(gè)了解。UART的全稱是:通用異步收發(fā)傳輸器(Universal Asynchronous Receiver/Transmitter)。串行傳輸數(shù)據(jù)是按照字節(jié)為單位進(jìn)行移位傳輸?shù)模虼送ㄐ潘俣容^低。但其擁有線路簡單、通信距離遠(yuǎn)的優(yōu)點(diǎn),使用兩條線即可實(shí)現(xiàn)雙向通信,一條用于發(fā)送,一條用于接收。因此在工業(yè)應(yīng)用中受到廣泛應(yīng)用。其通信格式也十分簡單,如下圖所示:
圖1 UART數(shù)據(jù)格式
空閑位:數(shù)據(jù)線在空閑狀態(tài)的時(shí)候保持高電平,表示沒有數(shù)據(jù)傳輸。
起始位:當(dāng)要傳輸數(shù)據(jù)的時(shí)候,數(shù)據(jù)線會(huì)被拉低,表示開始數(shù)據(jù)傳輸。
數(shù)據(jù)位:數(shù)據(jù)位就是實(shí)際要傳輸?shù)臄?shù)據(jù),一般都是按照字節(jié)傳輸數(shù)據(jù)的,即一次傳輸8 位數(shù)據(jù)的。一般都是低位在前,高位在后。當(dāng)然也有相反的傳輸協(xié)議,但平時(shí)很少會(huì)遇到。
奇偶校驗(yàn)位:這是對(duì)數(shù)據(jù)中“1”的位數(shù)進(jìn)行奇偶校驗(yàn)用的,可以根據(jù)需求進(jìn)行選擇。
停止位:數(shù)據(jù)傳輸完成標(biāo)志位,停止位的位數(shù)可以選擇 1 位、1.5 位或 2 位高電平,一般都選擇 1 位停止位。
波特率:波特率就是 UART 數(shù)據(jù)傳輸?shù)乃俾?,也就是每秒傳輸?shù)臄?shù)據(jù)位數(shù),一般選擇 9600、19200、115200 等。
隨著電腦日新月異的升級(jí)換代,現(xiàn)在很多電腦都不帶傳統(tǒng)的COM口,USB接口開始廣泛應(yīng)用。所以就有了USB轉(zhuǎn)串口芯片來解決這個(gè)難題,常用的U轉(zhuǎn)串芯片有CH340、PL2303 等。通過這些芯片就可以實(shí)現(xiàn)串口 TTL 轉(zhuǎn) USB。
ME32F030開發(fā)板使用的是PL2303 芯片來完成串口和電腦之間的連接,只需要一條USB 線即可。在使用前需要注意兩件事:第一,先下載并安裝PL2303的驅(qū)動(dòng)程序。第二,檢查開發(fā)板的USB跳線帽是否接到COM、USB這邊。
圖2 跳線連接
2、UART驅(qū)動(dòng)寄存器
ME32F030 提供2個(gè) UART 外設(shè):UART0,UART1。串行接口都支持紅外傳輸(IrDA)協(xié)議功能。時(shí)鐘都受 SYSAHBCLKCTRL 寄存器控制。同時(shí)每個(gè) UART 有獨(dú)立的時(shí)鐘分頻器來產(chǎn)生波特率,并使之不受系統(tǒng)時(shí)鐘和PCLK影響。UART對(duì)應(yīng)的管腳映射圖如下:
圖3 UART管腳映射
看完管腳的映射關(guān)系,接下來就列出與UART相關(guān)的寄存器組,隨后會(huì)挨個(gè)進(jìn)行講解。
圖4 UART寄存器
2-1 UART接收/發(fā)送緩沖寄存器
UART 接收/發(fā)送緩沖寄存器包含著 UART 接收到/將發(fā)送的字節(jié),接收到的數(shù)據(jù)和待發(fā)送的串口數(shù)據(jù)都在該寄存器中。
2-2 UART狀態(tài)寄存器
該寄存器用于提供 UART 接收發(fā)送緩存器的狀態(tài)。大致可以歸類為以下幾種狀態(tài):
發(fā)送狀態(tài):發(fā)送FIFO空、發(fā)送FIFO半滿、發(fā)送FIFO滿。
接收狀態(tài):接收FIFO空、接收FIFO半滿、接收FIFO滿。
奇偶校驗(yàn)狀態(tài):沒有奇偶校驗(yàn)錯(cuò)誤,或檢測(cè)到奇偶錯(cuò)誤,寫1來清除錯(cuò)誤標(biāo)志。
接收緩存器溢出狀態(tài) :用來表明緩存器是否溢出。
2-3 UART控制寄存器
接下來就要著重講解下UART控制寄存器了。0-5位屬于基本的接收、發(fā)送中斷使位,這里不再累述。
BIT6:奇偶校驗(yàn)中斷使能,使能該中斷后,當(dāng)接收到的數(shù)據(jù)發(fā)生奇偶校驗(yàn)錯(cuò)誤后,會(huì)產(chǎn)生中斷通知串口接收發(fā)生錯(cuò)誤。
BIT7:接收溢出中斷使能,使能該中斷后,當(dāng)接收到的數(shù)據(jù)超出FIFO容量就會(huì)產(chǎn)生中斷。通知及時(shí)取出數(shù)據(jù)或者清空FIFO。
BIT8:奇偶校驗(yàn)方式選擇位,0為偶校驗(yàn),1為奇校驗(yàn)。這里注意,這只是選擇了奇偶校驗(yàn)的方式,但是并不會(huì)生效,是否啟動(dòng)校驗(yàn)還需要下面介紹的寄存器。
BIT9:奇偶校驗(yàn)使能位,只有當(dāng)該位置1才會(huì)使能奇偶校驗(yàn),具體的校驗(yàn)方式由剛才介紹的奇偶校驗(yàn)方式選擇位來決定。
BIT10:IRDA傳輸協(xié)議使能位,置1使能。
BIT22:RX接收使能,置1使能。
BIT23:TX發(fā)送使能,置1使能。
2-4 UART中斷狀態(tài)寄存器
既然剛才在介紹UART控制寄存器的時(shí)候,介紹了不少中斷使能控制??隙ň蜁?huì)有相應(yīng)的中斷狀態(tài)的管理。UART中斷狀態(tài)寄存器從低位開始依次管理著:①、發(fā)送結(jié)束中斷狀態(tài),②、接收完成中斷狀態(tài),③、發(fā)送FIFO滿中斷,④、接收FIFO滿中斷,⑤、發(fā)送FIFO半滿中斷,⑥、接收FIFO半滿中斷,⑦、奇偶校驗(yàn)錯(cuò)誤中斷,⑧、接收溢出中斷。
2-5 UART 波特率分頻器寄存器
UART 波特率分頻器寄存器 (BAUDDIV) 用于時(shí)鐘分頻從而產(chǎn)生相應(yīng)的波特率。該寄存器可讀寫。該分頻器的時(shí)鐘源是由UARTnCLKDIV 控制 UART 的波特率源時(shí)鐘(SCLK)。
圖6 UART 波特率分頻器寄存器
波特率分頻值計(jì)算公式:
BAUDDIV = SCLK / UART BAUDRATE
2-6 UART TX/RX FIFO 數(shù)據(jù)清除寄存器
操作該寄存器可以快速對(duì)TX/RX FIFO進(jìn)行數(shù)據(jù)清空。
圖7 UART TX/RX FIFO 數(shù)據(jù)清除寄存器
3、UART驅(qū)動(dòng)函數(shù)
在例程LIB->common->Drivers->Source文件夾內(nèi)有uart.c文件,這個(gè)就是提供的UART驅(qū)動(dòng)文件,里面包含了一些基本的驅(qū)動(dòng)函數(shù),使用起來十分方便。下面會(huì)對(duì)每個(gè)函數(shù)進(jìn)行講解。
3-1 UART初始化
在每段源代碼的后面,筆者對(duì)其進(jìn)行一下注釋,方便大家快速掌握和使用這個(gè)函數(shù)。這個(gè)函數(shù)的4個(gè)參數(shù)的意義如下:
uart:要使能的UART模塊,可選UART0、UART1。
baudrate:要設(shè)置的串口的波特率。
parityoption:奇偶校驗(yàn)位,可選UART_EVEN_PARITY(奇校驗(yàn))、 UART_ODD_PARITY(偶校驗(yàn))、 UART_RX_NO_INT(無校驗(yàn))。
rxinttriggerlevel:接收中斷觸發(fā)條件。
void UART_Open(UART0_Type *uart, uint32_t baudrate, uint8_t parityoption, uint8_t rxinttriggerlevel)
{
uint32_t volatile delays;
if (uart==UART0)
{
//初始化時(shí)關(guān)閉UART0 IRQ
NVIC_DisableIRQ(UART0_IRQn);
//使能 UART0 時(shí)鐘
SYSCON->SYSAHBCLKCTRL_b.UART0_CLK=1; //enable UART0 PCLK
SYSCON->UART0CLKDIV_b.DIV = 0x1; /* divided by 1 */
//復(fù)位 UART0
SYSCON->PRESETCTRL_b.UART0_RST_N=0;
SYSCON->PRESETCTRL_b.UART0_RST_N=1;
}
else if (uart==UART1)
{
//初始化時(shí)關(guān)閉UART1 IRQ
NVIC_DisableIRQ(UART1_IRQn);
//使能 UART1 時(shí)鐘
SYSCON->SYSAHBCLKCTRL_b.UART1_CLK=1; //enable UART1 PCLK
SYSCON->UART1CLKDIV_b.DIV = 0x1; /* divided by 1 */
//復(fù)位 UART1
SYSCON->PRESETCTRL_b.UART1_RST_N=0;
SYSCON->PRESETCTRL_b.UART1_RST_N=1;
}
else return ;
//設(shè)置波特率
uart->BAUDDIV_b.BAUDDIV = MainClock/baudrate;
//設(shè)置奇偶校驗(yàn)
if (parityoption==UART_ODD_PARITY)
uart->CTRL_b.PARISEL=1;
if (parityoption!=UART_NO_PARITY)
uart->CTRL_b.PARIEN=1;
//設(shè)置中斷觸發(fā)條件
if (rxinttriggerlevel==UART_RX_NOT_EMPTY)
uart->CTRL_b.RXNEIE=1;
if (rxinttriggerlevel==UART_RX_HALF_FULL)
uart->CTRL_b.RXHLFIE=1;
if (rxinttriggerlevel==UART_RX_FULL)
uart->CTRL_b.RXFIE=1;
//使能發(fā)送和接收功能
uart->CTRL_b.TXEN=1;
uart->CTRL_b.RXEN=1;
//插入延時(shí)
SYS_DelaymS(1);
//清空 FIFO
uart->FIFOCLR=0xFF;
return;
}
3-2 UART關(guān)閉
這段函數(shù)用來關(guān)閉UART0或者UART1,只需要傳入需要關(guān)閉的串口即可。
void UART_Close(UART0_Type *uart)
{
if (uart==UART0)
{
//關(guān)閉UART0_IRQ
NVIC_DisableIRQ(UART0_IRQn);
//關(guān)閉UART0時(shí)鐘
SYSCON->SYSAHBCLKCTRL_b.UART0_CLK=0;
}else if (uart==UART1)
{
//關(guān)閉UART1_IRQ
NVIC_DisableIRQ(UART1_IRQn);
//關(guān)閉UART1時(shí)鐘
SYSCON->SYSAHBCLKCTRL_b.UART1_CLK=0;
}
else return ;
//關(guān)閉相應(yīng)UART的中斷,并清除中斷標(biāo)志
UART_DisableInt(uart);
UART_ClearIntFlag(uart);
return;
}
3-3 UART讀取單個(gè)字節(jié)
這段函數(shù)的作用是UART讀取單個(gè)字節(jié)的數(shù)據(jù)。
uint8_t UART_ByteRead(UART0_Type *uart, uint8_t *data)
{
if (uart->STATE_b.RXNE)
{
*data=uart->DATA;
return 0;
}
else
return 1;
}
3-4 UART連續(xù)讀取多個(gè)字節(jié)
UART連續(xù)讀取串口數(shù)據(jù),直到讀取到指定長度的數(shù)據(jù)。
void UART_Read(UART0_Type *uart, uint8_t * rxbuf, uint8_t *readbytes)
{
uint8_t temp=0;
//get all data
while ((uart->STATE_b.RXNE)&&((*readbytes)--))
{
*rxbuf++=uart->DATA;
temp++;
}
//return number of read
*readbytes=temp;
return;
}
3-5 UART發(fā)送單個(gè)字節(jié)
這段函數(shù)的作用是UART發(fā)送單個(gè)字節(jié)的數(shù)據(jù)。
uint8_t UART_ByteWrite(UART0_Type *uart, uint8_t data)
{
if (uart->STATE_b.TXF)
return 1;
uart->DATA=data;
return 0;
}
3-6 UART連續(xù)發(fā)送多個(gè)字節(jié)
UART連續(xù)發(fā)送串口數(shù)據(jù),直到發(fā)送完指定長度的數(shù)據(jù)。
void UART_Send(UART0_Type *uart, uint8_t * txbuf, uint32_t sendbytes)
{
while (sendbytes--)
{
while (uart->STATE_b.TXF);
uart->DATA=*txbuf++;
}
return;
}
3-7 UART發(fā)送字符串
UART發(fā)送一段字符串?dāng)?shù)據(jù),只需要將要發(fā)送的字符串?dāng)?shù)據(jù)首地址傳入即可。
void UART_PutString (UART0_Type *uart, uint8_t * str)
{
while (!(* str==''))
{
while (uart->STATE_b.TXF);
uart->DATA=*str++;
}
return;
}
3-8 UART使能中斷
有兩個(gè)參數(shù)項(xiàng),第一個(gè)是選擇需要使能的UART,第二個(gè)選擇觸發(fā)中斷的條件。
void UART_EnableInt(UART0_Type *uart, uint32_t intcon)
{
uart->CTRL |= intcon;
return;
}
3-9 UART關(guān)閉中斷
調(diào)用該函數(shù)后,所有的串口的中斷觸發(fā)條件都將關(guān)閉。
void UART_DisableInt(UART0_Type *uart)
{
uart->CTRL &= 0xFFFFFF00;
return;
}
4、串口中斷例程
介紹完UART常用的驅(qū)動(dòng)函數(shù),接下來用個(gè)小例程來演示下UART的驅(qū)動(dòng)。測(cè)試程序的功能是:通過串口助手發(fā)送一個(gè)字節(jié)的數(shù)據(jù)到單片機(jī),單片機(jī)收到該數(shù)據(jù)后,將該數(shù)據(jù)通過單片機(jī)的串口發(fā)送到串口助手。
程序設(shè)計(jì)思路
首先是對(duì)UART0端口的初始化,將IO口復(fù)用為串口UART0的TX、RX功能。
隨后將UART0初始化為波特率115200,無奇偶校驗(yàn),接收非空觸發(fā)中斷。
下一步就是使能UART0的中斷,中斷觸發(fā)條件為接收FIFO非空。
最后使能UART0_IRQn中斷服務(wù)子程序。
測(cè)試程序的代碼如下:
int main(void)
{
//UART0 端口初始化
PA_2_INIT(PA_2_TX0);
PA_3_INIT(PA_3_RX0);
//UART0 寄存器初始化
UART_Open(UART0,115200,UART_NO_PARITY,UART_RX_NOT_EMPTY);
UART_EnableInt(UART0,UART_RX_NOT_EMPTY);
NVIC_EnableIRQ(UART0_IRQn);
while(1)
{
}
}
//UART0 中斷服務(wù)子程序
void UART0_IRQHandler(void)
{
uint8_t cdata;
//判斷中斷狀態(tài)位
if (UART0->INTSTATUS_b.RXNEINT )
{
cdata = UART0->DATA; //將接收到的數(shù)據(jù)返回
UART0->DATA=cdata;
}
//清除中斷狀態(tài)
UART0->INTSTATUS = 0x0F;
}
程序調(diào)試
編寫完程序,首先要在編譯環(huán)境下進(jìn)行編譯、連接。沒有錯(cuò)誤后(最好連警告也沒有)。就可以實(shí)際連接到電路板進(jìn)行程序調(diào)試運(yùn)行了。
在實(shí)驗(yàn)前需要先確定U轉(zhuǎn)串所使用的的串口號(hào),通過windows的設(shè)備管理器中的端口(COM和LPT)查看我們的串口,比如本例中是COM7。
圖8 串口端口號(hào)選擇
接下來打開串口上位機(jī)工具,本例使用的是“大傻串口工具”。按照程序中設(shè)置的串口參數(shù)配置好串口。端口選擇COM7,波特率115200,數(shù)據(jù)位8位,無奇偶校驗(yàn),1位停止位。最后點(diǎn)擊打開串口即可。打開后如圖所示:
圖9 串口配置
上位機(jī)環(huán)境配置好之后,接下里就可以下載并仿真程序了。首先我們?cè)赨ART0_IRQ中斷子程序中位置打上斷點(diǎn)。隨后全速運(yùn)行程序。
圖10 仿真界面
然后我們?cè)谏衔粰C(jī)發(fā)送一個(gè)數(shù)據(jù)進(jìn)行測(cè)試,例如發(fā)送一個(gè)字節(jié)0x11。這時(shí)候單片機(jī)便會(huì)進(jìn)入串口中斷服務(wù)程序,并且停止在斷點(diǎn)處。這時(shí)候我們聽過watch窗口看到接收的數(shù)據(jù),就是0x11。
圖11 數(shù)據(jù)發(fā)送
繼續(xù)單步運(yùn)行并退出中斷服務(wù)程序,這時(shí)候我們?cè)偃タ瓷衔粰C(jī),發(fā)現(xiàn)收到了單片機(jī)返回的數(shù)據(jù)。
圖12 數(shù)據(jù)接收
-
單片機(jī)
+關(guān)注
關(guān)注
6040文章
44606瀏覽量
637244 -
GPRS
+關(guān)注
關(guān)注
21文章
984瀏覽量
129540 -
uart
+關(guān)注
關(guān)注
22文章
1243瀏覽量
101587 -
串口通信
+關(guān)注
關(guān)注
34文章
1627瀏覽量
55630
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論