- struct UartType{
- __IO uint32_t vuiTdr;
- __I uint32_t vuiRdr;
- __I uint32_t vuiCsr;
- __I uint32_t vuiIsr;
- __IO uint32_t vuiIer;
- __O uint32_t vuiIcr;
- __IO uint32_t vuiGcr;
- __IO uint32_t vuiCcr;
- __IO uint32_t vuiBrr;
- __IO uint32_t vuiFra;
- };
- /** 操作MM32L0xx串口硬件的指针*/
- #define pstUart1 ((struct UartType *) DE_Uart1BaseAddress)
- #define pstUart2 ((struct UartType *) DE_Uart2BaseAddress)
结构体里的vuiTdr就对应手册里的UART发送寄存器UART_TDR,我这里有个习惯就是,寄存器的相关定义我都我在变量名前面加字母v,阅读代码的时候就可以很清楚的知道这是一个寄存器。然后后面的ui表示unsigned int,用来表示这是一个32位宽的变量。后面跟的Tdr就是表示寄存器UART_TDR了,我这里是习惯将首字母大写。这也是我的一个习惯,寄存器名首字母大写,查看的时候可以很清楚的知道是什么寄存器,寄存器名前面的vui指出了这是一个32位的寄存器。这样看一个变量名就可以很清楚的知道这个变量的相关属性和含义。
后面再根据实际的寄存器中的位,写出对应位的宏定义,这里以UART通用控制寄存器(UART_CCR)为例进行介绍。
UART通用控制寄存器
首先我们看校验使能位PEN,我们可以做这样的定义#define DE_UartCcrPen (1ul),这里又来介绍我的一个习惯,我习惯宏定义的时候在其前面加DE_前缀来表明这是一个宏定义,这个也是方便在查阅代码的时候一眼就发现这是一个宏,对于一个很久之前写的代码做修改,通常只要看到宏的地方肯定是可以修改的地方。DE_后面跟着Uart表示这是一个和UART串口相关的宏定义,后面的Ccr就表示这是UART的通用控制寄存器UART_CCR,再后面的Pen,就表示手册里的校验使能位PEN。最后的(1ul)表示这个位在位0的位置,加ul表示这个位是一个32位寄存器中的位,当然这里也可以写成(1ul<<0)。同样的写法定义好其他位的宏定义如下:
- /** MM32L0xx串口通用控制寄存器位定义*/
- #define DE_UartCcrPen (1ul)
- #define DE_UartCcrPsel (1ul << 1)
- #define DE_UartCcrSpb (1ul << 2)
- #define DE_UartCcrBrk (1ul << 3)
- #define DE_UartCcrChar (3ul << 4)
这再说下这个CHAR字段,这个字段表示了UART的数据位宽,占了2个位,这样我们就可以写成(3ul << 4)。对于这种,我们可以配置这2位来指定串口的数据位是5位还是6位,或者7位,8位。这样就相当于一个配置参数,我们怎么配置呢。请看下面:
- /** 串口数据位宽配置参数*/
- #define DE_UartCcrChar5Bit (0ul)
- #define DE_UartCcrChar6Bit (1ul << 4)
- #define DE_UartCcrChar7Bit (2ul << 4)
- #define DE_UartCcrChar8Bit (3ul << 4)
看到上面的定义是不是很一目了然。
那么串口用的时候怎么用呢,我就实现了下面的串口配置的方法:
- /**
- * [url=home.php?mod=space&uid=247401]@brief[/url] 串口配置并使能,先打开串口时钟,复位串口后再配置
- * [url=home.php?mod=space&uid=536309]@NOTE[/url] 要先配置好使用串口的引脚复用,再调用此函数初始化配置串口,串口才能正常使用,在没有复用串口引脚前,串口引脚数据会乱码
- * @param [in] pstUart 要初始化的串口对应的硬件地址指针
- * [url=home.php?mod=space&uid=2817080]@ARG[/url] pstUart1, pstUart2
- * @param [in] uiBaudRate 要配置的波特率(分配置整数和小数部分)
- * @param [in] ucDataBits 要配置的数据位
- * @arg DE_UartCcrChar5Bit, DE_UartCcrChar6Bit, DE_UartCcrChar7Bit, DE_UartCcrChar8Bit
- * @param [in] ucStopBits 要配置的停止位
- * @arg DE_UartCcrSpb1Bit, DE_UartCcrSpb2Bit
- * @param [in] ucParity 要配置的校验
- * @arg DE_UartCcrPenNone, DE_UartCcrPenOdd, DE_UartCcrPenEven
- * @param [in] uiMode 要配置的串口模式,可以是可选参数的或组合
- * @arg DE_UartGcrDmamode, DE_UartGcrRxen, DE_UartGcrTxen
- * @param [in] ucFlowControl 要配置的硬件流控
- * @arg DE_UartGcrAutoflowerDisable, DE_UartGcrAutoflowerEnable
- * @retval None
- */
- void vUartConfig(struct UartType * pstUart,uint32_t uiBaudRate,uint32_t uiDataBits,uint32_t uiStopBits,uint32_t uiParity,uint32_t uiMode,uint32_t uiFlowControl)
这里的函数功能说明是参考Doxygen注释规范来写的,可以通过软件自动生成帮助手册。然后针对对应的参数,我还加入了可选参数列表到注释中。比如我们要使用串口1进行波特率为115200bps,8位数据位,一个停止位,无校验位,无流控的配置,可以调用下面的代码。
- vUartConfig(pstUart1,(uint32_t)115200ul,DE_UartCcrChar8Bit,DE_UartCcrSpb1Bit,DE_UartCcrPenNone,(DE_UartGcrRxen | DE_UartGcrTxen),DE_UartGcrAutoflowerDisable);
看这个代码就可以很清楚的知道串口的配置,这里函数前加的v表示void,表示这个函数是一个无返回数据类型的一个函数。
其他更多欢迎下载此代码一起讨论交流。
另外此代码还移植实现了一个xprint的功能,这是一个没有使用任何库实现的一个printf功能的开源代码。
- xdev_out(vUart1SendData);
- xprintf("%d\r\n", 1234); //"1234"
- xprintf("%6d,%3d%%\r\n", -200, 5); //" -200, 5%"
- xprintf("%-6u\r\n", 100); //"100 "
- xprintf("%ld\r\n", 12345678); //"12345678"
- xprintf("%llu\r\n", 0x100000000); //"4294967296" <_USE_LONGLONG>
- xprintf("%04x\r\n", 0xA3); //"00a3"
- xprintf("%08lX\r\n", 0x123ABC); //"00123ABC"
- xprintf("%016b\r\n", 0x550F); //"0101010100001111"
- xprintf("%*d\r\n", 6, 100); //" 100"
- xprintf("%s\r\n", "String"); //"String"
- xprintf("%-5s\r\n", "abc"); //"abc "
- xprintf("%5s\r\n", "abc"); //" abc"
- xprintf("%c\r\n", 'a'); //"a"
在此不做过多解释,欢迎大家下载使用。可以将此例程当成一个模板进行后续开发。
另外值得注意的是,这个eMiniBoard开发板的调试功能的那个串口是连到单片机的UART1的,但是我使用串口调试助手打开调试器的那个串口,是无法查看到单片机发来的数据的,这个可能是调试器的串口功能有问题的原因吧,不知道有没有其他的小伙伴可以正常使用这个调试器的串口功能的有没有,有的欢迎交流写。所以对于这个例程代码,需要另接一个串口调试器到单片机的TX1和RX1,那样电脑上才可以看到串口打印的效果了。我的打印效果如下:
xprint打印输出预览
下面是main.c文件代码。有兴趣的欢迎下载代码交流。
- #include "MM32L0xx_Uart.h"
- #include "xprintf.h"
- #include "Cortex_M0_SysTick.h"
- static void vUart1SendData(uint8_t ucData){
- while( !uiUartGetFlag(pstUart1,DE_UartCsrTxc) );
- pstUart1->vuiTdr = ucData;
- }
- int main(void){
- vRccEnableAhbPeripheralClock(DE_RccAhbenrGpioa | DE_RccAhbenrGpiob);
- pstGpioa->vuiOdr = DE_Pin15;
- pstGpiob->vuiOdr = DE_Pin3 | DE_Pin4 | DE_Pin5;
- pstGpiob->vuiCrl = (DE_GpioModePpOut<<12) | (DE_GpioModePpOut<<16) | (DE_GpioModePpOut<<20);
- /** 串口GPIO引脚复用配置 A9-TX1,A10-RX1*/
- pstGpioa->vuiCrh = (DE_GpioModeAfPp<<4) | (DE_GpioModeUpDnIn<<8) | (DE_GpioModePpOut<<28);
- pstGpioa->vuiOdr |= DE_Pin10;
- pstGpioa->vuiAfrh &=0x00f;//参考数据手册引脚定义章节的最后两页P21,P22
- pstGpioa->vuiAfrh |=0x110;
- vUartConfig(pstUart1,(uint32_t)115200ul,DE_UartCcrChar8Bit,DE_UartCcrSpb1Bit,DE_UartCcrPenNone,(DE_UartGcrRxen | DE_UartGcrTxen),DE_UartGcrAutoflowerDisable);
- xdev_out(vUart1SendData);
- xprintf("%d\r\n", 1234); //"1234"
- xprintf("%6d,%3d%%\r\n", -200, 5); //" -200, 5%"
- xprintf("%-6u\r\n", 100); //"100 "
- xprintf("%ld\r\n", 12345678); //"12345678"
- xprintf("%llu\r\n", 0x100000000); //"4294967296" <_USE_LONGLONG>
- xprintf("%04x\r\n", 0xA3); //"00a3"
- xprintf("%08lX\r\n", 0x123ABC); //"00123ABC"
- xprintf("%016b\r\n", 0x550F); //"0101010100001111"
- xprintf("%*d\r\n", 6, 100); //" 100"
- xprintf("%s\r\n", "String"); //"String"
- xprintf("%-5s\r\n", "abc"); //"abc "
- xprintf("%5s\r\n", "abc"); //" abc"
- xprintf("%c\r\n", 'a'); //"a"
- // xprintf("%f\r\n", 10.0); //<xprintf lacks floating point support. Use regular printf.>
- while(1){
- vSysTickDelayNms(1000);
- pstGpioa->vuiOdr ^= DE_Pin15;
- pstGpiob->vuiOdr ^= DE_Pin3 | DE_Pin4 |DE_Pin5;
- }
- }
MM32L0xx_n_Lib.zip
(267.8 KB, 下载次数: 25)