GPIOx->BSRR = (((uint8 t32_t)0x01) << pinpos);

下次自动登录
现在的位置:
& 综合 & 正文
STM32学习笔记——GPIO之从库函数到寄存器
例子为单片机的“Hello World”级的流水灯实验——虽然只有一个,其中并不是将完整的代码给出,只是给出关键部分来说明“如何调用ST公司的的库来完成对硬件的控制,以及对库文件代码进行跟踪和分析至寄存器级”。所以从第一段代码往下看就可以了,要用到的函数和变量大部分会说明,至于寄存器级的,那就只能翻手册了。
GPIO(General
Purpose Input/Output) - 通用输入/输出
main.c :此函数为主函数,控制LED,亮1s,灭1s
int main(void)
//LED初始化
LED_Configuration();
GPIO_SetBits(GPIOB,GPIO_Pin_5);
Systick_DelayMs(1000);
//延时1s,自己实现的,暂不说明
GPIO_ResetBits(GPIOB,GPIO_Pin_5);
Systick_DelayMs(1000);
stm32f10x_gpio.c GPIO_SetBits和GPIO_ResetBits
Sets the selected data port bits.
GPIOx: where x can be (A..G) to select the GPIO peripheral.
GPIO_Pin: specifies the port bits to be written.
This parameter can be any combination of GPIO_Pin_x where x can be (0..15).
* @retval None
*/void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
/* Check the parameters */
assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
assert_param(IS_GPIO_PIN(GPIO_Pin));
GPIOx-&BSRR = GPIO_P
Clears the selected data port bits.
GPIOx: where x can be (A..G) to select the GPIO peripheral.
GPIO_Pin: specifies the port bits to be written.
This parameter can be any combination of GPIO_Pin_x where x can be (0..15).
* @retval None
*/void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
/* Check the parameters */
assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
assert_param(IS_GPIO_PIN(GPIO_Pin));
GPIOx-&BRR = GPIO_P
需要用到以下库文件:stm32f10x_rcc.c,stm32f10x_gpio.c--&STM32的I/O口初始化函数
void LED_Configuration(void)
/*设置PB.5为输出模式,用于LED*/
//定义一个GPIO数据结构,存放设置的参数
GPIO_InitTypeDef
GPIO_InitS
//要使用一个I/O口时,需要先打开相应I/O口所在口的时钟,如使能PB端口时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
//先设置要配置的引脚,LED0--&PB.5 端口配置
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
//配置为推挽输出模式
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
//配置I/O口速度为50MHz
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
//根据设定参数初始化GPIOB
GPIO_Init(GPIOB, &GPIO_InitStructure);
下面为LED_Configuration中涉及到的结构体变量和一些其他变量的出处:
stm32f10x_gpio.h
GPIO Init structure definition
typedef struct
uint16_t GPIO_P
/*!& Specifies the GPIO pins to be configured.
This parameter can be any value of @ref GPIO_pins_define */
GPIOSpeed_TypeDef GPIO_S
/*!& Specifies the speed for the selected pins.
This parameter can be a value of @ref GPIOSpeed_TypeDef */
GPIOMode_TypeDef GPIO_M
/*!& Specifies the operating mode for the selected pins.
This parameter can be a value of @ref GPIOMode_TypeDef */
} GPIO_InitTypeD
stm32f10x_gpio.h :每个GPIO口有0x10个。
/** @defgroup GPIO_pins_define
#define GPIO_Pin_0
((uint16_t)0x0001)
/*!& Pin 0 selected */#define GPIO_Pin_1
((uint16_t)0x0002)
/*!& Pin 1 selected */#define GPIO_Pin_2
((uint16_t)0x0004)
/*!& Pin 2 selected */#define GPIO_Pin_3
((uint16_t)0x0008)
/*!& Pin 3 selected */#define GPIO_Pin_4
((uint16_t)0x0010)
/*!& Pin 4 selected */#define GPIO_Pin_5
((uint16_t)0x0020)
/*!& Pin 5 selected */#define GPIO_Pin_6
((uint16_t)0x0040)
/*!& Pin 6 selected */#define GPIO_Pin_7
((uint16_t)0x0080)
/*!& Pin 7 selected */#define GPIO_Pin_8
((uint16_t)0x0100)
/*!& Pin 8 selected */#define GPIO_Pin_9
((uint16_t)0x0200)
/*!& Pin 9 selected */#define GPIO_Pin_10
((uint16_t)0x0400)
/*!& Pin 10 selected */#define GPIO_Pin_11
((uint16_t)0x0800)
/*!& Pin 11 selected */#define GPIO_Pin_12
((uint16_t)0x1000)
/*!& Pin 12 selected */#define GPIO_Pin_13
((uint16_t)0x2000)
/*!& Pin 13 selected */#define GPIO_Pin_14
((uint16_t)0x4000)
/*!& Pin 14 selected */#define GPIO_Pin_15
((uint16_t)0x8000)
/*!& Pin 15 selected */#define GPIO_Pin_All
((uint16_t)0xFFFF)
/*!& All pins selected */
stm32f10x_gpio.h : ,比51多多了
Configuration Mode enumeration
typedef enum
GPIO_Mode_AIN = 0x0,
/* 模拟输入模式 */
GPIO_Mode_IN_FLOATING = 0x04,
/* 浮空输入模式 */
GPIO_Mode_IPD = 0x28,
/* 下拉输入模式 */
GPIO_Mode_IPU = 0x48,
/* 上拉输入模式 */
GPIO_Mode_Out_OD = 0x14,
/* 通用推挽输出模式 */
GPIO_Mode_Out_PP = 0x10,
/* 通用开漏输出模式 */
GPIO_Mode_AF_OD = 0x1C,
/* 复用功能推挽输出模式 */
GPIO_Mode_AF_PP = 0x18
/* 复用功能开漏输出模式 */
} GPIOMode_TypeD
具体区别翻手册,也没记那么清楚~
stm32f10x_gpio.h
: 赋予GPIO的运行频率
Output Maximum frequency selection
typedef enum
GPIO_Speed_10MHz = 1,
GPIO_Speed_2MHz,
GPIO_Speed_50MHz
} GPIOSpeed_TypeD
枚举变量:GPIO_Speed_10MHz =1;GPIO_Speed_2MHz =2;GPIO_Speed_50MHz =3,速度写着呢,选一个就ok了~
stm32f10x.h
#define PERIPH_BASE
((uint32_t)0x) /*!& Peripheral base address in the alias region */
#define APB2PERIPH_BASE
(PERIPH_BASE + 0x10000)
#define GPIOA_BASE
(APB2PERIPH_BASE + 0x0800)#define GPIOB_BASE
(APB2PERIPH_BASE + 0x0C00)#define GPIOC_BASE
(APB2PERIPH_BASE + 0x1000)#define GPIOD_BASE
(APB2PERIPH_BASE + 0x1400)#define GPIOE_BASE
(APB2PERIPH_BASE + 0x1800)#define GPIOF_BASE
(APB2PERIPH_BASE + 0x1C00)#define GPIOG_BASE
(APB2PERIPH_BASE + 0x2000)
#define GPIOA
((GPIO_TypeDef *) GPIOA_BASE)#define GPIOB
((GPIO_TypeDef *) GPIOB_BASE)#define GPIOC
((GPIO_TypeDef *) GPIOC_BASE)#define GPIOD
((GPIO_TypeDef *) GPIOD_BASE)#define GPIOE
((GPIO_TypeDef *) GPIOE_BASE)#define GPIOF
((GPIO_TypeDef *) GPIOF_BASE)#define GPIOG
((GPIO_TypeDef *) GPIOG_BASE)
GPIOA=GPIOA_BASE=0xx
通过查询STM32微控制器开发手册可以得知,STM32的外设起始基地址为0x,而APB2总线设备起始地址相对于外设基地址的偏移量为0x10000,GPIOA设备相对于APB2总线设备起始地址偏移量为0x800。
注意:以上只是很小的一部分定义,stm32f10x.h文件的代码行数有8000多行。
下面为LED_Configuration中再配置完参数之后,将结构体中的参数写入到寄存器中的GPIO_Init初始化函数:
stm32f10x_gpio.c
Initializes the GPIOx peripheral according to the specified
parameters in the GPIO_InitStruct.
GPIOx: where x can be (A..G) to select the GPIO peripheral.
GPIO_InitStruct: pointer to a GPIO_InitTypeDef structure that
contains the configuration information for the specified GPIO peripheral.
* @retval None
*/void GPIO_Init(GPIO_TypeDef *GPIOx, GPIO_InitTypeDef *GPIO_InitStruct)
uint32_t currentmode = 0x00, currentpin = 0x00, pinpos = 0x00, pos = 0x00;
uint32_t tmpreg = 0x00, pinmask = 0x00;
/* Check the parameters */
//用断言来检查参数是否正确
assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
assert_param(IS_GPIO_MODE(GPIO_InitStruct-&GPIO_Mode));
assert_param(IS_GPIO_PIN(GPIO_InitStruct-&GPIO_Pin));
/*---------------------------- GPIO Mode Configuration -----------------------*/
//将工作模式暂存至currentmode变量中
currentmode = ((uint32_t)GPIO_InitStruct-&GPIO_Mode) & ((uint32_t)0x0F);
//如果欲设置为任意一种输出模式,则再检查“翻转速率”参数是否正确
if((((uint32_t)GPIO_InitStruct-&GPIO_Mode) & ((uint32_t)0x10)) != 0x00)
/* Check the parameters */
assert_param(IS_GPIO_SPEED(GPIO_InitStruct-&GPIO_Speed));
/* Output mode */
currentmode |= (uint32_t)GPIO_InitStruct-&GPIO_S
/*---------------------------- GPIO CRL Configuration ------------------------*/
/* Configure the eight low port pins */
//设置低8位引脚(即pin0~pin7)
if(((uint32_t)GPIO_InitStruct-&GPIO_Pin & ((uint32_t)0x00FF)) != 0x00)
//独处当前配置字
tmpreg = GPIOx-&CRL;
for(pinpos = 0x00; pinpos & 0x08; pinpos++)
pos = ((uint32_t)0x01) &&
/* Get the port pins position */
//获取将要配置的引脚号
currentpin = (GPIO_InitStruct-&GPIO_Pin) &
if(currentpin == pos)
//先清除对应引脚的配置字
pos = pinpos && 2;
/* Clear the corresponding low control register bits */
pinmask = ((uint32_t)0x0F) &&
tmpreg &= ~
/* Write the mode configuration in the corresponding bits */
//写入新的配置字
tmpreg |= (currentmode && pos);
/* Reset the corresponding ODR bit */
//若欲配置为上拉/下拉输入,则需要配置BRR和BSRR寄存器
if(GPIO_InitStruct-&GPIO_Mode == GPIO_Mode_IPD)
GPIOx-&BRR = (((uint32_t)0x01) && pinpos);
/* Set the corresponding ODR bit */
if(GPIO_InitStruct-&GPIO_Mode == GPIO_Mode_IPU)
GPIOx-&BSRR = (((uint32_t)0x01) && pinpos);
//写入低8位引脚配置字
GPIOx-&CRL =
/*---------------------------- GPIO CRH Configuration ------------------------*/
/* Configure the eight high port pins */
//设置高8位引脚(即pin8~pin15),流程和低8位引脚一致
if(GPIO_InitStruct-&GPIO_Pin & 0x00FF)
tmpreg = GPIOx-&CRH;
for(pinpos = 0x00; pinpos & 0x08; pinpos++)
pos = (((uint32_t)0x01) && (pinpos + 0x08));
/* Get the port pins position */
currentpin = ((GPIO_InitStruct-&GPIO_Pin) & pos);
if(currentpin == pos)
pos = pinpos && 2;
/* Clear the corresponding high control register bits */
pinmask = ((uint32_t)0x0F) &&
tmpreg &= ~
/* Write the mode configuration in the corresponding bits */
tmpreg |= (currentmode && pos);
/* Reset the corresponding ODR bit */
if(GPIO_InitStruct-&GPIO_Mode == GPIO_Mode_IPD)
GPIOx-&BRR = (((uint32_t)0x01) && (pinpos + 0x08));
/* Set the corresponding ODR bit */
if(GPIO_InitStruct-&GPIO_Mode == GPIO_Mode_IPU)
GPIOx-&BSRR = (((uint32_t)0x01) && (pinpos + 0x08));
GPIOx-&CRH =
这段程序的流程:首先检查由结构体变量GPIO_InitStructure所传入的参数是否正确,然后对GPIO寄存器进行“读出-&修改-&写入”操作,完成对GPIO设备的配置工作。
总结起来就是:固件库首先将各个设备所有的寄存器的配置字进行预先定义在stm32f10x.h文件中,然后封装在结构或枚举变量中(存在相对应的stm32f10x_xxx.h,其中xxx代表gpio,spi,exti等外设模块),待用户调用对应的固件库函数时,会根据用户传入的参数从这些封装好的结构体或枚举变量中取出对应的配置字,最后写入寄存器中,完成对底层寄存器的配置。
stdint.h 一些具有可移植性的变量重定义
* 'signed' is redundant below, except for 'signed char' and if
* the typedef is used to declare a bitfield.
* '__int64' is used instead of 'long long' so that this header
* can be used in --strict mode.
/* 7.18.1.1 */
/* exact-width signed integer types */typedef
char int8_t;typedef
signed short
int int16_t;typedef
int int32_t;typedef
__int64 int64_t;
/* exact-width unsigned integer types */typedef unsigned
char uint8_t;typedef unsigned short
int uint16_t;typedef unsigned
int uint32_t;typedef unsigned
__int64 uint64_t;
/* 7.18.1.2 */
/* smallest type of at least n bits *//* minimum-width signed integer types */typedef
char int_least8_t;typedef
signed short
int int_least16_t;typedef
int int_least32_t;typedef
__int64 int_least64_t;
/* minimum-width unsigned integer types */typedef unsigned
char uint_least8_t;typedef unsigned short
int uint_least16_t;typedef unsigned
int uint_least32_t;typedef unsigned
__int64 uint_least64_t;
/* 7.18.1.3 */
/* fastest minimum-width signed integer types */typedef
int int_fast8_t;typedef
int int_fast16_t;typedef
int int_fast32_t;typedef
__int64 int_fast64_t;
/* fastest minimum-width unsigned integer types */typedef unsigned
int uint_fast8_t;typedef unsigned
int uint_fast16_t;typedef unsigned
int uint_fast32_t;typedef unsigned
__int64 uint_fast64_t;
/* 7.18.1.4 integer types capable of holding object pointers */typedef
int intptr_t;typedef unsigned
int uintptr_t;
/* 7.18.1.5 greatest-width integer types */typedef
__int64 intmax_t;typedef unsigned
__int64 uintmax_t;
&&&&推荐文章:
【上篇】【下篇】意法半导体在推出STM32微控制器之初,也同时提供了一套完整细致的固件开发包,里面包含了在STM32开发过程中所涉及到的所有底层操作。通过在程序开发中引入这样的固件开发包,可以使开发人员从复杂冗余的底层寄存器操作中解放出来,将精力专注应用程序的开发上,这便是ST推出这样一个开发包的初衷。
但这对于许多从51/AVR这类单片机的开发转到STM32平台的开发人员来说,势必有一个不适应的过程。因为程序开发不再是从寄存器层次起始,而要首先去熟悉STM32所提供的固件库。那是否一定要使用固件库呢?当然不是。但STM32微控制器的寄存器规模可不是常见的8位单片机可以比拟,若自己细细琢磨各个寄存器的意义,必然会消耗相当的时间,并且对于程序后续的维护,升级来说也会增加资源的消耗。对于当前“时间就是金钱”的行业竞争环境,无疑使用库函数进行STM32的产品开发是更好的选择。本文将通过一个简单的例子对STM32的库函数做一个简单的剖析。
以最常用的GPIO设备的初始化函数为例,如下程序段一:
GPIO_InitTypeDef GPIO_InitS&&&&&&&&&&&&&&&&&&&& &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& 1
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& 2
GPIO_InitStructure.GPIO_Speed =
GPIO_Speed_50MHz;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& 3
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& 4
GPIO_Init(GPIOA , &GPIO_InitStructure);
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& 5
这是一个在STM32的程序开发中经常使用到的GPIO初始化程序段,其功能是将GPIOA.4口初始化为推挽输出状态,并最大翻转速率为50MHz。下面逐一分解:
l首先是1,该语句显然定义了一个GPIO_InitTypeDef类型的变量,名为GPIO_InitStructure,则找出GPIO_InitTypeDef的原型位于“stm32f10x_gpio.h”文件,原型如下:
typedef struct
u16 GPIO_P
GPIOSpeed_TypeDef GPIO_S
GPIOMode_TypeDef GPIO_M
}GPIO_InitTypeD
(310.69 KB, 下载次数: 5934)
22:23 上传
点击文件名下载附件
[ 本帖最后由 losingamong 于
22:23 编辑 ]
回复查看:tongue: :tongue: :tongue:&
多谢分享!学习&
为嘛回复依然看不到PDF呢&
正好学习下&
&&&&&&&&&&
在线时间429 小时
威望2149分
芯币3918枚
TA的帖子TA的资源
五彩晶圆(初级), 积分 2149, 距离下一级还需 1351 积分
五彩晶圆(初级), 积分 2149, 距离下一级还需 1351 积分
由此可知GPIO_InitTypeDef是一个结构体类型同义字,其功能是定义一个结构体,该结构体有三个成员分别是u16类型的GPIO_Pin、GPIOSpeed_TypeDef 类型的GPIO_Speed和GPIOMode_TypeDef 类型的GPIO_Mode。继续探查GPIOSpeed_TypeDef和GPIOMode_TypeDef类型,在“stm32f10x_gpio.h”文件中找到对GPIOSpeed_TypeDef的定义:
& & & & typedef enum
&&& & & & & & & & GPIO_Speed_10MHz = 1,
&&& & & & & & & & GPIO_Speed_2MHz,
&&& & & & & & & & GPIO_Speed_50MHz
}GPIOSpeed_TypeD
则可知GPIOSpeed_TypeDef枚举类型同一只,其功能是定义一个枚举类型变量,该变量可表示GPIO_Speed_10MHz、GPIO_Speed_2MHz和GPIO_Speed_50MHz三个含义(其中GPIO_Speed_10MHz已经定义为1,读者必须知道GPIO_Speed_2MHz则依次被编译器赋予2,而GPIO_Speed_50MHz为3)。
同样也在“stm32f10x_gpio.h”文件中找到对GPIOMode_TypeDef的定义:
typedef enum
GPIO_Mode_AIN = 0x0,
& & & & GPIO_Mode_IN_FLOATING = 0x04,
&&GPIO_Mode_IPD = 0x28,
&&GPIO_Mode_IPU = 0x48,
&&GPIO_Mode_Out_OD = 0x14,
&&GPIO_Mode_Out_PP = 0x10,
&&GPIO_Mode_AF_OD = 0x1C,
&&GPIO_Mode_AF_PP = 0x18
}GPIOMode_TypeD
这同样是一个枚举类型同义字,其成员有GPIO_Mode_AIN、GPIO_Mode_AF_OD等(也可以轻易判断出这表示GPIO设备的工作模式)。
至此对程序段一的○1解析可以做一个总结:
该行定义一个结构体类型的变量GPIO_InitStructure,并且该结构体有3个成员,分别为GPIO_Pin、GPIO_Speed和GPIO_Mode,并且GPIO_Pin表示GPIO设备引脚GPIO_Speed表示GPIO设备速率和GPIO_Mode表示GPIO设备工作模式。
接下来是2,此句是一个赋值语句,把GPIO_Pin_4赋给GPIO_InitStructure结构体中的成员GPIO_Pin,可以在“stm32f10x_gpio.h”文件中找到对GPIO_Pin_4做的宏定义:
#define GPIO_Pin_4& & & & & & & & ((u16)0x0010)
& & & & 因此○2的本质是将16位数0x0010赋给GPIO_InitStructure结构体中的成员GPIO_Pin。
3语句和2相似将GPIO_Speed_50MHz赋给GPIO_InitStructure结构体中的成员GPIO_Speed,但注意到此处GPIO_Speed_50MHz只是一个枚举变量,并非具体的某个值。
4语句亦和2语句类似,把GPIO_Mode_Out_PP赋给GPIO_InitStructure结构体中的成员GPIO_Mode,从上文可知GPIO_Mode_Out_PP的值为0x10。
5是一个函数调用,即调用GPIO_Init函数,并提供给该函数2个参数,分别为GPIOA和&GPIO_InitStructure,其中&GPIO_InitStructure表示结构体变量GPIO_InitStructure的地址,而GPIOA则在“stm32f10x_map.h”文件中找到定义:
#ifdef _GPIOA
#define GPIOA& && && && && &((GPIO_TypeDef *) GPIOA_BASE)
此三行代码是一个预编译结构,首先判断是否定义了宏_GPIOA。可以在“stm32f10x_conf.h”中发现对_GPIOA的定义为:
#define _GPIOA
这表示编译器会将代码中出现的GPIOA全部替换为((GPIO_TypeDef *) GPIOA_BASE)。从该句的C语言语法可以判断出((GPIO_TypeDef *) GPIOA_BASE)的功能为将GPIOA_BASE强制类型转换为指向GPIO_TypeDef类型的结构体变量。如此则需要找出GPIOA_BASE的含义,依次在“stm32f10x_map.h”文件中找到:
#define GPIOA_BASE& && && && &(APB2PERIPH_BASE + 0x0800)
#define APB2PERIPH_BASE& && & (PERIPH_BASE + 0x10000)
#define PERIPH_BASE& && && &&&((u32)0x)
明显GPIOA_BASE表示一个地址,通过将以上3个宏展开可以得到:
GPIOA_BASE = 0x + 0x10000 + 0x0800
此处的关键便在于0xx10这三个数值的来历。读者应该通过宏名猜到了,这就是STM32微控制器的GPIOA的设备地址。通过查阅STM32微控制器开发手册可以得知,STM32的外设起始基地址为0x,而APB2总线设备起始地址相对于外设基地址的偏移量为0x10000,GPIOA设备相对于APB2总线设备起始地址偏移量为0x0800。
对○5句代码进行一个总结:调用GPIO_Init函数,并将STM32微控制器的GPIOA设备地址和所定义的结构体变量GPIO_InitStructure的地址传入。
& & & & 以上是对GPIOA初始化库函数的剖析,现继续转移到函数内部分析,GPIO_Init函数原型如程序段二:
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)
& & & & u32 currentmode = 0x00, currentpin = 0x00, pinpos = 0x00, pos = 0x00;
& & & & u32 tmpreg = 0x00, pinmask = 0x00;
& & & & /* 检查参数是否正确 */
& & & & assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
& & & & assert_param(IS_GPIO_MODE(GPIO_InitStruct-&GPIO_Mode));
& & & & assert_param(IS_GPIO_PIN(GPIO_InitStruct-&GPIO_Pin));&&
& & & & /* 将工作模式暂存至 currentmode 变量中 */
& & & & currentmode = ((u32)GPIO_InitStruct-&GPIO_Mode) & ((u32)0x0F);
& & & & /* 如果欲设置为任意一种输出模式,则再检查”翻转速率“参数是否正确 */
& & & & if ((((u32)GPIO_InitStruct-&GPIO_Mode) & ((u32)0x10)) != 0x00)
& & & & & & & & assert_param(IS_GPIO_SPEED(GPIO_InitStruct-&GPIO_Speed));
& & & & & & & & currentmode |= (u32)GPIO_InitStruct-&GPIO_S
& & & & /* 设置低八位引脚(即 pin0 ~ pin7) */
& & & & if (((u32)GPIO_InitStruct-&GPIO_Pin & ((u32)0x00FF)) != 0x00)
& & & & & & & & /* 读出当前配置字 */
& & & & & & & & tmpreg = GPIOx-&CRL;& & & &
& & & & & & & & for (pinpos = 0x00; pinpos & 0x08; pinpos++)
& & & & & & & & {
& & & & & & & & & & & & /* 获取将要配置的引脚号 */
& & & & & & & & & & & & pos = ((u32)0x01) &&
& & & & & & & & & & & & currentpin = (GPIO_InitStruct-&GPIO_Pin) &
& & & & & & & & & & & & if (currentpin == pos)
& & & & & & & & & & & & {
& & & & & & & & & & & & & & & & /* 先清除对应引脚的配置字 */
& & & & & & & & & & & & & & & & pos = pinpos && 2;
& & & & & & & & & & & & & & & & pinmask = ((u32)0x0F) &&
& & & & & & & & & & & & & & & & tmpreg &= ~
& & & & & & & & & & & & & & & & /* 写入新的配置字 */
& & & & & & & & & & & & & & & & tmpreg |= (currentmode && pos);
& & & & & & & & & & & & & & & & /* 若欲配置为上拉 / 下拉输入,则需要配置 BRR 和 BSRR寄存器 */
& & & & & & & & & & & & & & & & if (GPIO_InitStruct-&GPIO_Mode == GPIO_Mode_IPD)
& & & & & & & & & & & & & & & & {
& & & & & & & & & & & & & & & & & & & & GPIOx-&BRR = (((u32)0x01) && pinpos);
& & & & & & & & & & & & & & & & }
& & & & & & & & & & & & & & & & else
& & & & & & & & & & & & & & & & {
& & & & & & & & & & & & & & & & & & & & if (GPIO_InitStruct-&GPIO_Mode == GPIO_Mode_IPU)
& & & & & & & & & & & & & & & & & & & & {
& & & & & & & & & & & & & & & & & & & & & & & & GPIOx-&BSRR = (((u32)0x01) && pinpos);
& & & & & & & & & & & & & & & & & & & & }
& & & & & & & & & & & & & & & & }
& & & & & & & & & & & & }
& & & & & & & & }
& & & & & & & & /* 写入低八位引脚配置字 */
& & & & & & & & GPIOx-&CRL =
& & & & /* 设置高八位引脚(即 pin8 ~ pin15),流程和第八位引脚配置流程一致,不再作解析 */
& & & & if (GPIO_InitStruct-&GPIO_Pin & 0x00FF)
& & & & & & & & tmpreg = GPIOx-&CRH;
& & & & & & & & for (pinpos = 0x00; pinpos & 0x08; pinpos++)
& & & & & & & & {
& & & & & & & & & & & & pos = (((u32)0x01) && (pinpos + 0x08));
& & & & & & & & & & & & currentpin = ((GPIO_InitStruct-&GPIO_Pin) & pos);
& & & & & & & & & & & & if (currentpin == pos)
& & & & & & & & & & & & {
& & & & & & & & & & & & & & & & pos = pinpos && 2;
& & & & & & & & & & & & & & & & pinmask = ((u32)0x0F) &&
& & & & & & & & & & & & & & & & tmpreg &= ~
& & & & & & & & & & & & & & & & tmpreg |= (currentmode && pos);
& & & & & & & & & & & & & & & & if (GPIO_InitStruct-&GPIO_Mode == GPIO_Mode_IPD)
& & & & & & & & & & & & & & & & {
& & & & & & & & & & & & & & & & & & & & GPIOx-&BRR = (((u32)0x01) && (pinpos + 0x08));
& & & & & & & & & & & & & & & & }
& & & & & & & & & & & & & & & & if (GPIO_InitStruct-&GPIO_Mode == GPIO_Mode_IPU)
& & & & & & & & & & & & & & & & {
& & & & & & & & & & & & & & & & & & & & GPIOx-&BSRR = (((u32)0x01) && (pinpos + 0x08));
& & & & & & & & & & & & & & & & }
& & & & & & & & & & & & }
& & & & & & & & }
& & & & & & & & GPIOx-&CRH =
& && &&&这段程序的流程是:首先检查由结构体变量GPIO_InitStructure所传入的参数是否正确,然后对GPIO寄存器进行“保存——修改——写入”的操作,完成对GPIO设备的设置工作。显然,结构体变量GPIO_InitStructure所传入参数的目的是设置对应GPIO设备的寄存器。而STM32的参考手册对关于GPIO设备的设置寄存器的描述如下图1和表1(仅列出低八位引脚寄存器描述,高八位引脚类同):
该寄存器为32位,其中分为8份,每份4位,对应低八位引脚的设置。每一个引脚的设置字分为两部分,分别为CNF和MODE,各占两位空间。当MODE的设置字为0时,表示将对应引脚配置为输入模式,反之设置为输出模式,并有最大翻转速率限制。而当引脚配置为输出模式时,CNF配置字则决定引脚以哪种输出方式工作(通用推挽输出、通用开漏输出等)。通过对程序的阅读和分析不难发现,本文最初程序段中GPIO_InitStructure所传入参数的对寄存器的作用如下:
1、GPIO_Pin_4被宏替换为0x0010,对应图1可看出为用于选择配置GPIOx_CRL的[19:16]位,分别为CNF4[1:0]、MODE4[1:0]。
2、GPIO_Speed_50MHz为枚举类型,包含值0x03,被用于将GPIOx_CRL位中的MODE4[1:0]配置为b11(此处b意指二进制)。
3、GPIO_Mode亦为枚举类型,包含值0x10,被用于将GPIOx_CRL位中的MODE4[1:0]配置为b00。事实上GPIO_Mode的值直接影响寄存器的只有低四位,而高四位的作用可以从程序段二中看出,是用于判断此参数是否用于GPIO引脚输出模式的配置。
至此应不难知道STM32的固件库最后是怎样影响最底层的寄存器的。总结起来就是:固件库首先将各个设备所有寄存器的配置字进行预先定义,然后封装在结构或枚举变量中,待用户调用对应的固件库函数时,会根据用户传入的参数从这些封装好的结构或枚举变量中取出对应的配置字,最后写入寄存器中,完成对底层寄存器的配置。
可以看到,STM32的固件库函数对于程序开发人员来说是十分便利的存在,只需要填写言简意赅的参数就可以在完全不关心底层寄存器的前提下完成相关寄存器的配置,具有相当不错的通用性和易用性,也采取了一定措施保证库函数的安全性(主要引入了参数检查函数assert_param)。但同时也应该知道,通用性、易用性和安全性的代价是加大了代码量,同时增加了一些逻辑判断代码造成了一定的时间消耗,在对时间要求比较苛刻的应用场合需要评估使用固件库函数对程序运行时间所带来的影响。读者在使用STM32的固件库函数进行程序开发时,应该意识到这些问题。
[ 本帖最后由 losingamong 于
22:17 编辑 ]
太感谢了,一直不清楚到底是怎么回事。现在明白了&
Look,look&
一点都不会啊&
在线时间429 小时
威望2149分
芯币3918枚
TA的帖子TA的资源
五彩晶圆(初级), 积分 2149, 距离下一级还需 1351 积分
五彩晶圆(初级), 积分 2149, 距离下一级还需 1351 积分
编辑帖子太纠结了,估计看的人也纠结,论坛的编辑器 ……还是上pdf吧,一楼,老规矩,回复可见。 PS:问部分小仙,是不是有的人不回复也可见?&
[ 本帖最后由 losingamong 于
22:22 编辑 ]
楼主讲得精辟啊&
好东西 学习学习 谢谢&
感谢楼主分享,楼主辛苦了&
感謝分享~!&
再看看吧!&
在线时间267 小时
威望3392分
芯币2490枚
TA的帖子TA的资源
五彩晶圆(初级), 积分 3392, 距离下一级还需 108 积分
五彩晶圆(初级), 积分 3392, 距离下一级还需 108 积分
恩,来学习下!!!
邮箱:ternence.
在线时间120 小时
TA的帖子TA的资源
一粒金砂(中级), 积分 10, 距离下一级还需 190 积分
一粒金砂(中级), 积分 10, 距离下一级还需 190 积分
看一下附件,LZ辛苦了
正好学习一下&
我回复了,可是看不到附件......&
在线时间25 小时
威望5553分
芯币1945枚
TA的帖子TA的资源
五彩晶圆(中级), 积分 5553, 距离下一级还需 447 积分
五彩晶圆(中级), 积分 5553, 距离下一级还需 447 积分
原帖由 losingamong 于
22:19 发表
编辑帖子太纠结了,估计看的人也纠结,论坛的编辑器 ……还是上pdf吧,一楼,老规矩,回复可见。 PS:问部分小仙,是不是有的人不回复也可见?&
回楼主:不回复 不可见
在线时间9377 小时
威望185571分
芯币17256枚
TA的帖子TA的资源
回复 板凳 losingamong 的帖子
请问楼主 编辑器遇到了什么问题?
2017,加油!继续为中国电子行业做出小小的贡献吧!
在线时间1794 小时
威望8338分
芯币11175枚
E金币126枚
TA的帖子TA的资源
五彩晶圆(高级), 积分 8338, 距离下一级还需 1662 积分
五彩晶圆(高级), 积分 8338, 距离下一级还需 1662 积分
楼主很善于思考
在线时间33 小时
TA的帖子TA的资源
一粒金砂(中级), 积分 80, 距离下一级还需 120 积分
一粒金砂(中级), 积分 80, 距离下一级还需 120 积分
嗯,论坛的编辑器要改进才行啊!
在线时间4 小时
TA的帖子TA的资源
一粒金砂(初级), 积分 1, 距离下一级还需 4 积分
一粒金砂(初级), 积分 1, 距离下一级还需 4 积分
嗯,论坛的编辑器要改进才行啊!
<p id="rate_820" onmouseover="showTip(this)" tip="&威望 + 1 分
" class="mtn mbn">
在线时间68 小时
TA的帖子TA的资源
一粒金砂(中级), 积分 62, 距离下一级还需 138 积分
一粒金砂(中级), 积分 62, 距离下一级还需 138 积分
在线时间0 小时
TA的帖子TA的资源
一粒金砂(初级), 积分 0, 距离下一级还需 5 积分
一粒金砂(初级), 积分 0, 距离下一级还需 5 积分
在线时间16 小时
TA的帖子TA的资源
一粒金砂(高级), 积分 290, 距离下一级还需 210 积分
一粒金砂(高级), 积分 290, 距离下一级还需 210 积分
了解一下。
在线时间752 小时
芯币18009枚
TA的帖子TA的资源
纯净的硅(初级), 积分 680, 距离下一级还需 120 积分
纯净的硅(初级), 积分 680, 距离下一级还需 120 积分
在线时间1 小时
TA的帖子TA的资源
一粒金砂(初级), 积分 0, 距离下一级还需 5 积分
一粒金砂(初级), 积分 0, 距离下一级还需 5 积分
谢谢楼主~~~~
在线时间4 小时
TA的帖子TA的资源
一粒金砂(初级), 积分 0, 距离下一级还需 5 积分
一粒金砂(初级), 积分 0, 距离下一级还需 5 积分
多谢指点,好老师!
在线时间19 小时
TA的帖子TA的资源
一粒金砂(初级), 积分 0, 距离下一级还需 5 积分
一粒金砂(初级), 积分 0, 距离下一级还需 5 积分
回复 楼主 losingamong 的帖子
回复一下,看看是否可见!
在线时间4 小时
TA的帖子TA的资源
一粒金砂(初级), 积分 0, 距离下一级还需 5 积分
一粒金砂(初级), 积分 0, 距离下一级还需 5 积分
&& 看看,呵呵。我是新手,很需要哦。
在线时间16 小时
TA的帖子TA的资源
一粒金砂(中级), 积分 10, 距离下一级还需 190 积分
一粒金砂(中级), 积分 10, 距离下一级还需 190 积分
在线时间0 小时
TA的帖子TA的资源
一粒金砂(初级), 积分 0, 距离下一级还需 5 积分
一粒金砂(初级), 积分 0, 距离下一级还需 5 积分
对新手很有有用啊!
1 / 108 页
资源大师勋章
在下载中心贡献超过4000份资料
论坛测评队员
EEWORLD 官方微信
Powered by

我要回帖

更多关于 uint32 t 的文章

 

随机推荐