强仔00001 发表于 2015-1-14 01:16

Atmel SAM4E Xplained Pro学习笔记之串口

现在我就来简单介绍SAM4E16E的串口,在SAM4E16E这款MCU中,有4个串口,分别是两个UART和两个USART。如下图:这次我来使用板子上的UART1模块作为介绍。
首先在操作UART1时,我先得知道UART1挂在那个总线桥上,从手册中我们可以看出UART1是挂在桥1上,如下图:接着我们就要找UART1对应的管脚,从手册中可以知道PIOA5和PIOA6是UART1的RX,TX脚,如下图:光知道管脚是不行了,因为有些PIO口可以复用多种功能的管脚,如下手册PIO模块的截图可以知道,有些PIO口最多有4中功能复用:然后我们跳转到手册关于这部分的介绍:从上图可以看出,各个管脚的复用情况了,这个类比我数电的多路选择器。接着下来,就看看串口寄存器部分:
相比PIO口来说,UART的寄存器少了不少,如下图UART的寄存器框图:大家可以看到画着红色框的部分,这部分是Power Management Controller (PMC)电源管理模块,这个模块是控制了MCU上所有外设的时钟源。   从下面截图的介绍可以看出:所以当我们要用某个外设时一定要打开该外设的时钟。从串口这部分的内容也可以看出:那问题来了,我们怎么打开某个外设的时钟呢??
我可以通过PMC的PMC Peripheral Clock Enable Register寄存器打开,这里分PMCPeripheral Clock Enable Register0和PMCPeripheral Clock Enable Register1,PMCPeripheral Clock Enable Register 0是管前32个外设的时钟源开关,PMCPeripheral Clock Enable Register 1管剩下外设的时钟源的来源,如下面手册的一段话,大意是要我们找对应外设的ID号:然后可以通过PDF的查找功能找到这部分的详细资料,如下图我们可以查出UART1的外设ID号:可以看出UART1是的ID号是45,这样我就可以直接对PMC_PCER1寄存器写入1 <<(45-32)也就是把PMC_PCER1(PMC Peripheral Clock Enable Register1)的第13位置1,就是打开UART1的时钟源了。串口这部分的寄存器的我就不多说了,大家可以自行去查E文手册。现在我来理清下思路了:使用串口时的步奏:(1)初始化系统时钟和外设的时钟。(2)设置相关PIO口的复用为UART的TX和RX脚,关闭PIO功能。大家要注意的是但凡你使用到某个外设,外设涉及到的PIO管脚一定要把PIO功能关闭。可以通过ioport_disable_port(xxx,xxx)的库函数关闭PIO功能,或者直接对PIO_PDR写1;例如:ioport_disable_port(IOPORT_PIOA,(PIO_PA5C_URXD1 | PIO_PA6C_UTXD1));或者PIOA->PIO_PDR =(PIO_PA5C_URXD1 | PIO_PA6C_UTXD1);这两种写法一样的。(3)设置UART的工作模式,波特率等(4)实现用户功能。关于波特率这里我要多补充几点:设置波特率的是通过UART_BRGR(UART Baud Rate GeneratorRegister)波特率寄存器设定的。
计算公式如下图:分母是外设时钟,单位数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 |=   (PIO_PA5C_URXD1 | PIO_PA6C_UTXD1); //把PIOA5和PIOA6设置为Peripheral C function模式
PIOA->PIO_ABCDSR &=   ~(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管脚的电平
            
         }
         */
      }
}
这里有两部分代码,一个是写寄存器的,一个是写库的,只要在主函数调用即可。
附上测图:{:1_138:}{:1_138:}附上源代码:



dj狂人 发表于 2015-1-15 11:10

挺详细的,赞一个。楼主在调试过程中遇到的问题或者解决问题的方法可以发到以下两个贴https://bbs.eeworld.com.cn/thread-454443-1-1.html      、 https://bbs.eeworld.com.cn/thread-454136-1-1.html有奖励哦:victory:

强仔00001 发表于 2015-1-15 11:39

dj狂人 发表于 2015-1-15 11:10
挺详细的,赞一个。楼主在调试过程中遇到的问题或者解决问题的方法可以发到以下两个贴https://bbs.eeworld.com.cn/thread-454443-1-1.html      、 https://bbs.eeworld.com.cn/thread-454136-1-1.html有奖励哦这个提议不错:)



ciqie 发表于 2024-8-6 18:36

太牛了,大佬
页: [1]
查看完整版本: Atmel SAM4E Xplained Pro学习笔记之串口