STM32库函数编程思路总结及其与寄存器编程的对比剖析

一、STM32库函数编程思路总结

1、基于STM32库函数的开发过程

进行具体的项目开发前,做好项目创建工作,通常包括如下步骤:

(1)新建工程项目的文件夹和子文件夹(如user、output、listing等)

(2)使用MDK新建(或打开项目),选择目标CPU、添加CMSIS核心、STM32启动代码和外设驱动程序,构成运行环境。

(3)添加包含main()函数的主程序文件。

(4)配置目标选项。

这些项目创建的步骤是通用的,项目构建确认无误后,可以复制整个项目文件夹的内容并保存,再次创建项目时可以直接应用(仅需适当改变项目名称等)。

通过以下步骤对项目本身流程进行分析,以明确并掌握相关外设的STM32驱动函数(以GPIO控制LED为例):

(1)为每个目标板上的外设编写一个驱动程序源文件[ led.c ],包含外设初始化函数[ led_init() ]和简单通用的外设操控函数      [ led_on_all()](直接应用性质的控制函数)

(2)将外设驱动程序的常量定义、函数声明等写入对应的头文件[ led.h ]。源程序文件[ led.c ]要包含其头文件[ led.h ],并添加到项目的源文件组中[ user ]。

(3)单独编写一个主程序文件[ main() ],实现项目需要的主控流程。主程序应包含外设驱动头文件[ led.h ](无需包含GPIO和RCC的头文件,尽管它们是必须被调用的。如下图所示,因为在配置RTE时已经在StdPeriph Drivers中选择了GPIO和RCC等外设驱动,故已经自动添加了该部分,无需在自己编写的源程序main()、led()中添加),并调用外设操控函数[ led_on_all()]或STM32库函数[ GPIO_ResetBits() ]实现外设控制。


主函数的调用关系如下图所示:


项目构建后最好先进行软件模拟,然后将程序下载到目标板进行硬件调试和运行。除了常规的寄存器、存储器等显示窗口,还应该利用外设窗口和逻辑分析仪窗口观测外设及其引脚的工作状态,尤其是在软件模拟时。

二、使用STM32库函数的一般规则

CMSIS和STM32库本身比较复杂,但有统一的规范。熟悉这些规律有助于我们更好地使用驱动程序。

1、常量定义

各种参数有宏定义或者枚举常量。对于每个寄存器而言,各个参量的值即为填入寄存器中某位的数值,名称一致。

2、外设函数

外设函数名用一个下划线分割两部分。各种外设往往具有功能雷同的函数,STM32库采用统一的函数名称,如下表所示。


3、外设结构类型

每种外设至少有2个结构体数据类型:位于stm32f10x.h头文件中的外设寄存器结构体PPP_TypeDef,用于访问外设寄存器;另一个是位于外设头文件stm32f10x_ppp.h中的外设初始化结构体PPP_InitTypeDef,用于配置外设初始化参数。

其中,

stm32f10x.h头文件中主要包含三部分内容:

(1)所有外设的寄存器结构体

(2)所有外设的内存映射

(3)用于每个寄存器位设置的宏定义常量(名称和寄存器的位名称一致,便于移植和应用)

stm32f10x_ppp.h头文件中主要包含:

(1)库函数,用于实现外设具备的各种功能

(2)宏定义、枚举常量以及外设初始化的结构体,用于抽象化硬件。常量就是设置相应寄存器位功能的数值,以达到所需的功能。

有了这两个外设结构体,就可以使用外设驱动程序库进行编程,步骤如下:

(1)开启外设时钟:使用RCC的外设时钟命令函数。——可以工作

(2)初始化外设:定义外设初始化结构变量,为外设初始化结构变量成员赋值,调用外设初始化函数配置外设。——如何工作

(3)控制外设:使用驱动程序库函数编写应用程序。——进行工作

4、外设初始化

外设初始化和配置的一般步骤如下:

(1)定义外设初始化结构变量:PPP_InitTypeDef   PPP_initStructure;

(2)用允许的成员值填充外设初始化结构成员变量

    方法1:逐个成员地填充整个结构体

PPP_InitStructure.number1=Val1;

...........

PPP_InitStructure.numberN=ValN;

   方法2:当成员较多,且无需全部设置为用户指定的特定值时,可以用PPP_StructInit()函数先将所有成员值设置为系统默认值后,再对其中的部分参数进行重新赋值。

PPP_StructInit(&PPP_InitStructure);

PPP_InitStructure.numberX=ValX;

PPP_InitStructure.numberY=ValY;

(3)调用PPP_Init()函数初始化外设

PPP_Init(PPP,&PPP_InitStructure)

(4)用PPP_Cmd()函数打开外设时钟,允许外设开始工作

PPP_Cmd(PPP,ENABLE);

经过以上4步对外设初始化后,可以灵活运用库函数进行应用程序的开发。

以初始化GPIO为例(库函数):

void GPIO_Init(void)

{

GPIO_InitTypeDef GPIO_InitStructure;

GPIO_InitStructure.GPIO_Pin = PIN_LED;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

GPIO_Init(GPIOB, &GPIO_InitStructure);

        RCC_APB2PeriphClockCmd(RCC_LED, ENABLE);  

GPIO_ResetBits(GPIOB,GPIO_Pin_All);

}

二、采用库函数和直接对外设寄存器编程的对比

以初始化GPIO为例(库函数):源代码共86行代码,在写入寄存器数值前需要大量代码去判断工作模式和配置的引脚,最后才组合出正确的数值

void GPIO_Init(void)

{

GPIO_InitTypeDef GPIO_InitStructure;

GPIO_InitStructure.GPIO_Pin = PIN_LED;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

GPIO_Init(GPIOB, &GPIO_InitStructure);

        RCC_APB2PeriphClockCmd(RCC_LED, ENABLE);  

GPIO_ResetBits(GPIOB,GPIO_Pin_All);

}


以初始化GPIO为例(寄存器):源代码只有1条语句,直接对端口配置寄存器CRL进行赋值,即可初始化配置端口

void GPIO_Init(void)

{

GPIOB->CRL=0X44444443;

}

由上面的例子可知,STM32库函数本质上是对外设寄存器直接编程,只是为了方便应用封装成了函数。所以用户的应用程序也可以绕过库函数,直接对寄存器编程。

直接对寄存器编程的代码效率最高。不过,需要花费较多的时间学习和查阅STM32数据手册,这个过程繁琐、易错,难以移植。

库函数就是用宏定义、枚举标识符等代表的数值写入寄存器,替用户摆脱枯燥的机械过程。在一些代码要求高效率的情况下,对寄存器编程是非常必要的。同时,对寄存器的学习与操作,将非常有助于我们在出错时进行程序调试。






猜你喜欢

转载自blog.csdn.net/chenguigan/article/details/80369887