[MM32生态] 【MM32 eMiniBoard测评报告】+自写寄存器头文件,开源xprint使用

[复制链接]
5807|34
 楼主| axushilong 发表于 2020-6-3 18:57 | 显示全部楼层 |阅读模式
做单片机开发久了,发现用的单片机也多,现在每个厂家都提供对应的库以方便加快客户的开发。但是总是有那么一些人,不习惯用官方的库,因为厂家太多,每家写代码的规范都不一样,A厂的单片机是一个规范,B厂的单片机可能又是一个规范,C厂的又会是其他的规范,这样看起来就有点头大了。于是我就干脆不用官方的头文件,自己定义头文件,统一规范。又由于一般写单片机程序还都是要看寄存器用户手册的,于是干脆自己动手写头文件吧,而且我发现自己定义寄存器相关头文件,可以更加深刻的了解单片机。
下面以MM32L0xx系列单片机的UART模块为例进行介绍。
首先我们根据寄存器用户手册的UART模块的寄存器概况,定义一个UART类型struct UartType,然后定义好模块访问指针pstUart1    和pstUart1 如下:

UART模块的寄存器概况

UART模块的寄存器概况

  1. struct UartType{
  2.   __IO uint32_t vuiTdr;
  3.   __I  uint32_t vuiRdr;
  4.   __I  uint32_t vuiCsr;
  5.   __I  uint32_t vuiIsr;
  6.   __IO uint32_t vuiIer;
  7.   __O  uint32_t vuiIcr;
  8.   __IO uint32_t vuiGcr;
  9.   __IO uint32_t vuiCcr;
  10.   __IO uint32_t vuiBrr;
  11.   __IO uint32_t vuiFra;
  12. };

  13. /** 操作MM32L0xx串口硬件的指针*/
  14. #define pstUart1    ((struct UartType *) DE_Uart1BaseAddress)
  15. #define pstUart2    ((struct UartType *) DE_Uart2BaseAddress)
结构体里的vuiTdr就对应手册里的UART发送寄存器UART_TDR,我这里有个习惯就是,寄存器的相关定义我都我在变量名前面加字母v,阅读代码的时候就可以很清楚的知道这是一个寄存器。然后后面的ui表示unsigned int,用来表示这是一个32位宽的变量。后面跟的Tdr就是表示寄存器UART_TDR了,我这里是习惯将首字母大写。这也是我的一个习惯,寄存器名首字母大写,查看的时候可以很清楚的知道是什么寄存器,寄存器名前面的vui指出了这是一个32位的寄存器。这样看一个变量名就可以很清楚的知道这个变量的相关属性和含义。
后面再根据实际的寄存器中的位,写出对应位的宏定义,这里以UART通用控制寄存器(UART_CCR)为例进行介绍。

UART通用控制寄存器

UART通用控制寄存器

首先我们看校验使能位PEN,我们可以做这样的定义#define DE_UartCcrPen (1ul),这里又来介绍我的一个习惯,我习惯宏定义的时候在其前面加DE_前缀来表明这是一个宏定义,这个也是方便在查阅代码的时候一眼就发现这是一个宏,对于一个很久之前写的代码做修改,通常只要看到宏的地方肯定是可以修改的地方。DE_后面跟着Uart表示这是一个和UART串口相关的宏定义,后面的Ccr就表示这是UART的通用控制寄存器UART_CCR,再后面的Pen,就表示手册里的校验使能位PEN。最后的(1ul)表示这个位在位0的位置,加ul表示这个位是一个32位寄存器中的位,当然这里也可以写成(1ul<<0)。同样的写法定义好其他位的宏定义如下:
  1. /** MM32L0xx串口通用控制寄存器位定义*/
  2. #define DE_UartCcrPen (1ul)
  3. #define DE_UartCcrPsel (1ul << 1)
  4. #define DE_UartCcrSpb (1ul << 2)
  5. #define DE_UartCcrBrk (1ul << 3)
  6. #define DE_UartCcrChar (3ul << 4)
这再说下这个CHAR字段,这个字段表示了UART的数据位宽,占了2个位,这样我们就可以写成(3ul << 4)。对于这种,我们可以配置这2位来指定串口的数据位是5位还是6位,或者7位,8位。这样就相当于一个配置参数,我们怎么配置呢。请看下面:
  1. /** 串口数据位宽配置参数*/
  2. #define DE_UartCcrChar5Bit (0ul)
  3. #define DE_UartCcrChar6Bit (1ul << 4)
  4. #define DE_UartCcrChar7Bit (2ul << 4)
  5. #define DE_UartCcrChar8Bit (3ul << 4)
看到上面的定义是不是很一目了然。
那么串口用的时候怎么用呢,我就实现了下面的串口配置的方法:
  1. /**
  2.   * [url=home.php?mod=space&uid=247401]@brief[/url]  串口配置并使能,先打开串口时钟,复位串口后再配置
  3.   * [url=home.php?mod=space&uid=536309]@NOTE[/url]   要先配置好使用串口的引脚复用,再调用此函数初始化配置串口,串口才能正常使用,在没有复用串口引脚前,串口引脚数据会乱码
  4.   * @param  [in] pstUart 要初始化的串口对应的硬件地址指针
  5.   * [url=home.php?mod=space&uid=2817080]@ARG[/url]    pstUart1, pstUart2
  6.   * @param  [in] uiBaudRate 要配置的波特率(分配置整数和小数部分)
  7.   * @param  [in] ucDataBits 要配置的数据位
  8.   * @arg    DE_UartCcrChar5Bit, DE_UartCcrChar6Bit, DE_UartCcrChar7Bit, DE_UartCcrChar8Bit
  9.   * @param  [in] ucStopBits 要配置的停止位
  10.   * @arg    DE_UartCcrSpb1Bit, DE_UartCcrSpb2Bit
  11.   * @param  [in] ucParity 要配置的校验
  12.   * @arg    DE_UartCcrPenNone, DE_UartCcrPenOdd, DE_UartCcrPenEven
  13.   * @param  [in] uiMode 要配置的串口模式,可以是可选参数的或组合
  14.   * @arg    DE_UartGcrDmamode, DE_UartGcrRxen, DE_UartGcrTxen
  15.   * @param  [in] ucFlowControl 要配置的硬件流控
  16.   * @arg    DE_UartGcrAutoflowerDisable, DE_UartGcrAutoflowerEnable
  17.   * @retval None
  18.   */
  19. 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位数据位,一个停止位,无校验位,无流控的配置,可以调用下面的代码。

  1. vUartConfig(pstUart1,(uint32_t)115200ul,DE_UartCcrChar8Bit,DE_UartCcrSpb1Bit,DE_UartCcrPenNone,(DE_UartGcrRxen | DE_UartGcrTxen),DE_UartGcrAutoflowerDisable);
看这个代码就可以很清楚的知道串口的配置,这里函数前加的v表示void,表示这个函数是一个无返回数据类型的一个函数。
其他更多欢迎下载此代码一起讨论交流。
另外此代码还移植实现了一个xprint的功能,这是一个没有使用任何库实现的一个printf功能的开源代码。

  1.         xdev_out(vUart1SendData);
  2.         xprintf("%d\r\n", 1234);                        //"1234"
  3.         xprintf("%6d,%3d%%\r\n", -200, 5);        //"  -200,  5%"
  4.         xprintf("%-6u\r\n", 100);                        //"100   "
  5.         xprintf("%ld\r\n", 12345678);                //"12345678"
  6.         xprintf("%llu\r\n", 0x100000000);        //"4294967296"        <_USE_LONGLONG>
  7.         xprintf("%04x\r\n", 0xA3);                        //"00a3"
  8.         xprintf("%08lX\r\n", 0x123ABC);                //"00123ABC"
  9.         xprintf("%016b\r\n", 0x550F);                //"0101010100001111"
  10.         xprintf("%*d\r\n", 6, 100);                        //"   100"
  11.         xprintf("%s\r\n", "String");                //"String"
  12.         xprintf("%-5s\r\n", "abc");                        //"abc  "
  13.         xprintf("%5s\r\n", "abc");                        //"  abc"
  14.         xprintf("%c\r\n", 'a');                                //"a"
在此不做过多解释,欢迎大家下载使用。可以将此例程当成一个模板进行后续开发。
另外值得注意的是,这个eMiniBoard开发板的调试功能的那个串口是连到单片机的UART1的,但是我使用串口调试助手打开调试器的那个串口,是无法查看到单片机发来的数据的,这个可能是调试器的串口功能有问题的原因吧,不知道有没有其他的小伙伴可以正常使用这个调试器的串口功能的有没有,有的欢迎交流写。所以对于这个例程代码,需要另接一个串口调试器到单片机的TX1和RX1,那样电脑上才可以看到串口打印的效果了。我的打印效果如下:

xprint打印输出预览

xprint打印输出预览

下面是main.c文件代码。有兴趣的欢迎下载代码交流。
  1. #include "MM32L0xx_Uart.h"
  2. #include "xprintf.h"
  3. #include "Cortex_M0_SysTick.h"


  4. static void vUart1SendData(uint8_t ucData){
  5.         while( !uiUartGetFlag(pstUart1,DE_UartCsrTxc) );
  6.         pstUart1->vuiTdr = ucData;
  7. }

  8. int main(void){
  9.         vRccEnableAhbPeripheralClock(DE_RccAhbenrGpioa | DE_RccAhbenrGpiob);
  10.         pstGpioa->vuiOdr = DE_Pin15;
  11.         pstGpiob->vuiOdr = DE_Pin3 | DE_Pin4 | DE_Pin5;
  12.         pstGpiob->vuiCrl = (DE_GpioModePpOut<<12) | (DE_GpioModePpOut<<16) | (DE_GpioModePpOut<<20);
  13.         /** 串口GPIO引脚复用配置 A9-TX1,A10-RX1*/
  14.         pstGpioa->vuiCrh = (DE_GpioModeAfPp<<4) | (DE_GpioModeUpDnIn<<8) | (DE_GpioModePpOut<<28);
  15.         pstGpioa->vuiOdr |= DE_Pin10;
  16.         pstGpioa->vuiAfrh &=0x00f;//参考数据手册引脚定义章节的最后两页P21,P22
  17.         pstGpioa->vuiAfrh |=0x110;
  18.         vUartConfig(pstUart1,(uint32_t)115200ul,DE_UartCcrChar8Bit,DE_UartCcrSpb1Bit,DE_UartCcrPenNone,(DE_UartGcrRxen | DE_UartGcrTxen),DE_UartGcrAutoflowerDisable);
  19.         xdev_out(vUart1SendData);
  20.         xprintf("%d\r\n", 1234);                        //"1234"
  21.         xprintf("%6d,%3d%%\r\n", -200, 5);        //"  -200,  5%"
  22.         xprintf("%-6u\r\n", 100);                        //"100   "
  23.         xprintf("%ld\r\n", 12345678);                //"12345678"
  24.         xprintf("%llu\r\n", 0x100000000);        //"4294967296"        <_USE_LONGLONG>
  25.         xprintf("%04x\r\n", 0xA3);                        //"00a3"
  26.         xprintf("%08lX\r\n", 0x123ABC);                //"00123ABC"
  27.         xprintf("%016b\r\n", 0x550F);                //"0101010100001111"
  28.         xprintf("%*d\r\n", 6, 100);                        //"   100"
  29.         xprintf("%s\r\n", "String");                //"String"
  30.         xprintf("%-5s\r\n", "abc");                        //"abc  "
  31.         xprintf("%5s\r\n", "abc");                        //"  abc"
  32.         xprintf("%c\r\n", 'a');                                //"a"
  33. //        xprintf("%f\r\n", 10.0);            //<xprintf lacks floating point support. Use regular printf.>
  34.         while(1){
  35.                 vSysTickDelayNms(1000);
  36.                 pstGpioa->vuiOdr ^= DE_Pin15;
  37.                 pstGpiob->vuiOdr ^= DE_Pin3 | DE_Pin4 |DE_Pin5;
  38.         }
  39. }
MM32L0xx_n_Lib.zip (267.8 KB, 下载次数: 25)






cashrwood 发表于 2021-7-10 17:37 | 显示全部楼层
使用寄存器,可以减少时钟的浪费。
robertesth 发表于 2021-7-10 17:36 | 显示全部楼层
寄存器操作确实可以帮助深刻的了解单片机
saservice 发表于 2021-7-10 17:36 | 显示全部楼层
楼主已经将单片机玩到了出神入化了。   
yorkbarney 发表于 2021-7-10 17:36 | 显示全部楼层
推荐给厂家试试。           
benjaminka 发表于 2021-7-10 17:35 | 显示全部楼层
xprint在哪方面有提升吗      
beacherblack 发表于 2021-7-10 17:35 | 显示全部楼层
为什么不用stdio.h带的printf呢?   
vivilyly 发表于 2021-7-10 17:35 | 显示全部楼层
这个有完整的工程文件吗     
deliahouse887 发表于 2021-7-10 17:34 | 显示全部楼层
自写寄存器头文件,办不了看看。  
loutin 发表于 2021-7-10 17:34 | 显示全部楼层
已经到了寄存器操作了。        
timfordlare 发表于 2021-7-10 17:34 | 显示全部楼层
xprint在哪里定义的?           
呐咯密密 发表于 2021-6-16 09:51 | 显示全部楼层
徒手撸代码可太牛了,这样搞很方便,但是我这种对底层不熟悉的菜鸟撸不来
cehuafan 发表于 2021-6-13 21:32 | 显示全部楼层
资料的确是很全面                                 
mmbs 发表于 2021-6-13 21:32 | 显示全部楼层
资料够全的,多谢分享                                 
bestwell 发表于 2021-6-13 21:32 | 显示全部楼层
谢谢你共享的资料                                 
wilhelmina2 发表于 2021-6-13 21:32 | 显示全部楼层
共享的资料比较详细  谢谢                                 
maqianqu 发表于 2021-6-13 21:32 | 显示全部楼层
有时间需要好好看看   不错                                 
minzisc 发表于 2021-6-13 21:32 | 显示全部楼层
相当全的资料,很适合初学者                                 
belindagraham 发表于 2021-6-13 21:31 | 显示全部楼层
正准备学习的朋友推荐下载。                                 
sanfuzi 发表于 2021-6-13 21:31 | 显示全部楼层
非常感谢楼主分享                                 
adolphcocker 发表于 2021-6-13 21:31 | 显示全部楼层
正准备用 来做产品,刚好用上。         
您需要登录后才可以回帖 登录 | 注册

本版积分规则

5

主题

38

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部