打印

Atmel SAM4E Xplained Pro学习笔记之串口

[复制链接]
1743|3
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
powerantone|  楼主 | 2021-10-26 10:55 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
现在我就来简单介绍SAM4E16E的串口,在SAM4E16E这款MCU中,有4个串口,分别是两个UART和两个USART。如下图:
这次我来使用板子上的UART1模块作为介绍。

首先在操作UART1时,我先得知道UART1挂在那个总线桥上,从手册中我们可以看出UART1是挂在桥1上,如下图:
接着我们就要找UART1对应的管脚,从手册中可以知道PIOA5PIOA6UART1RXTX脚,如下图:
光知道管脚是不行了,因为有些PIO口可以复用多种功能的管脚,如下手册PIO模块的截图可以知道,有些PIO口最多有4中功能复用:
然后我们跳转到手册关于这部分的介绍:
从上图可以看出,各个管脚的复用情况了,这个类比我数电的多路选择器。
接着下来,就看看串口寄存器部分:

相比PIO口来说,UART的寄存器少了不少,如下图UART的寄存器框图:
大家可以看到画着红色框的部分,这部分是Power Management Controller (PMC)电源管理模块,这个模块是控制了MCU上所有外设的时钟源。     从下面截图的介绍可以看出:
所以当我们要用某个外设时一定要打开该外设的时钟。从串口这部分的内容也可以看出:

使用特权

评论回复
沙发
powerantone|  楼主 | 2021-10-26 10:57 | 只看该作者
那问题来了,我们怎么打开某个外设的时钟呢??

我可以通过PMCPMC Peripheral Clock Enable Register寄存器打开,这里分PMCPeripheral Clock Enable Register  0PMCPeripheral Clock Enable Register  1PMCPeripheral Clock Enable Register 0是管前32个外设的时钟源开关,PMCPeripheral Clock Enable Register 1管剩下外设的时钟源的来源,如下面手册的一段话,大意是要我们找对应外设的ID号:
然后可以通过PDF的查找功能找到这部分的详细资料,如下图我们可以查出UART1的外设ID号:
可以看出UART1是的ID号是45,这样我就可以直接对PMC_PCER1寄存器写入1 <<(45-32)也就是把PMC_PCER1PMC Peripheral Clock Enable Register  1)的第13位置1,就是打开UART1的时钟源了。
串口这部分的寄存器的我就不多说了,大家可以自行去查E文手册。
现在我来理清下思路了:
使用串口时的步奏:
1)初始化系统时钟和外设的时钟。
2)设置相关PIO口的复用为UARTTXRX脚,关闭PIO功能。大家要注意的是但凡你使用到某个外设,外设涉及到的PIO管脚一定要把PIO功能关闭。可以通过ioport_disable_port(xxx,xxx)的库函数关闭PIO功能,或者直接对PIO_PDR1;例如:
ioport_disable_port(IOPORT_PIOA,(PIO_PA5C_URXD1 | PIO_PA6C_UTXD1));或者PIOA->PIO_PDR =(PIO_PA5C_URXD1 | PIO_PA6C_UTXD1);这两种写法一样的。
3)设置UART的工作模式,波特率等
4)实现用户功能。
关于波特率这里我要多补充几点:
设置波特率的是通过UART_BRGRUART Baud Rate GeneratorRegister)波特率寄存器设定的。

使用特权

评论回复
板凳
powerantone|  楼主 | 2021-10-26 10:59 | 只看该作者
计算公式如下图:
分母是外设时钟,单位数HZ,把CD求出来,写入UART_BRGR寄存器即可。如我这里的外设时钟是24MHZ,则比特率应该填入的值如下:UART1->UART_BRGR = (24000000/(16*9600));

现在贴上我的源代码吧:
  • #include "asf.h"
  • #define STRING_EOL    "\r"
  • #define STRING_HEADER "-- USART Serial Example --\r\n" \
  •                 "-- "BOARD_NAME" --\r\n" \
  •                 "-- Compiled: "__DATE__" "__TIME__" --"STRING_EOL
  • void Send_Data(uint8_t data);
  • #ifdef __GNUC__
  • /* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
  •      set to 'Yes') calls __io_putchar() */
  • #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
  • #else
  • #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
  • #endif /* __GNUC__ */
  • PUTCHAR_PROTOTYPE
  • {
  • /* Place your implementation of fputc here */
  • /* e.g. write a character to the USART */
  •   Send_Data((uint8_t) ch);
  • /* Loop until the end of transmission */
  • return ch;
  • }
  • static void configure_console(void)
  • {
  •         const   usart_serial_options_t uart_serial_options = {
  •                 .baudrate = 9600,
  •                 .paritytype = UART_MR_PAR_NO,
  •         };
  •         /* Configure console UART. */
  •         sysclk_enable_peripheral_clock(ID_UART1);
  •         stdio_serial_init(UART1, &uart_serial_options);
  • }
  • void Port_Init()
  • {
  •   ioport_set_port_mode(IOPORT_PIOA,(PIO_PA5C_URXD1 | PIO_PA6C_UTXD1),IOPORT_MODE_MUX_C);//把PIOA5和PIOA6设置为UART1的TX和RX脚
  •   ioport_disable_port(IOPORT_PIOA, (PIO_PA5C_URXD1 | PIO_PA6C_UTXD1));                       //关闭PIO功能
  • }
  • void Port_Regster_Init()
  • {
  •   PIOA->PIO_ABCDSR[1] |=   (PIO_PA5C_URXD1 | PIO_PA6C_UTXD1); //把PIOA5和PIOA6设置为Peripheral C function模式
  •   PIOA->PIO_ABCDSR[0] &=   ~(PIO_PA5C_URXD1 | PIO_PA6C_UTXD1);
  •   PIOA->PIO_PUDR = (PIO_PA5C_URXD1 | PIO_PA6C_UTXD1);           //禁止上拉
  •   PIOA->PIO_PPDDR = (PIO_PA5C_URXD1 | PIO_PA6C_UTXD1);          //禁止下拉
  •   PIOA->PIO_MDDR = (PIO_PA5C_URXD1 | PIO_PA6C_UTXD1);
  •   PIOA->PIO_IFDR = (PIO_PA5C_URXD1 | PIO_PA6C_UTXD1);
  •   PIOA->PIO_IFSCDR = (PIO_PA5C_URXD1 | PIO_PA6C_UTXD1);
  •   PIOA->PIO_PDR = (PIO_PA5C_URXD1 | PIO_PA6C_UTXD1);           //禁止PIO功能
  • }
  • uint32_t uart_mck;
  • void Config_Uart()
  • {
  •   uart_mck = sysclk_get_peripheral_hz();
  •   PMC->PMC_PCER1 = 1 << 13; //打开UART1的时钟源
  •   UART1->UART_CR = UART_CR_RSTRX | UART_CR_RSTTX | UART_CR_RXDIS | UART_CR_TXDIS; //复位UART1
  •   UART1->UART_MR = UART_MR_PAR_NO |UART_MR_CHMODE_NORMAL ; //设置UART1的模式为无奇偶校验,普通方式
  •   UART1->UART_PTCR = UART_PTCR_RXTDIS | UART_PTCR_TXTDIS;   //禁止发送和接受中断
  •   UART1->UART_BRGR = (uart_mck/(16*9600));               //设置UART1的波特率
  •   UART1->UART_CR = UART_CR_RXEN | UART_CR_TXEN;           //使能UART1的发送和接收
  • }
  • uint8_t Uart_get()
  • {
  •    uint8_t data;
  •    while ((UART1->UART_SR & UART_SR_RXRDY) == 0)  //检测是否接收到数据
  •     ;
  •    data = UART1->UART_RHR;                      //接收到数据
  •    return data;
  • }
  • void Send_Data(uint8_t data)
  • {
  •     /* 发送*/
  •     while((UART1->UART_SR & UART_SR_TXRDY) == 0)     //检测是否准备发送数据
  •         ;
  •     UART1->UART_THR = data;                              //发送数据
  • }
  • int main(void)
  • {
  •              sysclk_init();
  •         /**/
  •         arch_ioport_init();
  •        //configure_console();
  •         Port_Regster_Init();                                           //初始化时钟
  •         Config_Uart();
  •        // pio_configure_pin(PIO_PA2_IDX,PIO_INPUT|PIO_PULLUP | PIO_DEFAULT);//把PIOA2脚设置为上拉输入模式
  •        // pio_configure_pin(PIO_PD22_IDX,PIO_OUTPUT_1 | PIO_DEFAULT);       //把PIOD22设置为输出模式
  •         while(1)
  •         {
  •          uint8_t data;
  •          data = Uart_get();
  •          Send_Data(data);
  •          //puts("\r\n");
  •            // puts(STRING_HEADER);
  •         /*   if(!pio_get_pin_value(PIO_PA2_IDX) )   //检测PIOA2是否被按下,按下时管脚读回来的数值是0
  •            {
  •               while(!pio_get_pin_value(PIO_PA2_IDX));//检测按键是否松开
  •               pio_toggle_pin(PIO_PD22_IDX);//翻转PIOD22管脚的电平
  •            }
  •            */
  •         }
  • }


复制代码

这里有两部分代码,一个是写寄存器的,一个是写库的,只要在主函数调用即可。

使用特权

评论回复
地板
powerantone|  楼主 | 2021-10-26 11:02 | 只看该作者
附上测图:

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

415

主题

1464

帖子

4

粉丝