在实际开发过程中,根据应用程序的需要,可以采取2种方法使用标准外设库(StdPeriph_Lib):
(1)使用外设驱动:这时应用程序开发基于外设驱动的API(应用编程接口)。用户只需要配置文件”stm32f10x_conf.h”,并使用相应的文件”stm32f10x_ppp.h/.c”即可。
(2) 不使用外设驱动:这时应用程序开发基于外设的寄存器结构和位定义文件。
这两种方法的优缺点在“使用标准外设库开发的优势”小节中已经有了具体的介绍,这里仍要说明的是,使用使用标准外设库进行开发可以极大的减小软件开发的工作量,也是目前嵌入式系统开发的一个趋势。
标准外设库(StdPeriph_Lib)支持STM32F10xxx系列全部成员:大容量,中容量和小容量产品。从表5-6中也可以看出,启动文件已经对不同的系列进行了划分,实际开发中根据使用的STM32产品具体型号,用户可以通过文件”stm32f10x.h”中的预处理define或
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_Examples\ADC\3ADCs_DMA\mian.c中的一段程序。DMA_InitType Def DMA_InitStructure;
/* DMA1 channel1 configuration----------------------------------------------*/ DMA_DeInit(DMA1_Channel1);
DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;
DMA_InitStructure.DMA_MemoryBaseAddr =
(uint32_t)&ADC1ConvertedValue;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = 1;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;
DMA_InitStructure.DMA_PeripheralDataSize =
DMA_PeripheralDataSize_HalfWord;
DMA_InitStructure.DMA_MemoryDataSize =
DMA_MemoryDataSize_HalfWord;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel1, &DMA_InitStructure);
/* Enable DMA1 channel1 */
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的安装根目录下,可以找到对应的定义,路径为:Keil\ARM\INC\ST\STM32F10x\stm32f10x_type.h
/* Includes------------------------------------------------------------------*/
/* Exported types------------------------------------------------------------*/ typedef signed long s32;
typedef signed short s16;
typedef signed char s8;
typedef signed long const sc32; /* Read Only */
typedef signed short const sc16; /* Read Only */
typedef signed char const sc8; /* Read Only */
typedef volatile signed long vs32;
typedef volatile signed short vs16;
typedef volatile signed char vs8;
typedef volatile signed long const vsc32; /* Read Only */
typedef volatile signed short const vsc16; /* Read Only */
typedef volatile signed char const vsc8; /* Read Only */
typedef unsigned long u32;
typedef unsigned short u16;
typedef unsigned char u8;
typedef unsigned long const uc32; /* Read Only */
typedef unsigned short const uc16; /* Read Only */
typedef unsigned char const uc8; /* Read Only */
typedef volatile unsigned long vu32;
typedef volatile unsigned short vu16;
typedef volatile unsigned char vu8;
typedef volatile unsigned long const vuc32; /* Read Only */
typedef volatile unsigned short const vuc16; /* Read Only */
typedef volatile unsigned char const vuc8; /* Read Only */
3.0以后的版本中使用了CMSIS数据类型,变量的定义有所不同,但是出于兼容旧版本的目的,以上的数据类型仍然兼容。CMSIS的IO类型限定词如表5-7所示,CMSIS和STM32固件库的数据类型对比如表5-8所示。这些数据类型可以在
STM32F10x_StdPeriph_Lib_V3.4.0\Libraries\CMSIS\CM3
\DeviceSupport\ST\STM32F10x\stm32f10x.h中找到具体的定义,此部分定义如下。/*!< STM32F10x Standard Peripheral Library old types (maintained for legacy purpose) */
typedef int32_t s32;
typedef int16_t s16;
stm32f10x.h文件中还包含了常用的布尔形变量定义,如:
typedef enum {RESET = 0, SET = !RESET} FlagStatus, ITStatus;
typedef enum {DISABLE = 0, ENABLE = !DISABLE} FunctionalState;
#define IS_FUNCTIONAL_STATE(STATE) (((STATE) == DISABLE) || ((STATE) == ENABLE))
typedef enum {ERROR = 0, SUCCESS = !ERROR} ErrorStatus;
不同版本的标准外设库的变量定义略有不同,如3.4版本中就没有之前版本的TRUE和FALSE的定义,用户也可以根据自己的需求按照上面的格式定义自己的布尔形变量。在使用标准外设库进行开发遇到相关的定义问题时应首先找到对应的头文件定义。
4. 使用步骤
前面几个小节已经详细介绍了标准外设库的组成结构以及部分主要文件的功能描述,那么如果在开发中使用标准外设库需要哪些描述呢?下面就进行简要的介绍,这儿介绍的使用方法是与开发环境无关的,在不同的开发环境中可能在操作方式上略有不同,但是总体的流程都是一样的,下一小节将介绍在MDK ARM开发环境下使用标准外设库的详细过程。
首先新建一个项目并设置工具链对应的启动文件,可以使用标准外设库中提供的模板,也可以自己根据自己的需求新建。标准外设库中已经提供了不同工具链对应的文件,位于STM32F10x_StdPeriph_Lib_V3.4.0\Libraries\CMSIS\CM3\DeviceSupport\ST
\STM32F10x\startup目录下。
其次按照使用产品的具体型号选择具体的启动文件,加入工程。文件主要按照使用产品的容量进行区分,根据产品容量进行选择即可。每个文件的具体含义可以在“stm32f10x.h”文件中找到对应的说明,摘录如下:
#if !defined (STM32F10X_LD) && !defined (STM32F10X_LD_VL)&& !defined (STM32F10X_MD) && !defined (STM32F10X_MD_VL) && !defined
(STM32F10X_HD) && !defined (STM32F10X_HD_VL) && !defined
(STM32F10X_XL)&& !defined (STM32F10X_CL)
/* #define STM32F10X_LD */ /*!< STM32F10X_LD: STM32 Low density devices */
/* #define STM32F10X_LD_VL */ /*!< STM32F10X_LD_VL: STM32 Low density Value Line devices */
/* #define STM32F10X_MD */ /*!< STM32F10X_MD: STM32 Medium density devices */
/* #define STM32F10X_MD_VL */ /*!< STM32F10X_MD_VL: STM32 Medium density Value Line devices */ /* #define STM32F10X_HD */ /*!<
STM32F10X_HD: STM32 High density devices */
/* #define STM32F10X_HD_VL */ /*!< STM32F10X_HD_VL: STM32 High density value line devices */
/* #define STM32F10X_XL */ /*!< STM32F10X_XL: STM32 XL-density devices */
/* #define STM32F10X_CL */ /*!< STM32F10X_CL: STM32 Connectivity line devices */
#endif
/* Tip: To avoid modifying this file each time you need to switch between these devices, you can define the device in your toolchain compiler preprocessor.
- Low-density devices are STM32F101xx, STM32F102xx and STM32F103xx microcontrollers
where the Flash memory density ranges between 16 and 32 Kbytes.
- Low-density value line devices are STM32F100xx microcontrollers where the Flash
memory density ranges between 16 and 32 Kbytes.
- Medium-density devices are STM32F101xx, STM32F102xx and STM32F103xx microcontrollers
where the Flash memory density ranges between 64 and 128 Kbytes.
- Medium-density value line devices are STM32F100xx microcontrollers where the
Flash memory density ranges between 64 and 128 Kbytes.
- High-density devices are STM32F101xx and STM32F103xx microcontrollers where
the Flash memory density ranges between 256 and 512 Kbytes.
- High-density value line devices are STM32F100xx microcontrollers where the Flash memory density ranges between 256 and 512 Kbytes.
- XL-density devices are STM32F101xx and STM32F103xx microcontrollers where
the Flash memory density ranges between 512 and 1024 Kbytes.
- Connectivity line devices are STM32F105xx and STM32F107xx microcontrollers.
*/
“stm32f10x.h”是整个标准外设库的入口文件,这个文件包含了STM32F10x全系列所有外设寄存器的定义(寄存器的基地址和布局)、位定义、中断向量表、存储空间的地址映射等。为了是这个文件适用于不同系列的产品,程序中是通过宏定义来实现不同产品的匹配的,上面这段程序的注释中已经详细给出了每个启动文件所对应的产品系列,与之对应,也要相应的修改这个入口文件,需要根据所使用的产品系列正确的注释/去掉相应的注释define。在这段程序的下方同样有这样的一个注释程序/*#define USE_STDPERIPH_DRIVER*/ 用于选择是否使用标准外设库,如果保留这个注释,则用户开发程序可以基于直接访问“stm32f10x.h”中定义的外设寄存器,所有的操作均基于寄存器完成,目前不使用固件库的单片机开发,如51、AVR、MSP430等其实都是采用此种方式,通过在对应型号的头文件中进行外设寄存器等方面的定义,从而在程序中对相应的寄存器操作完成相应的功能设计。
如果去掉/*#define USE_STDPERIPH_DRIVER*/的注释,则是使用标准外设库进行开发,用户需要使用在文件“stm32f10x_conf.h”中,选择要用的外设,外设同样是通过注释/去掉注释的方式来选择。示例程序如下:
/* Uncomment the line below to enable peripheral header file inclusion */
#include "stm32f10x_adc.h"
/* #include "stm32f10x_bkp.h" */
/* #include "stm32f10x_can.h" */
/* #include "stm32f10x_cec.h" */
/* #include "stm32f10x_crc.h" */
/* #include "stm32f10x_dac.h" */
/* #include "stm32f10x_dbgmcu.h" */
#include "stm32f10x_dma.h"
/* #include "stm32f10x_exti.h" */
/* #include "stm32f10x_flash.h" */
/* #include "stm32f10x_fsmc.h" */
#include "stm32f10x_gpio.h"
/* #include "stm32f10x_i2c.h" */
/* #include "stm32f10x_iwdg.h" */
/* #include "stm32f10x_pwr.h" */
#include "stm32f10x_rcc.h"
/* #include "stm32f10x_rtc.h" */
/* #include "stm32f10x_sdio.h" */
/* #include "stm32f10x_spi.h" */
/* #include "stm32f10x_tim.h" */
/* #include "stm32f10x_usart.h" */
/* #include "stm32f10x_wwdg.h" */
#include "misc.h" /* High level functions for NVIC and SysTick (add-on to CMSIS functions) */
上面一段程序来自于例程中的AD采集程序,程序使用了AD和DMA,因此去掉相应的注释,同时几乎所有的应用都需要使用复位与时钟以及通用I/O,因此这两项是必须的,
而多数程序同样要使用NVIC中断IRQ设置和SysTick时钟源设置,那么“misc.h”这一项也是必须的。
上面已经针对具体的产品信号和程序功能进行了针对性的配置,接下来需要配置系统所使用的时钟,系统时钟在“system_stm32f10x.c”同样通过注释的方式来配置,程序如下:#if defined (STM32F10X_LD_VL) || (defined STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)
/* #define SYSCLK_FREQ_HSE HSE_VALUE */
#define SYSCLK_FREQ_24MHz 24000000
#else
/* #define SYSCLK_FREQ_HSE HSE_VALUE */
/* #define SYSCLK_FREQ_24MHz 24000000 */
/* #define SYSCLK_FREQ_36MHz 36000000 */
/* #define SYSCLK_FREQ_48MHz 48000000 */
/* #define SYSCLK_FREQ_56MHz 56000000 */
#define SYSCLK_FREQ_72MHz 72000000
#endif
如果这儿没有明确的定义那么HSI时钟将会作为系统时钟。
至此,已经配置了系统的主要外部参数,这些参数主要是通过更改相关的宏定义来实现的,有些开发环境,例如Keil支持在软件设置中加入全局宏定义,因此像芯片系列定义,是否使用固件库定义等也可以通过软件添加来实现。
完成了主要参数配置以后就可以进行程序的开发了,标准外设库开发就可以使用标准外设库中提供的方便的API函数进行相应的功能设计了。在4.2.2小节中已经介绍了基于标准外设库开发的优势,配置完成后,程序中仍然可以直接更改相应寄存器的配置,通过对寄存器的操作可以提高程序的效率,因此可以使用标准外设库和寄存器操作两种相结合的方式。