一板网
发表于: 2015-6-3 08:48:04 | 显示全部楼层

一、准备工作:

将上一节搭建的工程复制一份,命名为“3.uart”。这一节主要讲如何使用SAM4N的UART功能,实现串口的收发。

二、程序编写:

细心看数据手册的朋友也许已经发现了,SAM4N有4个UART,还有3个USART哦,如果都配置成串口,那就足足有7个可用的串口了。也许很多人就疑惑了,UART和USART有啥区别啊?其实细节上我也不太懂有多少区别,看了数据手册,大概就明白USART可用工作在SPI模式,可用使用硬件流控,可用设置不同数据位和停止位,功能比UART要强很多,UART不支持硬件流控,不支持SPI模式,不支持数据位和停止位编程。好了,下面咱就去试试UART是怎么用的吧。


打开原理图,可用看到有如下电路:

29143551-0836a6d795494d438901f9a29e886313.png


是的,这里说明板子上的USB CDC虚拟串口设备连接在了SAM4N的PA10和PA9上,而这两个正是UART0的UTXD和URXD。

29143551-aa43740f12c1435cb0b60da3636392ac.png


通过上面这个表可用看出,UART0的URXD0是PA9的外设A功能,UTXD0是PA10的外设A功能。


要使用UART0,首先需要对它进行初始化配置,代码如下:



  1. /**************************************************************************

  2. * 函数名:UART0_Init()

  3. * 参数  :uint32_t buadrate 波特率

  4. * 返回值:void

  5. * 描述  :UART0初始化函数,在使用UART0前先调用

  6. **************************************************************************/

  7. void UART0_Init(uint32_t baudrate)

  8. {

  9.   uint32_t Fdiv =0;

  10. /*禁止外设管理控制寄存器(PMC)写保护*/

  11.   PMC->PMC_WPMR = 0x504D4300;

  12.   /*使能UART1和PIOA时钟*/

  13.   PMC->PMC_PCER0 = ((1UL << ID_PIOA) |  

  14.                     (1UL << ID_UART0) );

  15. /*使能外设管理控制寄存器(PMC)写保护*/

  16.   PMC->PMC_WPMR = 0x504D4301;

  17.   /*配置PA9为UART0的RXD,PA10为UART0的TXD*/

  18. PIOA->PIO_IDR=(PIO_PA9A_URXD0|PIO_PA10A_UTXD0);

  19. PIOA->PIO_PUDR=(PIO_PA9A_URXD0|PIO_PA10A_UTXD0);

  20. PIOA->PIO_ABCDSR[0]&=~(PIO_PA9A_URXD0|PIO_PA10A_UTXD0);

  21. PIOA->PIO_ABCDSR[1]&=~(PIO_PA9A_URXD0|PIO_PA10A_UTXD0);

  22. PIOA->PIO_PDR=(PIO_PA9A_URXD0|PIO_PA10A_UTXD0);

  23. /* 复位并禁止UART的发送和接收*/

  24. UART0->UART_CR = UART_CR_RSTRX | UART_CR_RSTTX

  25. | UART_CR_RXDIS | UART_CR_TXDIS;

  26. /*配置UART0的波特率*/

  27. Fdiv = (SystemCoreClock/  baudrate) /UART_MCK_DIV ;

  28. if (Fdiv < UART_MCK_DIV_MIN_FACTOR || Fdiv > UART_MCK_DIV_MAX_FACTOR)

  29. return ;

  30. UART0->UART_BRGR=Fdiv;

  31. /*定义数据位为8bit,停止位为1,校验位为NONE*/

  32. UART0->UART_MR = UART_MR_PAR_NO|UART_MR_CHMODE_NORMAL;

  33. /*禁止 DMA 通道 */

  34. UART0->UART_PTCR = UART_PTCR_RXTDIS | UART_PTCR_TXTDIS;

  35. /*使能UART接收和发送*/

  36. UART0->UART_CR = UART_CR_RXEN | UART_CR_TXEN;

  37. /*使能接收中断*/

  38. UART0->UART_IER=UART_IER_RXRDY;

  39.    /*配置UART0的先占优先级为1,从优先级为1*/

  40.    NVIC_SetPriority(UART0_IRQn, ((0x01<<3)|0x01));

  41. /*使能UART0的中断通道*/

  42.     NVIC_EnableIRQ(UART0_IRQn);

  43. }
复制代码

第一步就是使能PIOA和UART0的时钟,然后配置PIOA9和PIOA10连接到外设A功能,也就是URXD0和UTXD0功能,然后禁止PIOA9和PIOA10的GPIO功能,这样PIOA9和PIOA10就配置成了URXD0和UTXD0。


接下来配置UART,首先复位UART0并禁止接收和发送,接着计算波特率分频值,数据手册给出如下计算公式,按照这个计算就好。


29143552-6d9808a192e3477c8aae56a39f0cb7e8.png


接下来配置UART的模式,这里选择普通模式,校验位为NONE,然后禁止DMA功能,因为没有用DMA传输。


最后使能UART的收发,使能中断,这样算是完成了UART的配置了。


完成配置还不行,还需要一个接收和发送函数,代码如下:



  1. /**************************************************************************

  2. * 函数名:UART0_Handler()

  3. * 参数  :void

  4. * 返回值:void

  5. * 描述  :UART0中断服务函数

  6. **************************************************************************/

  7. void UART0_Handler(void)

  8. {

  9. uint8_t temp;

  10. if((UART0->UART_SR& UART_SR_RXRDY)==1)

  11. {                                            //接收数据中断

  12.   temp= UART0->UART_RHR&0xff;          //接收一个字节

  13.        UART0_SendByte(temp);          //将接收的数据发回

  14.    }

  15. }

  16.   /*****************************************************************************

  17. * 函数名:UART0_SendByte()

  18. * 参数  :uint8_t c  要发送字符

  19. * 返回值:void

  20. * 描述  :UART0发送一个字符函数

  21. **************************************************************************/

  22. void UART0_SendByte(uint8_t c)

  23. {

  24.    while((UART0->UART_SR & UART_SR_TXEMPTY) == 0); //等待发送缓冲器为空

  25.    UART0->UART_THR=c; //将发送字符写入发送保持寄存器

  26. }

  27. /******************************************************************************

  28. * 函数名:UART0_SendString()

  29. * 参数  :uint8_t *s  指向字符串的指针

  30. * 返回值:void

  31. * 描述  :UART0发送字符串函数

  32. **************************************************************************/

  33. void UART0_SendString(uint8_t *s)

  34. {

  35.   while(*s) //判断是否到字符串末尾

  36.   {

  37.    UART0_SendByte(*s); //发送指针当前所指的字节

  38.    s++; //地址加1

  39.   }

  40. }
复制代码


这里我们使用的中断接收方式,因为接收的数据只是用来实验是否有接收到,所有这里是收到后再发回去。接收时要读取UART状态寄存器UART_SR的值,看UART_SR_RXRDY位是否被置位,如果置位说明有数据接收。发送时要先检测UART的发送数据寄存器UART_THR是不是为空。


好了,这样就完成UART0的驱动了,接下来按这样的方法去配置其他UART就都可以用了。


接下来还需要去实现int fputc(int ch,FILE *f)这个函数,试printf的打印输出到UART0去,这样就可以在程序中使用printf()函数打印消息了,代码如下:


  1. int fputc(int ch,FILE *f)

  2. {

  3.   UART0_SendByte((uint8_t)ch); //发送1个字节

  4.   return ch;    //返回 ch

  5. }
复制代码


在main.c中写个简单的测试程序,如下:



  1. int main(void)

  2. {

  3. systick_hw_init();

  4. led_hw_init();

  5. UART0_Init(115200);

  6. UART0_SendString("hello,this is demo for uart\r\n");

  7. while(1){

  8. printf("hello,I am SAM4N\r\n");

  9. led_hw_on();

  10. delay_ms(500);

  11. led_hw_off();

  12. delay_ms(500);

  13. }

  14. }
复制代码

下载程序,打开串口调试工具,就可以看到板子的串口输出了,如下图:

29143553-23b4214424154882ade3bb5ee654522b.png


注意:使用printf需要把MicroLIB勾上,如下图:

29143554-3ebcfad977914957ba34ac2384912174.png



跳转到指定楼层
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

主题 28 | 回复: 31



手机版|

GMT+8, 2024-12-21 21:14 , Processed in 0.047734 second(s), 8 queries , Gzip On, MemCache On. Powered by Discuz! X3.5

YiBoard一板网 © 2015-2022 地址:河北省石家庄市长安区高营大街 ( 冀ICP备18020117号 )

快速回复 返回顶部 返回列表