认识STM32开发环境的固件库

您所在的位置:网站首页 gpio固件库资源群 认识STM32开发环境的固件库

认识STM32开发环境的固件库

2023-11-02 19:16| 来源: 网络整理| 查看: 265

本文笔者就结合上一篇文章《学习STM32mini版(流水灯)》,来解释什么是固件库以及他是怎么工作的。

认识固件库

STM32的固件库又叫固件函数包,它是由程序、数据结构和宏组成,包括了微控制器所有外设的性能特征。该函数库还包括每一个外设的驱动描述和应用实例,为开发者访问底层硬件提供了一个中间API,通过使用固件函数库,无需深入掌握底层硬件细节,开发者就可以轻松应用每一个外设。因此,使用固态函数库可以大大减少开发者开发使用片内外设的时间,进而降低开发成本。每个外设驱动都由一组函数组成,这组函数覆盖了该外设所有功能。同时,STM32官方还给出了大量的示例代码以供学习。

ST公司的ST(意法半导体)为了方便用户开发程序,提供了一套丰富的 STM32 固件库。固件库就是函数的集合,固件库函数的作用是向下负责与寄存器直接打交道,向上提供用户函数调用的接口(API) 。固件库将这些寄存器底层操作都封装起来,提供一整套接口(API)供开发者调用,大多数场合下,你不需要去知道操作的是哪个寄存器,你只需要知道调用哪些函数即可。 ARM 公司为了能让不同的芯片公司生产的 Cortex-M3 芯片能在软件上基本兼容,和芯片生产商共同提出了一套标准 CMSIS 标准(Cortex Microcontroller Software Interface Standard) ,翻译过来是“ARM Cortex 微控制器软件接口标准”。 ST 官方库就是根据这套标准设计的。 CMSIS 分为 3 个基本功能层:

核内外设访问层:ARM 公司提供的访问,定义处理器内部寄存器地址以及功能函数。中间件访问层:定义访问中间件的通用 API,也是 ARM 公司提供。外设访问层:定义硬件寄存器的地址以及外设的访问函数。 CMSIS 层在整个系统中是处于中间层,向下负责与内核和各个外设直接打交道,向上提供实时操作系统用户程序调用的函数接口。如果没有 CMSIS 标准,那么各个芯片公司就会设计自己喜欢的风格的库函数,而 CMSIS 标准就是要强制规定,芯片生产公司设计的库函数必须按照 CMSIS 这套规范来设计。

一个简单的例子,我们在使用 STM32 芯片的时候首先要进行系统初始化, CMSIS 规范就规定,系统初始化函数名字必须为 SystemInit,所以各个芯片公司写自己的库函数的时候就必须用 SystemInit 对系统进行初始化。CMSIS 还对各个外设驱动文件的文件名字规范化,以及函数名字规范化等等一系列规定。

固件库的讲解

在讲解之前,先给大家展示一个例子。之前我们在学习C语言的开发中,经常会用到printf()函数。该函数可以很容易的实现所谓的格式化输出,相信很多人都和我一样在使用函数的时候不去关注他具体是怎样实现的,只看重最终的结果。 一样的道理,我们在使用ST公司提供的固件库的时候,尤其是在前期学习阶段,我们应该把重点放在熟悉固件库提供的函数上,着重分析几个函数即可,先熟悉函数,然后才是去关注,具体的实现方式。 以流水灯为例,下面给出了流水灯使用到的函数。

GPIO_InitTypeDef GPIO_Structure; GPIO_Structure.GPIO_Pin=GPIO_Pin_5; GPIO_Structure.GPIO_Mode=GPIO_Mode_Out_PP; GPIO_Init(GPIOB,&GPIO_Structure); GPIO_SetBits(GPIOB,GPIO_Pin_5); GPIO_ResetBits(GPIOB,GPIO_Pin_5);

上述6行代码基本可以实现点亮一个LED了!就是可以这么简单,下面对其进行分析,着重说明其原理及设计方法。 第1行,首先定义一个结构体变量GPIO_Structure,其类型GPIO_InitTypeDef。为什么要定义这么一个结构体呢? 一般来说,GPIO口的寄存器都是一组,例如输入和输出控制寄存器、数据寄存器、上拉控制寄存器、输出位置复位寄存器等,通常这些寄存器的地址都是连续的,所以,请明白一点GPIO_InitTypeDef结构体中的各个变量是用来初始化GPIO口有关的寄存器,因此,只需要通过GPIO_Structure结构体变量,就可以“间接的”访问GPIO口的所有的寄存器了。 间接的?为什么是“间接的”呢? 第2行,对结构体变量GPIO_Structure中的GPIO_Pin赋值为GPIO_Pin_5,其中GPIO_Pin_5是一个宏定义。 第3行,对结构体变量GPIO_Structure中的GPIO_Mode赋值为GPIO_Mode_Out_PP,其中,GPIO_Mode_Out_PP是一个宏定义。从字面的意思来看该变量控制GPIO口的输入和输出模式。 第4行,调用GPIO_Init()函数,那么该函数完成什么工作呢?可能有人会想这个函数是如何实现的?还是得换个角度看问题,这里的主要问题是尽快的弄明白这个函数到底完成什么事情就可以了,其他工作可适当延后完成。 我们可以联想一下现实,邮寄快递的时候,一般快递公司都有相应的包装盒,用户只需要根据邮寄的物品选择不同的包装即可,剩下的就靠快递公司就可以了。 这里的GPIO_Structure结构类似体就类似于一个包装盒,只要将该结构体里面的变量初始化,然后调用GPIO_Init()函数,就可以实现对相应的寄存器的初始化工作,此时GPIO_Init()函数就是快递公司了,我们只需要按照调用方法调用就可以了,没必要去关心他是怎么实现的。 在这里插入图片描述 第5行,GPIO_SetBits()函数,实现对某个IO口的位置操作,即使其输出高电平。 第6行,GPIO_ResetBits()函数,实现对某个IO口的复位操作,即使其输出低电平。

经过以上的介绍,可以完成下面的子程序。 已知LED2接在PD6引脚,当PD6引脚输出高电平时,点亮LED2,我们对比前面的例子,来写具体程序。 首先,我们得先找什么?“快递的包装盒”,也就是定义一个结构体变量,其类型为GPIO_InitTypeDef,然后对其初始化。可以看上面的那张图。 “快递包装盒”程序

GPIO_InitTypeDef GPIO_Structure; GPIO_Structure.GPIO_Pin=GPIO_Pin_6; GPIO_Structure.GPIO_Mode=GPIO_Mode_Out_PP;

然后将这个“快递包装盒”给“快递公司”也就是调用GPIO_Init()函数,这时候,GPIO口的初始化工作结束,GPIO——Init()函数就会完成PD口的相应寄存器初始化工作。

GPIO_Init(GPIOD,&GPIO_Structure);

最后了,我们就可以去调用IO口的置位和复位函数来实现相应的IO输出高低电平了。

GPIO_SetBits(GPIOD,GPIO_Pin_6); GPIO_ResetBits(GPIOD,GPIO_Pin_6);

还有个问题,需要声明一下。上述的所有函数都是ST公司固件库中的函数,既然是使用了人家公司的固件库,那么就需要有包含固件库的头文件,例如#include"stm32f10x.h",stm32f10x.h文件中包含了STM32F10xx系列的处理器所用到的大量库函数以及寄存器定义,我们在以后的学习中会经常用到这个在文件里的函数。

笔者疑问

GPIO_Init()函数是如何被调用? 望广大读者可以在评论区给出你们的答案,谢谢。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3