將上一節搭建的工程複製一份,命名爲「3.uart」。這一節主要講如何使用SAM4N的UART功能,實現串口的收發。編程
細心看數據手冊的朋友也許已經發現了,SAM4N有4個UART,還有3個USART哦,若是都配置成串口,那就足足有7個可用的串口了。也許不少人就疑惑了,UART和USART有啥區別啊?其實細節上我也不太懂有多少區別,看了數據手冊,大概就明白USART可用工做在SPI模式,可用使用硬件流控,可用設置不一樣數據位和中止位,功能比UART要強不少,UART不支持硬件流控,不支持SPI模式,不支持數據位和中止位編程。好了,下面咱就去試試UART是怎麼用的吧。函數
打開原理圖,可用看到有以下電路:工具
是的,這裏說明板子上的USB CDC虛擬串口設備鏈接在了SAM4N的PA10和PA9上,而這兩個正是UART0的UTXD和URXD。測試
經過上面這個表可用看出,UART0的URXD0是PA9的外設A功能,UTXD0是PA10的外設A功能。ui
要使用UART0,首先須要對它進行初始化配置,代碼以下:this
/**************************************************************************3d
* 函數名:UART0_Init()指針
* 參數 :uint32_t buadrate 波特率調試
* 返回值:voidblog
* 描述 :UART0初始化函數,在使用UART0前先調用
**************************************************************************/
void UART0_Init(uint32_t baudrate)
{
uint32_t Fdiv =0;
/*禁止外設管理控制寄存器(PMC)寫保護*/
PMC->PMC_WPMR = 0x504D4300;
/*使能UART1和PIOA時鐘*/
PMC->PMC_PCER0 = ((1UL << ID_PIOA) |
(1UL << ID_UART0) );
/*使能外設管理控制寄存器(PMC)寫保護*/
PMC->PMC_WPMR = 0x504D4301;
/*配置PA9爲UART0的RXD,PA10爲UART0的TXD*/
PIOA->PIO_IDR=(PIO_PA9A_URXD0|PIO_PA10A_UTXD0);
PIOA->PIO_PUDR=(PIO_PA9A_URXD0|PIO_PA10A_UTXD0);
PIOA->PIO_ABCDSR[0]&=~(PIO_PA9A_URXD0|PIO_PA10A_UTXD0);
PIOA->PIO_ABCDSR[1]&=~(PIO_PA9A_URXD0|PIO_PA10A_UTXD0);
PIOA->PIO_PDR=(PIO_PA9A_URXD0|PIO_PA10A_UTXD0);
/* 復位並禁止UART的發送和接收*/
UART0->UART_CR = UART_CR_RSTRX | UART_CR_RSTTX
| UART_CR_RXDIS | UART_CR_TXDIS;
/*配置UART0的波特率*/
Fdiv = (SystemCoreClock/ baudrate) /UART_MCK_DIV ;
if (Fdiv < UART_MCK_DIV_MIN_FACTOR || Fdiv > UART_MCK_DIV_MAX_FACTOR)
return ;
UART0->UART_BRGR=Fdiv;
/*定義數據位爲8bit,中止位爲1,校驗位爲NONE*/
UART0->UART_MR = UART_MR_PAR_NO|UART_MR_CHMODE_NORMAL;
/*禁止 DMA 通道 */
UART0->UART_PTCR = UART_PTCR_RXTDIS | UART_PTCR_TXTDIS;
/*使能UART接收和發送*/
UART0->UART_CR = UART_CR_RXEN | UART_CR_TXEN;
/*使能接收中斷*/
UART0->UART_IER=UART_IER_RXRDY;
/*配置UART0的先佔優先級爲1,從優先級爲1*/
NVIC_SetPriority(UART0_IRQn, ((0x01<<3)|0x01));
/*使能UART0的中斷通道*/
NVIC_EnableIRQ(UART0_IRQn);
}
第一步就是使能PIOA和UART0的時鐘,而後配置PIOA9和PIOA10鏈接到外設A功能,也就是URXD0和UTXD0功能,而後禁止PIOA9和PIOA10的GPIO功能,這樣PIOA9和PIOA10就配置成了URXD0和UTXD0。
接下來配置UART,首先復位UART0並禁止接收和發送,接着計算波特率分頻值,數據手冊給出以下計算公式,按照這個計算就好。
接下來配置UART的模式,這裏選擇普通模式,校驗位爲NONE,而後禁止DMA功能,由於沒有用DMA傳輸。
最後使能UART的收發,使能中斷,這樣算是完成了UART的配置了。
完成配置還不行,還須要一個接收和發送函數,代碼以下:
/**************************************************************************
* 函數名:UART0_Handler()
* 參數 :void
* 返回值:void
* 描述 :UART0中斷服務函數
**************************************************************************/
void UART0_Handler(void)
{
uint8_t temp;
if((UART0->UART_SR& UART_SR_RXRDY)==1)
{ //接收數據中斷
temp= UART0->UART_RHR&0xff; //接收一個字節
UART0_SendByte(temp); //將接收的數據發回
}
}
/*****************************************************************************
* 函數名:UART0_SendByte()
* 參數 :uint8_t c 要發送字符
* 返回值:void
* 描述 :UART0發送一個字符函數
**************************************************************************/
void UART0_SendByte(uint8_t c)
{
while((UART0->UART_SR & UART_SR_TXEMPTY) == 0); //等待發送緩衝器爲空
UART0->UART_THR=c; //將發送字符寫入發送保持寄存器
}
/******************************************************************************
* 函數名:UART0_SendString()
* 參數 :uint8_t *s 指向字符串的指針
* 返回值:void
* 描述 :UART0發送字符串函數
**************************************************************************/
void UART0_SendString(uint8_t *s)
{
while(*s) //判斷是否到字符串末尾
{
UART0_SendByte(*s); //發送指針當前所指的字節
s++; //地址加1
}
}
這裏咱們使用的中斷接收方式,由於接收的數據只是用來實驗是否有接收到,全部這裏是收到後再發回去。接收時要讀取UART狀態寄存器UART_SR的值,看UART_SR_RXRDY位是否被置位,若是置位說明有數據接收。發送時要先檢測UART的發送數據寄存器UART_THR是否是爲空。
好了,這樣就完成UART0的驅動了,接下來按這樣的方法去配置其餘UART就均可以用了。
接下來還須要去實現int fputc(int ch,FILE *f)這個函數,試printf的打印輸出到UART0去,這樣就能夠在程序中使用printf()函數打印消息了,代碼以下:
int fputc(int ch,FILE *f)
{
UART0_SendByte((uint8_t)ch); //發送1個字節
return ch; //返回 ch
}
在main.c中寫個簡單的測試程序,以下:
int main(void)
{
systick_hw_init();
led_hw_init();
UART0_Init(115200);
UART0_SendString("hello,this is demo for uart\r\n");
while(1){
printf("hello,I am SAM4N\r\n");
led_hw_on();
delay_ms(500);
led_hw_off();
delay_ms(500);
}
}
下載程序,打開串口調試工具,就能夠看到板子的串口輸出了,以下圖:
注意:使用printf須要把MicroLIB勾上,以下圖: