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

Cortex-M3(STM32和NXPLPC1768)(4)
1)不改变其他位的值的状态下,对某几位进行设置初始值
这个场景,单片机开发中经常使用,方法就是先对需要设置的位用&符号进行清零操作,然后用|操作符设定数值,比如我们经常改变GPIO的状态,可以先对寄存器的值进行清零操作&
GPIOA -&CRL &= 0xFFFF FF0F; &//将第4-7位清零
GPIOA -&CRL &= 0x; //设置相应位的值,不改变其他位置的数值
2)移位操作提高代码的可读性
移位操作在单片机开发中非常重要,固件库中GPIO初始化的函数里面有一行代码
GPIOx -& BSRR = (((uint 32_t)0x01)&&pinpos); //
这个操作就是将BSRR寄存器的第pinpos位置设为1,为什么要通过左移而不是直接设定一个固定的值呢?其实这是为了提高代码的可读性以及可重用性。这行代码可以很直观明了的知道,是将第pinpos位设置为1,如果写成 &BPIOx -& BSRR = 0x0030;需要你转换为二进制才能来清楚是哪位进行了置1,这样的代码就不好看也不好重用了,类似的代码可以写为 &GPIOA -& ODR |= 1&&5; &//PA.5输出高,不改变其他位
3)~取反操作使用技巧
SR寄存器的每一位都代表一个状态,某个时刻我们希望去设置某一位的值为0,同时保留其他位都为1,简单的做法是直接给寄存器设置一个值: TIMx -&SR = 0xFFF7;
这样的做法设计第3位为0,但是这样的做法同样不好看,并且可读性很差。
库函数给出一种很好的写作方法, TIMx -& SR = (uint16_t)~TIM_FLAG;
而TIM_FLAG是通过宏定义定义的值:#define TIM_FLAG &((uint16_t)0x0001) &这样的方法就可以看出来设置的第0位了。可读性非常强
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:6715次
排名:千里之外
原创:29篇
(1)(3)(6)(5)(2)(3)(3)(1)(2)(2)(1)(1)(1)(5)(1)C__Users_xujianping_Desktop_STM32 GPIO_Init 详细分析_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
C__Users_xujianping_Desktop_STM32 GPIO_Init 详细分析
&&STM32 GPIO配置详解
阅读已结束,如果下载本文需要使用1下载券
想免费下载本文?
定制HR最喜欢的简历
你可能喜欢下次自动登录
现在的位置:
& 综合 & 正文
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;
&&&&推荐文章:
【上篇】【下篇】2181人阅读
STM32的GPIO使用的函数剖析
STM32的总结
该文是自己学习了一段STM32后所写,是对STM32使用固件库编程最简单的一段程序,是对固件库函数的一部分进行解析。如有错误之处请指正,不胜感激。
一、GPIO_Init函数解析
首先来看一下GPIO_Init函数的原型void&GPIO_Init(GPIO_TypeDef*&GPIOx,&GPIO_InitTypeDef*&GPIO_InitStruct)。这个函数的实现是在文件中,若要使用该函数在相应的应用程序的前面包含头文件。
1、参数GPIO_TypeDef
该函数的第一个参数为,它是一个结构体类型,该类型在中被定义。定义的原型为:
typedef&struct
&&__IO&uint32_t&CRL;
&&__IO&uint32_t&CRH;
&&__IO&uint32_t&IDR;
&&__IO&uint32_t&ODR;
&&__IO&uint32_t&BSRR;
&&__IO&uint32_t&BRR;
&&__IO&uint32_t&LCKR;
}&GPIO_TypeD
在这个结构体类型当中有个(字节)位的变量,这些变量在存储空间的地址是相邻的。打开数据手册不难看出,每个端口对应有的引脚,由个寄存器控制行为,并且这个寄存器的顺序也是连续的。各个端口都有相同的结构。的固件库就将这种结构抽象出一个类型。在操作寄存器之前你一定要有一个寄存器映射的操作,否则无法访问指定的寄存器,在这里我们只需要映射一次而不需要映射此。这样做是不是很方便,也提高了代码的可读性,使代码规范化。
既然的第一个参数的指针变量,这个指针变量存放的就是某一个端口的首地址。某一个程序的调用语句是这样的初始化
GPID是固件库中定义的一个宏,在编译的时候会宏展开,先列出与端口地址映射有关的宏定义如下:
#define&GPIOD&&&&&&&&&&&&&&&((GPIO_TypeDef&*)&GPIOD_BASE)
#define&GPIOD_BASE&&&&&&&&&&&&(APB2PERIPH_BASE&+&0x1400)
#define&APB2PERIPH_BASE&&&&&&&(PERIPH_BASE&+&0x10000)
#define&PERIPH_BASE&&&&&&&&&&&((uint32_t)0x)&
看到了这个数字是不是非常熟悉,它是外设的首地址。在芯片的内部有两个,一个叫,一个叫。每一个桥都会管理很多外设。把这两个的外设寄存器访问地址放在了不同的存储空间。就是外设的存储空间首地址相对于整个外设的偏移。而是端口外设首地址相对于外设的存储空间首地址的偏移。这样就找到了外设的基地址了!而可以同时实现所有控制端口的个寄存器的映射。若访问某一个寄存器只需要通过指向变量的指针。
2、参数GPIO_InitStruct
第二个参数的为。就是一个指向的地址。第一个参数只找到配置的目标寄存器,第二个参数就是对相应端口如何配置的数据参数。这些参数存储在指向变量的首地址处。先列处该参数由来的一断代码
GPIO_InitTypeDef&&GPIO_InitS&
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitTypeDef&是一个结构体的变量,该变量在头文件中被定义,定义的原型如下:
typedef&struct
&&uint16_t&GPIO_P
&&GPIOSpeed_TypeDef&&GPIO_S&&
&&GPIOMode_TypeDef&&GPIO_M&&
&}GPIO_InitTypeD
GPIO_InitTypeDef的第一个变量为是一个为的无符号数,该数只有位,每一位代表一个引脚,若要配置某一个端口的某一个引脚只需要把相应的位设置为就可以了。在的固件库中有如下引脚号定义:
#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&*/
使用这些定义好的宏就方便多了,要配置某几个引脚只需要把相应的引脚相或就可以了。若你要多某一个端口的所有为进行配置,那么只需要使用一个宏。简单吧!哈哈!
GPIOSpeed_TypeDef是一个枚举变量,它用于存储速度的参数,它的定义如下:
typedef&enum
&&GPIO_Speed_10MHz&=&1,
&&GPIO_Speed_2MHz,&
&&GPIO_Speed_50MHz
}GPIOSpeed_TypeD
通过定义可以知道,的变量有三种取值,那么的速度有三种,
枚举变量的值
对应的速度
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
设计这个枚举变量的可取值有一定的意义。在第四位当中只用到了其中的高两位,这两位数据用来存储到某一个引脚的模式控制位而高四位用来标志某一些标志。
高四位的取值
3、函数代码详解
上面是函数参数的解释。我在我们就可以进入函数的内部看看了。
先把函数的代码列出,对代码的解释都放在了注释当中&,如下:
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&=&((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&*/
&&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)&&&//currentpin&的值为或者为
&&&&&&if&(currentpin&==&pos)//若为说明该位需要配置
&&&&&&&&pos&=&pinpos&&&&2;//pinpos&的值乘以得到某一引脚配置位的最低位号:
&&&&&&&&/*&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&*/
&&&&&&&&if&(GPIO_InitStruct-&GPIO_Mode&==&GPIO_Mode_IPD)//若为输入下拉,需要打开相 应的开关
&&&&&&&&&&GPIOx-&BRR&=&(((uint32_t)0x01)&&&&pinpos);
&&&&&&&&else
&&&&&&&&&&/*&Set&the&corresponding&ODR&bit&*/
&&&&&&&&&&if&(GPIO_InitStruct-&GPIO_Mode&==&GPIO_Mode_IPU)//若为输入下拉,需要打开 相应的开关
&&&&&&&&&&{
&&&&&&&&&&&&GPIOx-&BSRR&=&(((uint32_t)0x01)&&&&pinpos);
&&&&&&&&&&}
&&&&GPIOx-&CRL&=&//对低个引脚配置寄存器赋值
/*----------------------------&GPIO&CRH&Configuration&------------------------*/
&&/*&Configure&the&eight&high&port&pins&*/
&&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&=&
assert_param函数是对参数的检测。参数要么是逻辑或者。也是一个宏,宏定义为:
#define&IS_GPIO_ALL_PERIPH(PERIPH)&(((PERIPH)&==&GPIOA)&||&\
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&((PERIPH)&==&GPIOB)&||&\
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&((PERIPH)&==&GPIOC)&||&\
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&((PERIPH)&==&GPIOD)&||&\
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&((PERIPH)&==&GPIOE)&||&\
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&((PERIPH)&==&GPIOF)&||&\
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&((PERIPH)&==&GPIOG))
其他的参数检测函数当中使用的宏都是相似的,具体可以查看相应的宏定义,在此不一一列出。
对低位的配置和对高位的配置原理是一样的。所以在此只对低引脚配置进行说明。
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:25806次
排名:千里之外
原创:23篇
(2)(1)(1)(3)(3)(14)

我要回帖

更多关于 uint8array 的文章

 

随机推荐