历史上的今天
今天是:2025年03月25日(星期二)
2020年03月25日 | STM32固件库详解
2020-03-25 来源:eefocus
1.1 基于标准外设库的软件开发
1.1.1 STM32标准外设库概述
STM32标准外设库之前的版本也称固件函数库或简称固件库,是一个固件函数包,它由程序、数据结构和宏组成,包括了微控制器所有外设的性能特征。该函数库还包括每一个外设的驱动描述和应用实例,为开发者访问底层硬件提供了一个中间API,通过使用固件函数库,无需深入掌握底层硬件细节,开发者就可以轻松应用每一个外设。因此,使用固态函数库可以大大减少用户的程序编写时间,进而降低开发成本。每个外设驱动都由一组函数组成,这组函数覆盖了该外设所有功能。每个器件的开发都由一个通用API (application programming interface 应用编程界面)驱动,API对该驱动程序的结构,函数和参数名称都进行了标准化。
ST公司2007年10月发布了V1.0版本的固件库,MDK ARM3.22之前的版本均支持该库。2008年6月发布了V2.0版的固件库,从2008年9月推出的MDK ARM3.23版本至今均使用V2.0版本的固件库。V3.0以后的版本相对之前的版本改动较大,本书使用目前较新的V3.4版本。
1.1.2 使用标准外设库开发的优势
简单的说,使用标准外设库进行开发最大的优势就在于可以使开发者不用深入了解底层硬件细节就可以灵活规范的使用每一个外设。标准外设库覆盖了从GPIO到定时器,再到CAN、I2C、SPI、UART和ADC等等的所有标准外设。对应的C源代码只是用了最基本的C编程的知识,所有代码经过严格测试,易于理解和使用,并且配有完整的文档,非常方便进行二次开发和应用。
1.1.3 STM32F10XXX标准外设库结构与文件描述
1. 标准外设库的文件结构
在上一小节中已经介绍了使用标准外设库的开发的优势,因此对标准外设库的熟悉程度直接影响到程序的编写,下面让我们来认识一下STM32F10XXX的标准外设库。STM32F10XXX的标准外设库经历众多的更新目前已经更新到最新的3.5版本,开发环境中自带的标准外设库为2.0.3版本,本书中以比较稳定而且较新的V3.4版本为基础介绍标准外设库的结构。
可以从ST的官方网站下载到各种版本的标准外设库,首先看一下3.4版本标准外设库的文件结构,如图 5‑3所示。3.0以上版本的文件结构大致相同,每个版本可能略有调整。
![clip_image002[19] clip_image002[19]](https://8.eewimg.cn/news/uploadfile/2020/0325/1585121580785301.jpg?imageView2/2/w/550)
![clip_image004[6] clip_image004[6]](https://8.eewimg.cn/news/uploadfile/2020/0325/1585121581200505.png?imageView2/2/w/550)
![clip_image005[6] clip_image005[6]](https://8.eewimg.cn/news/uploadfile/2020/0325/1585121612129898.png?imageView2/2/w/550)
层主要分为以下3 个部分:
(1) 核内外设访问层(CPAL,Core Peripheral Access Layer):该层由ARM 负责实现。包括对寄存器名称、地址的定义,对核寄存器、NVIC、调试子系统的访问接口定义以及对特殊用途寄存器的访问接口(例如:CONTROL,xPSR)定义。由于对特殊寄存器的访问以内联方式定义,所以针对不同的编译器ARM 统一用来屏蔽差异。该层定义的接口函数均是可重入的。
(2) 片上外设访问层(DPAL, Device Peripheral Access Layer):该层由芯片厂商负责实现。该层的实现与CPAL 类似,负责对硬件寄存器地址以及外设访问接口进行定义。该层可调用CPAL 层提供的接口函数同时根据设备特性对异常向量表进行扩展,以处理相应外设的中断请求。
(3) 外设访问函数(AFP, Access Functions for Peripherals):该层也由芯片厂商负责实现,主要是提供访问片上外设的访问函数,这一部分是可选的。
对一个Cortex-M 微控制系统而言,CMSIS 通过以上三个部分实现了:
l 定义了访问外设寄存器和异常向量的通用方法;
l 定义了核内外设的寄存器名称和核异常向量的名称;
l 为RTOS 核定义了与设备独立的接口,包括Debug 通道。
这样芯片厂商就能专注于对其产品的外设特性进行差异化,并且消除他们对微控制器进
行编程时需要维持的不同的、互相不兼容的标准需求,以达到低成本开发的目的。CMSIS中的具体文件结构如表 5‑6所示。


在实际开发过程中,根据应用程序的需要,可以采取2种方法使用标准外设库(StdPeriph_Lib):
(1) 使用外设驱动:这时应用程序开发基于外设驱动的API(应用编程接口)。用户只需要配置文件”stm32f10x_conf.h”,并使用相应的文件”stm32f10x_ppp.h/.c”即可。
(2) 不使用外设驱动:这时应用程序开发基于外设的寄存器结构和位定义文件。
这两种方法的优缺点在“使用标准外设库开发的优势”小节中已经有了具体的介绍,这里仍要说明的是,使用使用标准外设库进行开发可以极大的减小软件开发的工作量,也是目前嵌入式系统开发的一个趋势。
标准外设库(StdPeriph_Lib)支持STM32F10xxx系列全部成员:大容量,中容量和小容量产品。从表 5‑6中也可以看出,启动文件已经对不同的系列进行了划分,实际开发中根据使用的STM32产品具体型号,用户可以通过文件”stm32f10x.h”中的预处理define或者通过开发环境中的全局设置来配置标准外设库(StdPeriph_Lib),一个define对应一个产品系列。
下面列出支持的产品系列
STM32F10x_LD:STM32小容量产品
STM32F10x_MD:STM32中容量产品
STM32F10x_HD:STM32大容量产品
在库文件中这些define的具体作用范围是:
l 文件“stm3210f.h”中的中断IRQ定义
l 启动文件中的向量表,小容量,中容量,大容量产品各有一个启动文件
l 外设存储器映像和寄存器物理地址
l 产品设置:外部晶振(HSE)的值等
l 系统配置函数
因此通过宏定义这种方式,可以使标准外设库适用于不同系列的产品,同时也方便与不同产品之间的软件移植,极大的方便了软件的开发。
1.1.4 STM32F10XXX标准外设库的使用
标准外设库中包含了众多的变量定义和功能函数,如果不能了解他们的命名规范和使用规律将会给编程带来很大的麻烦,本节将主要叙述标准外设库中的相关规范,通过这些规范的学习可以更加灵活的使用固件库,同时也将极大增强程序的规范性和易读性,同时标准外设库中的这种规范也值得我们在进行其他相关的开发时使用和借鉴。
1. 缩写定义
标准外设库中的主要外设均采用了缩写的形式,通过这些缩写可以很容易的辨认对应的外设。


2. 命名规则
标准外设库遵从以下命名规则 PPP表示任一外设缩写,例如:ADC。源程序文件和头文件命名都以“stm32f10x_”作为开头,例如:stm32f10x_conf.h。常量仅被应用于一个文件的,定义于该文件中;被应用于多个文件的,在对应头文件中定义。所有常量都由英文字母大写书写。寄存器作为常量处理。他们的命名都由英文字母大写书写。在大多数情况下,他们采用与缩写规范一致。外设函数的命名以该外设的缩写加下划线为开头。每个单词的第一个字母都由英文字母大写书写,例如:SPI_SendData。在函数名中,只允许存在一个下划线,用以分隔外设缩写和函数名的其它部分。对于函数命名,总的来说有以下规则:
l 名为PPP_Init的函数,其功能是根据PPP_InitTypeDef中指定的参数,初始化外设PPP,例如TIM_Init.
l 名为PPP_DeInit的函数,其功能为复位外设PPP的所有寄存器至缺省值,例如TIM_DeInit.
l 名为PPP_Init的函数,其功能为通过设置PPP_InitTypeDef 结构中的各种参数来定义外设的功能,例如:USART_Init .
l 名为PPP_Cmd的函数,其功能为使能或者失能外设PPP,例如: SPI_Cmd.
l 名为PPP_ITConfig的函数,其功能为使能或者失能来自外设PPP某中断源,例如: RCC_ITConfig.
l 名为PPP_DMAConfig的函数,其功能为使能或者失能外设PPP的DMA接口,例如:TIM1_DMAConfig.
l 用以配置外设功能的函数,总是以字符串“Config”结尾,例如GPIO_PinRemapConfig.
l 名为PPP_GetFlagStatus的函数,其功能为检查外设PPP某标志位被设置与否,例如:I2C_GetFlagStatus.
l 名为PPP_ClearFlag的函数,其功能为清除外设PPP标志位,例如:I2C_ClearFlag.
l 名为PPP_GetITStatus的函数,其功能为判断来自外设PPP的中断发生与否,例如:I2C_GetITStatus.
l 名为PPP_ClearITPendingBit的函数,其功能为清除外设PPP中断待处理标志位,例如: I2C_ClearITPendingBit.
这样的命名方式非常便于程序的编写和阅读,以标准外设库中的示例函数为例,下面摘录了STM32F10x_StdPeriph_ExamplesADC3ADCs_DMAmian.c中的一段程序。
1 DMA_InitType Def DMA_InitStructure;
2
3 /* DMA1 channel1 configuration ----------------------------------------------*/
4
5 DMA_DeInit(DMA1_Channel1);
6
7 DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;
8
9 DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&ADC1ConvertedValue;
10
11 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
12
13 DMA_InitStructure.DMA_BufferSize = 1;
14
15 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
16
17 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;
18
19 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
20
21 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
22
23 DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
24
25 DMA_InitStructure.DMA_Priority = DMA_Priority_High;
26
27 DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
28
29 DMA_Init(DMA1_Channel1, &DMA_InitStructure);
30
31 /* Enable DMA1 channel1 */
32
33 DMA_Cmd(DMA1_Channel1, ENABLE);
这段程序完成了DMA1通道的配置,首先定义了DMA_InitType DMA_InitStructure,接着配置DMA_InitType的各种参数,各参数的命名方式也均使用约定的命名方式,从命名就能够很容易的看出各参数所指代的具体功能。功能参数配置完成后,使用DMA_Init(DMA1_Channel1, &DMA_InitStructure);完成相应外设的初始化,最后使用DMA_Cmd(DMA1_Channel1, ENABLE) 使能相应外设。从这个例子就能够很容易的看出标准外设库这种规范化的命名规则给编写和阅读程序带来的好处。
3. 变量定义
在早期的版本中有24个变量定义,在Keil的安装根目录下,可以找到对应的定义,路径为:KeilARMINCSTSTM32F10xstm32f10x_type.h
1 /* Includes ------------------------------------------------------------------*/
2
3 /* Exported types ------------------------------------------------------------*/
4
5 typedef signed long s32;
6
7 typedef signed short s16;
8
9 typedef signed char s8;
10
11 typedef signed long const sc32; /* Read Only */
12
13 typedef signed short const sc16; /* Read Only */
14
15 typedef signed char const sc8; /* Read Only */
16
17 typedef volatile signed long vs32;
18
19 typedef volatile signed short vs16;
20
21 typedef volatile signed char vs8;
22
23 typedef volatile signed long const vsc32; /* Read Only */
24
25 typedef volatile signed short const vsc16; /* Read Only */
26
27 typedef volatile signed char const vsc8; /* Read Only */
28
29 typedef unsigned long u32;
30
31 typedef unsigned short u16;
32
33 typedef unsigned char u8;
34
35 typedef unsigned long const uc32; /* Read Only */
36
37 typedef unsigned short const uc16; /* Read Only */
38
39 typedef unsigned char const uc8; /* Read Only */
40
41 typedef volatile unsigned long vu32;
42
43 typedef volatile unsigned short vu16;
44
45 typedef volatile unsigned char vu8;
46
47 typedef volatile unsigned long const vuc32; /* Read Only */
48
49 typedef volatile unsigned short const vuc16; /* Read Only */
50
51 typedef volatile unsigned char const vuc8; /* Read Only */
3.0以后的版本中使用了CMSIS数据类型,变量的定义有所不同,但是出于兼容旧版本的目的,以上的数据类型仍然兼容。CMSIS的IO类型限定词如表 5‑7所示,CMSIS和STM32固件库的数据类型对比如表 5‑8所示。这些数据类型可以在STM32F10x_StdPeriph_Lib_V3.4.0LibrariesCMSISCM3DeviceSupportSTSTM32F10xstm32f10x.h中找到具体的定义,此部分定义如下。
1 /*!< STM32F10x Standard Peripheral Library old types (maintained for legacy purpose) */
2
3 typedef int32_t s32;
4
5 typedef int16_t s16;
6
7 typedef int8_t s8;
8
9 typedef const int32_t sc32; /*!< Read Only */
10
11 typedef const int16_t sc16; /*!< Read Only */
12
13 typedef const int8_t sc8; /*!< Read Only */
14
15 typedef __IO int32_t vs32;
16
17 typedef __IO int16_t vs16;
18
19 typedef __IO int8_t vs8;
20
21 typedef __I int32_t vsc32; /*!< Read Only */
22
23 typedef __I int16_t vsc16; /*!< Read Only */
24
25 typedef __I int8_t vsc8; /*!< Read Only */
26
27 typedef uint32_t u32;
28
29 typedef uint16_t u16;
30
31 typedef uint8_t u8;
32
33 typedef const uint32_t uc32; /*!< Read Only */
34
35 typedef const uint16_t uc16; /*!< Read Only */
36
37 typedef const uint8_t uc8; /*!< Read Only */
38
39 typedef __IO uint32_t vu32;
40
41 typedef __IO uint16_t vu16;
42
43 typedef __IO uint8_t vu8;
44
45 typedef __I uint32_t vuc32; /*!< Read Only */
46
47 typedef __I uint16_t vuc16; /*!< Read Only */
48
49 typedef __I uint8_t vuc8; /*!< Read Only */
表 5‑7 CMSIS IO类型限定词

表 5‑8 固件库与CMSIS数据类型对比


stm32f10x.h文件中还包含了常用的布尔形变量定义,如:
1 typedef enum {RESET = 0, SET = !RESET} FlagStatus, ITStatus;
2
3 typedef enum {DISABLE = 0, ENABLE = !DISABLE} FunctionalState;
4
5 #define IS_FUNCTIONAL_STATE(STATE) (((STATE) == DISABLE) || ((STATE) == ENABLE))
6
7 typedef enum {ERROR = 0, SUCCESS = !ERROR} ErrorStatus;
不同版本的标准外设库的变量定义略有不同,如3.4版本中就没有之前版本的TRUE和FALSE的定义,用户也可以根据自己的需求按照上面的格式定义自己的布尔形变量。在使用标准外设库进行开发遇到相关的定义问题时应首先找到对应的头文件定义。
史海拾趣
|
昨天看了一下电路图,发现内存(SDRAM)和2440接口有点不可思议,后来仔细对比。 发现问题在LDQM,UDQM这两个引脚,他们接到2440的四个nWBE引脚。内存资料是这么说的:Data Input/Output Mask Controls output buffers in read mode and masks inp ...… 查看全部问答> |
|
写一个底层软件,到时下载到单片机,一上电自动运行这个程序。 在CF卡里预存了10个文件,每次上电打开不同的文件,用来保存数据, fs_openfile(“文件名”)。 但是怎么一上电赋给“文件名\"不同的值呢? (不想使用实时时钟获取时 ...… 查看全部问答> |
|
准备上个项目,人手不够,打算找人合作。 杭州有产品经验,有业余时间,熟悉工业级ARM,51,tcp/ip,RTOS等之一的技术便可。 有兴趣的回个贴。 技术专长,业余时间,要求等。 sssbang@163.com … 查看全部问答> |
|
请大侠指点: 我目前定了嵌入式方向,但是不知道学具体的哪块比较好?对于一个初学者来说,我该如何准备,如何选书,该看哪些书?才能更快的入门。还有3个月就要开题了,很急,多谢指教,不甚感激!!… 查看全部问答> |
|
本帖最后由 jameswangsynnex 于 2015-3-3 19:54 编辑 用头戴式耳机,尤其是小型耳机听音乐,总感到音乐味不够足,在低频段的效果更差。因此用本机增强耳机的低频特性,并采用立体声反相合成的办法,加上内藏简易矩阵环绕声电路,能获得强劲的低音 ...… 查看全部问答> |
|
是不是现在支持STM32F的GCC编译器开发环境都是命令行模式的 我下载了一个WINARM20080331里面没找到XP可以运行的程序CodeSourcery 里面用的好象也是命令行模式 … 查看全部问答> |
|
求一个基于MSP430F149或F449芯片的LCD键盘显示系统的完整C程序 求一个基于MSP430F149或F449芯片的LCD键盘显示系统的完整C程序 说明:本人刚开始学习MSP430,想用MSP430做一个键盘LCD显示控制系统 求一个完整的C程序,来学习和模仿下。 控制系统要求:1,键盘是3*4列的行列式扫描键盘。LCD最好用truely(信利公 ...… 查看全部问答> |




