FireBLE

FireBLE 是一个面向于打造智能生活的开源平台,以BLE(Bluetooth Low Energy)技术为核心,拥有超低的功耗、不俗的处理能力和广泛的应用场合,专注于更智能、高效率的工作模式,让生活在科技中更安全、方便、快捷。也许您一个不经意的想法与FireBLE擦出的火花,会在这片原野上燎出火焰,甚至燃烧整个世界。

UART 驱动

更新时间:2017-08-08 阅读:2904

前言

Uart通信是一个非常常用的设备通信协议,其特点是通信线路简单,只要一对传输线就可以实现双向通信。Uart经常使用于简单设备间的数据传输,也经常使用于程序的调试。

串口初始化

串口初始化之前要先配置GPIO。

 //UART io configurate
 uart_io_config();
 void uart_io_config(void)
 {
     // pin mux
     syscon_SetPMCR0(QN_SYSCON, P07_SW_CLK_PIN_CTRL
                              | P06_SW_DAT_PIN_CTRL
                              | P00_UART0_TXD_PIN_CTRL    // P0.0 uart0 tx
                              | P17_UART0_RXD_PIN_CTRL    // P1.7 uart0 rx
                              );
     syscon_SetPMCR1(QN_SYSCON, P21_UART1_TXD_PIN_CTRL    // P2.1 uart1 tx
                                | P20_UART1_RXD_PIN_CTRL    // P2.0 uart1 rx
                              );
 
     // pin select
     syscon_SetPMCR2(QN_SYSCON, SYSCON_MASK_UART1_PIN_SEL);
 
     // pin pull ( 00 : High-Z,  01 : Pull-down,  10 : Pull-up,  11 : Reserved )
     syscon_SetPPCR0(QN_SYSCON, 0xAAAA5AAA);
     syscon_SetPPCR1(QN_SYSCON, 0x2AAAAAAA);
 }

函数syscon_SetPMCR0,syscon_SetPMCR1分别配置 GPIO_P00~GPIO_P17 和 GPIO_P20~GPIO_P36的GPIO复用功能,请注意此范围限制,GPIO_P23是不能syscon_SetPMCR0所配置的。

     // pin mux
     syscon_SetPMCR0(QN_SYSCON, P07_SW_CLK_PIN_CTRL
                              | P06_SW_DAT_PIN_CTRL
                              | P00_UART0_TXD_PIN_CTRL    // P0.0 uart0 tx
                              | P17_UART0_RXD_PIN_CTRL    // P1.7 uart0 rx
                              );
     syscon_SetPMCR1(QN_SYSCON, P21_UART1_TXD_PIN_CTRL    // P2.1 uart1 tx
                                | P20_UART1_RXD_PIN_CTRL    // P2.0 uart1 rx
                              );

函数syscon_SetPMCR2选择开启某些外设的引脚复用功能,因为本例只是用了UART1,故配置为:

   // pin select
   syscon_SetPMCR2(QN_SYSCON, SYSCON_MASK_UART1_PIN_SEL);

其他可供开启的特殊引脚选择位为

  • 31 - 27 : TEST_CTRL[4 :0]
  • 27 - 8 : RSVD
  • 7 : CLK_OUT_SEL[1]
  • 6 : CLK_OUT_SEL[0]
  • 5 : UART1_PIN_SEL
  • 4 : I2C_PIN_SEL
  • 3 : ADCT_PIN_SEL
  • 2 : RSVD
  • 1 : SPI0_PIN_SEL
  • 0 : SPI1_PIN_SEL

另外由于开启SWD需要下拉IO口,所以需要如下配置

     // pin pull ( 00 : High-Z,  01 : Pull-down,  10 : Pull-up,  11 : Reserved )
     syscon_SetPPCR0(QN_SYSCON, 0xAAAA5AAA);  //GPIO_P06,GPIO_P07配置为5(0101),其他的GPIO都是A(1010) 
     syscon_SetPPCR1(QN_SYSCON, 0x2AAAAAAA);  //由于没有GPIO_P37,所以最高两位保留,而GPIO_P36为上拉,故为2(0010)AAAAAAA

配置完成GPIO,接下来应该是UART的初始化,根据时钟的不同,我们可以配置不同的初始化参数,如下

 #if __AHB_CLK == 32000UL
     //Initialize uart0 with 1200 baudrate, 8bit data, 1 stop bit, no parity, LSB bitorder, no HW flow control.
     uart_init(QN_UART0, __USART_CLK, UART_1200);
 #else
     //Initialize uart0 with 115200 baudrate, 8bit data, 1 stop bit, no parity, LSB bitorder, no HW flow control.
     uart_init(QN_UART0, __USART_CLK, UART_115200);
     //uart_init(QN_UART0, __USART_CLK, UART_57600);
 #endif
     uart_tx_enable(QN_UART0, MASK_ENABLE);
     uart_rx_enable(QN_UART0, MASK_ENABLE);

uart_init分别包含三个参数,第一个参数是串口模块的选择,QN902x中有两个串口模块,其中QN_UART0最为常用。第二个参数是Uart串口的选择,第三个参数是波特率的设置,在32K晶振下只能采用1200的波特率。其他的例如传输位数、停止位、校验位、大小端、流控的设置需要进入uart_init函数里面进行更改和设置。

 uart_init(QN_UART0, __USART_CLK, UART_1200);

串口的收发可以选择轮询,也可以选择中断,一般为了效率考虑,我们一般使用的是中断方式,所以还需要打开中断

     uart_tx_enable(QN_UART0, MASK_ENABLE);
     uart_rx_enable(QN_UART0, MASK_ENABLE);

初始化完成!

串口打印字符串

   //Print out "Hello Quintic!\n" thought uart.
   uart_printf(QN_UART0, (uint8_t *)"Hello Quintic!\n");

通过uart_printf函数可以实现串口的字符串打印,当然字符串可以和数组互通,你也可以用来打印一串你需要传输的数字。函数参数很简单,第一个是串口选择,第二个是待发送数组指针。

串口收发示例

   //uart0 receive data
   rx_flag = 1;
   uart_read(QN_UART0, buffer, 10, led_blink_left);
   while (rx_flag == 1);
 
   //uart0 send data
   tx_flag = 1;
   uart_write(QN_UART0, buffer, 10, led_blink_right);
   while (tx_flag == 1);

示例中采用了UART0先向串口读取10个字节数据存入buffer数组内,再通过UART0向串口写入刚才在串口中读入保存在buffer中的10字节数据。
uart_read有四个参数,第一个串口选择,第二个是读取的数据存放的位置,第三个参数是读取的字节个数,第四个参数是回调函数的设置在读取数据完成后,就会调用回调函数。

  uart_read(QN_UART0, buffer, 10, led_blink_left);

在读取之前,可以先设置一个读取标志位rx_flag,执行读取函数之后就进入到while循环中进行空操作,在读取完成后,在回调函数中清零读取标志位,完成一次读取操作。

 void led_blink_left(void)
 {
     rx_flag = 0;
 }

串口写入操作与读取类似。