2.3 外设的初始化和设置
本节按步骤描述了如何初始化和设置任意外设。这里PPP代表任意外设。 1.在主应用文件中,声明一个结构PPP_InitTypeDef,例如:
PPP_InitTypeDef PPP_InitStructure;
这里PPP_InitStructure是一个位于内存中的工作变量,用来初始化一个或者多个外设PPP。
2.为变量PPP_InitStructure的各个结构成员填入允许的值。可以采用以下2种方式: a)按照如下程序设置整个结构体 PPP_InitStructure.member1=val1; PPP_InitStructure.member2 = val2; PPP_InitStructure.memberN = valN;
/* where N is the number of the structure members */ 以上步骤可以合并在同一行里,用以优化代码大小:
PPP_InitTypeDef PPP_InitStructure = { val1, val2,.., valN}
b)仅设置结构体中的部分成员:这种情况下,用户应当首先调用函数PPP_SturcInit(..)来初始化变量PPP_InitStructure,然后再修改其中需要修改的成员。这样可以保证其他成员的值(多为缺省值)被正确填入。
PPP_StructInit(&PPP_InitStructure); PP_InitStructure.memberX = valX; PPP_InitStructure.memberY = valY;
/*where X and Y are the members the user wants to configure*/
3. 调用函数PPP_Init(..)来初始化外设PPP。
4. 在这一步,外设PPP已被初始化。可以调用函数PPP_Cmd(..)来使能之。
PPP_Cmd(PPP, ENABLE);
可以通过调用一系列函数来使用外设。每个外设都拥有各自的功能函数。更多细节参阅 Section3 外设固件概述。
注: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. 在外设设置完成以后,继续修改它的一些参数,可以参照如下步骤:
PPP_InitStucture.memberX = valX;
PPP_InitStructure.memberY = valY; /* where X and Y are the only members that user wants to modify*/ PPP_Init(PPP, &PPP_InitStructure);
2.4 位段(Bit-Banding)
Cortex?-M3 存储器映像包括两个位段(bit-band)区。这两个位段区将别名存储器区中的每个字映射到位段存储器区的一个位,在别名存储区写入一个字具有对位段区的目标位执行读-改-写操作的相同效果。所有STM32F10x外设寄存器都被映射到一个位段(bit-band)区。这个特性在各个函数中对单个比特进行置1/置0操作时被大量使用,用以减小和优化代码尺寸。
Section 2.4.1和Section 2.4.2给出了外设固件函数库中如何实现位段访问的描述。
2.4.1 映射公式
映射公式给出了别名区中的每个字是如何对应位带区的相应位的,公式如下: bit_word_offset = (byte_offset x 32) + (bit_number × 4) bit_word_addr = bit_band_base + bit_word_offset 其中:
bit_word_offset是目标位在存取器位段区中的位置。
bit_word_addr 是别名存储器区中字的地址,它映射到某个目标位。 bit_band_base 是别名区的起始地址。
byte_offset 是包含目标位的字节在位段里的序号。 bit_number 是目标位所在位置(0-31)。
2.4.2 应用实例
下例展现了如何把寄存器RCC_CR的PLLON[24]位,映射到别名区:
/* 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))
编写一个使能/失能PLL的函数,步骤如下:
...
#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; }
2.5 运行时间检测
固件函数库通过检查库函书的输入来实现运行时间错误侦测。通过使用宏assert_param来实现运行时间检测。所有要求输入参数的函数都使用这个宏。它可以检查输入参数是否在允许的范围之内。
例:函数PWR_ClearFlag stm32f10x_pwr.c:
void PWR_ClearFlag(u32 PWR_FLAG) {
/* Check the parameters */
assert_param(IS_PWR_CLEAR_FLAG(PWR_FLAG)); PWR->CR |= PWR_FLAG << 2; }
stm32f10x_pwr.h:
/* PWR Flag */
#define PWR_FLAG_WU ((u32)0x00000001) #define PWR_FLAG_SB ((u32)0x00000002) #define PWR_FLAG_PVDO ((u32)0x00000004)
#define IS_PWR_CLEAR_FLAG(FLAG) ((FLAG == PWR_FLAG_WU) || (FLAG == PWR_FLAG_SB)
如果传给宏assert_param的参数为false,则调用函数assert_failed并返回被错误调用的函数所在的文件名和行数。如果传给宏assert_param的参数为true,则无返回值。 宏assert_param编写于文件stm32f10x_conf.h中:
/* Exported macro ------------------------------------------------------------*/ #ifdef DEBUG
/******************************************************************************* * * Macro Name : assert_param
* Description : The assert_param macro is used for function's parameters check. * It is used only if the library is compiled in DEBUG mode.
* Input : - expr: If expr is false, it calls assert_failed function. * which reports the name of the source file and the source * line number of the call that failed. * If expr is true, it returns no value. * Return : None
*******************************************************************************/ #define assert_param(expr) ((expr) ? (void)0 : assert_failed((u8 *)__FILE__, __LINE__))
/* Exported functions ------------------------------------------------------- */ void assert_failed(u8* file, u32 line); #else
#define assert_param(expr) ((void)0) #endif /* DEBUG */
函数assert_failed编写于文件main.c或者其他用户C文件:
#ifdef DEBUG
/****************************************************************** * Function name : assert_failed
* Description : Reports the name of the source file and the source line number. * where the assert_param error has occurred. * Input : - file: pointer to the source file name
* - line: assert_param error line source number * Output : None * Return : None
******************************************************************/ void assert_failed(u8* file, u32 line) {
/* User can add his own implementation to report the file name and line number, ex: printf(\/* Infinite loop */ while (1) { } } #endif
注:
运行时间检查,即宏assert_param应当只在库在Debug模式下编译时使用。建议在用户应用代码的开发和调试阶段使用运行时间检查,在最终的代码中去掉它们以改进代码尺寸和速度。
如果用户仍然希望在最终的代码中保留这项功能,可以在调用库函数前,重新使用宏assert_param来测试输入参数。