×
单片机 > 单片机程序设计 > 详情

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

发布时间:2020-08-25 发布时间:
|

一、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() ]实现外设控制。

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数据手册,这个过程繁琐、易错,难以移植。


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


关键字:STM32  库函数  编程思路  寄存器编程 

『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
C51 特殊功能寄存器SFR的名称和地址