嵌入式嵌入式软件开发首页投稿(暂停使用,暂停投稿)

STM32F10x之标准外设库

2016-03-24  本文已影响810人  hackvilin

1 简介

STM32F10x标准外设库是一个完整的包,包含了所有标准外设的设备驱动,适用于STM32价值系列(高、中和低),互联系列,超高、高、中、低密度32-bit Flash的微处理器。

这个库是一个固件库包,包含了一系列程序、数据结构和宏定义,覆盖了STM32外设的所有功能。它包括了设备驱动的描述和对应外设的一系列示例。固件库使得用户不需要深入学习每个外设说明就可以使用,使用标准外设库有两个优点:它节省了编码时间同时减少了应用程序开发和集成的时间消耗。STM32F10x标准外设库完全符合Cortex微处理器软件接口标准。

2 架构

2.1 CMSIS标准

因为基于Cortex-M3的系列芯片采用的内核都是相同的,区别主要在于核外的片上外设的,这些差异却导致软件在同内核、不同外设的芯片上移植困难。为了解决不同芯片厂商生产的Cortex微控制器软件的兼容性问题,ARM与芯片厂商建立了CMSIS标准。
  
ARM® Cortex™ 微控制器软件接口标准 (CMSIS) 是 Cortex-M 处理器系列的与供应商无关的硬件抽象层。CMSIS 可实现与处理器和外设之间的一致且简单的软件接口,从而简化软件的重用,缩短微控制器开发人员新手的学习过程,并缩短新设备的上市时间。

ARM提供以下软件层,可用于多种编译器:

芯片商提供以下软件层:

CMSIS对Cortex-M微处理器系统定义:

2.2 库目录分析

ST官网下载最新的STM32F10x标准外设库,目前最新版本为V3.5.0。解压该zip文件,得到如下文件夹和文件:
_htmresc
Libraries
Project
Utilities
Release_Notes.html
stm32f10x_stdperiph_lib_um.chm
其中Libraries包含了库的源代码,Project包含了各个外设的使用示例和模板,Utilities是使用ST公司评估板的示例,stm32f10x_stdperiph_lib_um.chm是标准库的帮助文档。

2.3 标准外设库结构

标准外设库源代码结构如下图所示:


图1 标准外设库结构分析

CMSIS文件夹提供了对STM32F10x系列芯片的Cortex-M3内核的支持。Documentation下有一个CMSIS_Core.html文件,该文件描述了CMSIS标准。CM3文件夹下的两个文件夹分别包括了核内外设访问层CPAL文件(core_cm3.h和core_cm3.c),STM32F10x系列MCU编写的设备外设访问层DPAL头文件stm32f10x.h,设备外设访问层系统文件DPALS(system_stm32f10x.h和system_stm32f10x.c)和根据4中不同编译环境编写的启动汇编代码startup文件。

2.3.1 CPAL文件

2.3.2 DPAL

设备外设访问层包括了STM32F10x系列处理器所有外设寄存器的定义、位定义和不同容量STM32F10x的内存映射。

CMSIS对异常和中断标识符、中断处理函数名以及中断向量异常号都有严格的要求。异常和中断标识符需加后缀_IRQn。系统向量好必须为负值,而设备中断向量号是从0开始递增的。对异常处理函数以及普通中断处理函数名的定义也有所不同,系统异常处理函数名需加后缀_Handler,而普通中断处理函数名则加后缀_IRQHandler。这些异常中断处理函数被定义为weak属性,以便在其他文件中重新实现时不出现重复定义的错误,这些处理函数的地址用来填充中断异常向量表,并在启动代码中给以声明,例如:NMI_Handler、MemManage_Handler、WWDG_IRQHandler等等。

2.3.3 DPLAS

设备外设访问层系统文件提供了两个函数和一个全局变量。

系统复位后,系统时钟采用的是内部高速时钟HSI(8MHz),然后通过SystemInit函数配置系统时钟,如果系统启动不成功,这SystemInit函数时钟配置不生效。HSE默认频率是8MHz,可在stm32f10x.h中修改“HSE_VALUE”的值来改变此值。

2.3.4 startup文件

该文件夹下根据4种不同编译环境编写了启动的汇编代码,主要完成STM32F10x系列芯片的系统所必要的初始化,主要包括:初始化堆栈指针SP、程序指针PC、中断向量配置、系统时钟配置。系统启动完毕后运行主程序。这些汇编文件是根据芯片的Flash容量来区分的,使用时需要注意。

3 标准外设驱动

3.1 缩写

缩写 外设
ADC 模数转换器
BKP 备份寄存器
CAN 控制器局域网模块
DMA 直接内存存取控制器
EXTI 外部中断事件控制器
FLASH 闪存存储器
GPIO 通用输入输出
I2C 内部集成电路
IWDG 独立看门狗
NVIC 嵌套中断向量列表控制器
PWR 电源/功耗控制
RCC 复位与时钟控制器
RTC 实时时钟
SPI 串行外设接口
SysTick 系统嘀嗒定时器
TIM 通用定时器
TIM1 高级控制定时器
USART 通用同步异步接收发射端
WWDG 窗口看门狗

3.2 命名规范

标准外设驱动包含了所有外设的驱动函数,固态函数库应遵从以下命名规则:

3.3 编码规则

3.3.1 变量

固态函数库定义了 24 个变量类型,他们的类型和大小是固定的。在文件 ***stm32f10x.h ***中我们定义了这些变量:

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.3.2 布尔型

在文件 ***stm32f10x.h ***中,布尔形变量被定义如下:

typedef enum
{
    FALSE = 0,
    TRUE = !FALSE
} bool;

3.3.3 标识位状态类型

在文件 ***stm32f10x.h ***中,我们定义标志位类型( ***FlagStatus ***type)的 2 个可能值为“设置”与“重置”( SETor RESET)。

typedef enum
{
    RESET = 0,
    SET = !RESET
} FlagStatus;

3.3.4 功能状态类型

在文件 ***stm32f10x.h ***中,我们定义功能状态类型( ***FunctionalState ***type)的 2 个可能值为“使能”与“失能”( ***ENABLE ***or DISABLE)。

typedef enum
{
    DISABLE = 0,
    ENABLE = !DISABLE
} FunctionalState;

3.3.5 错误状态类型

在文件 ***stm32f10x.h ***中,我们错误状态类型类型( ***ErrorStatus ***type)的 2 个可能值为“成功”与“出错”( ***SUCCESS ***or ERROR)。

typedef enum
{
    ERROR = 0,
    SUCCESS = !ERROR
} ErrorStatus;

3.3.6 外设

通过外设结构体的指针可以访问外设的寄存器,每个外设都有它自己的结构体和指针,所有结构体都定义在stm32f10x.h中。

以SPI寄存器结构体的声明为例:

/**  
   * @brief Serial  Peripheral Interface 
   */
typedef struct
{  
    __IO uint16_t CR1; 
    uint16_t  RESERVED0;
    __IO uint16_t CR2;
    uint16_t  RESERVED1;
    __IO uint16_t SR;
    uint16_t  RESERVED2;
    __IO uint16_t DR;
    uint16_t  RESERVED3;
    __IO uint16_t CRCPR;
    uint16_t  RESERVED4;
    __IO uint16_t RXCRCR;
    uint16_t  RESERVED5; 
    __IO uint16_t TXCRCR;
    uint16_t  RESERVED6;
    __IO uint16_t I2SCFGR;
    uint16_t  RESERVED7;
    __IO uint16_t I2SPR;
    uint16_t  RESERVED8; 
} SPI_TypeDef;

寄存器命名遵循上节的寄存器缩写命名规则。 RESERVEDi( i 为一个整数索引值)表示被保留区域。

以下示例展示了SPI外设的声明:

#define PERIPH_BASE ((u32)0x40000000)
#define APB1PERIPH_BASE PERIPH_BASE 
#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000)
...
/* SPI2 Base Address definition*/
#define SPI2_BASE (APB1PERIPH_BASE + 0x3800) 

外设寄存器按以下方式访问:

SPI1->CR1 = 0x0001;

每个外设都有若干寄存器专门分配给标志位用的,我们用专用的结构体定义这些寄存器。标志位的命名,同样遵循上节的外设缩写规范,以‘PPP_FLAG_’开始。对于不同的外设,标志位都被定义在相应的文件***stm32f10x_ppp.h ***中。

PPP_<register_name>_<bit_name> 

示例

#define SPI_CR2_RXDMAEN  ((uint8_t)0x01)  /*!<Rx Buffer DMA Enable */ 
#define SPI_CR2_TXDMAEN  ((uint8_t)0x02)  /*!<Tx Buffer DMA Enable */
#define SPI_CR2_SSOE  ((uint8_t)0x04)  /*!<SS Output Enable */ 
#define SPI_CR2_ERRIE ((uint8_t)0x20)  /*!<Error Interrupt Enable */ 
#define SPI_CR2_RXNEIE ((uint8_t)0x40)  /*!<RX buffer Not Empty Interrupt Enable */
#define SPI_CR2_TXEIE ((uint8_t)0x80)  /*!<Tx buffer Empty Interrupt Enable */

3.2.7 位段

Cortex-M3存储映射包括两个位段存储域,别名域的每个字对应位段域的一个位,对别名域读-改-写一个字对位段域目标位有相同的影响。所有STM32F10x外设寄存器都映射到位段域,这样可以使得对某个寄存器的某些位执行集中修改从而减少和优化代码。

/* Peripheral base address in the bit-band region */
#define PERIPH_BASE ((u32)0x40000000)
/* Peripheral address in the alias region */ 
#define PERIPH_BB_BASE ((u32)0x42000000) 
/* ----- RCC registers bit address in the alias region ------ */
#define RCC_OFFSET (RCC_BASE - PERIPH_BASE) 
/* --- CR Register ---*/ 
/* Alias word address of PLLON bit */ 
#define CR_OFFSET (RCC_OFFSET + 0x00) 
#define PLLON_BitNumber 0x18 
#define CR_PLLON_BB (PERIPH_BB_BASE + (CR_OFFSET * 32) + (PLLON_BitNumber * 4)) 

/*To code a function which enables/disables the 
PLL, the usual method is the following:*/
... 
#define CR_PLLON_Set ((u32)0x01000000) 
#define CR_PLLON_Reset ((u32)0xFEFFFFFF) 
...
void RCC_PLLCmd(FunctionalState NewState)
{ 
  if (NewState != DISABLE) 
  { 
    /* Enable PLL */
    RCC->CR |= CR_PLLON_Set;
  }
  else 
  { 
    /* Disable PLL */
    RCC->CR &= CR_PLLON_Reset;
  }
} 
/*Using bit-band access this function will be coded as follows:*/
void RCC_PLLCmd(FunctionalState NewState) 
{
  *(vu32 *) CR_PLLON_BB = (u32)NewState;
}

4 标准外设库使用

1.创建一个工程,设置工具链的启动文件(或者使用库中提供的模板工程,位于Project\STM32F10x_StdPeriph_Template目录下
依赖于所使用的设备选择合适的启动文件:

2.库的入口是stm32f10x.h(在Libraries/CMSIS/CM3/DeviceSupport/ST/STM32F10x目录下),用户必须在应用程序的main函数中包含并配置它:

#if !defined (STM32F10X_LD) && !defined (STM32F10X_LD_VL)\
&& !defined (STM32F10X_MD) && !defined (STM32F10X_MD_VL)\ 
&& !defined (STM32F10X_HD) && !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_VL */  /*!< STM32F10X_HD: STM32 High density Value line devices */
/* #define STM32F10X_HD */     /*!< STM32F10X_HD: STM32 High density devices */  
/* #define STM32F10X_XL  */    /*!< STM32F10X_CL: STM32 XL-density devices */  
/* #define STM32F10X_CL */     /*!< STM32F10X_CL: STM32 Connectivity line devices */
#endif

3.添加system_stm32f10x.c(在Libraries/CMSIS/CM3/DeviceSupport/ST/STM32F10x目录下)文件到应用程序中,这个文件提供了设置STM32系统的函数:配置PLL,系统时钟和初始化内嵌的FLASH接口。此文件对系统时钟频率提供了多个选择,可以根据程序的需要从下面列表(覆盖了大部分应用程序的通用时钟频率)中选择合适的频率:

#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

注意:此文件提供的系统时钟配置函数基于以下假设:

5 外设初始化和配置

这一章主要描述如何一步一步使用外设驱动初始化和配置一个外设,外设使用PPP表示。
1.在main函数文件中声明一个PPP_InitTypeDef结构体,例如:PPP_InitTypeDef PPP_InitStructrue;
2.用结构体成员允许的值填充PPP_Inittypedef的值,可以有两种方式:

PPP_InitStructure.member1 = val1;
PPP_InitStructure.member2 = val2;
/* where N is the number of the structure members */
PPP_InitStructure.memberN = valN; 

前面的初始化步骤可以合成一行以优化代码大小:

PPP_InitTypeDef PPP_InitStructure = { val1, val2,.., valN}
PPP_StructInit(&PPP_InitStructure);
/*where X and Y are the members the user wants to configure*/
PP_InitStructure.memberX = valX;
PPP_InitStructure.memberY = valY; 

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

PPP_Init(PPP, &PPP_InitStructure);

4.调用PPP_Cmd(...)函数使能外设。

PPP_Cmd(PPP, ENABLE);

然后就可以通过一系列外设专用的函数使用外设啦。
注意:
1.在配置外设前,必须调用下面中的一个使能外设的时钟:

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_PPPx, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_PPPx, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PPPx, ENABLE);

2.PPP_DeInit(...)函数可以设置PPP外设所有寄存器到默认值。

PPP_DeInit(PPP);

3.在配置了外设以后修改外设的配置,用户可以继续采用下面方式处理:

/* where X and Y are the only members that user wants to modify*/
PPP_InitStucture.memberX = valX;
PPP_InitStructure.memberY = valY; 
PPP_Init(PPP, &PPP_InitStructure);
上一篇 下一篇

猜你喜欢

热点阅读