当前位置: 代码迷 >> 综合 >> stm32f1-GPIO
  详细解决方案

stm32f1-GPIO

热度:67   发布时间:2023-11-15 06:11:44.0

一、数据手册

1、STM32F105RC引脚说明

这里写图片描述
可知:STM32F105RC
一共有4组IO口
一共16X3+3=51个IO
GPIOA0~A15
GPIOB0~B15
GPIOC0~C15
GPIOD0~D2

2、程序定义

GPIO端口号

STM32F105RC使用GPIO端口号为:GPIOA、GPIOB、GPIOC、GPIOD

#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)

GPIO I/O口(gpio_init.GPIO_Pin)

#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 /

二、GPIO工作方式

这里的输入、输出是相对于MCU来说的。
举个栗子:
GSM状态引脚,连接MCU PC8引脚。
STATUS 输出高电平开机、低电平关机。
相对于MCU来说,就是输入高电平开机、低电平关机。
这里写图片描述

1、GPIO 8种工作模式(gpio_init.GPIO_Mode)

(1) GPIO_Mode_AIN 模拟输入
(2) GPIO_Mode_IN_FLOATING 浮空输入
(3) GPIO_Mode_IPD 下拉输入
(4) GPIO_Mode_IPU 上拉输入
(5) GPIO_Mode_Out_OD 开漏输出
(6) GPIO_Mode_Out_PP 推挽输出
(7) GPIO_Mode_AF_OD 复用开漏输出
(8) GPIO_Mode_AF_PP 复用推挽输出

具体外设IO口配置:stm32参考手册->GPIO章节内会有 外设的GPIO。下图如节选

2、程序定义

/**
* @brief 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_TypeDef;

enum小知识:
有些数据的取值往往是有限的,只能是非常少量的整数,并且最好为每个值都取一个名字,以方便在后续代码中使用
#define命令虽然能解决问题,但也带来了不小的副作用,导致宏名过多,代码松散,看起来总有点不舒服

3、详解

什么是推挽和开漏,
参看:S5PV210开发 – I2C 你知道多少?(三)

GPIO_Mode_AIN 模拟输入

这里写图片描述
施密特触发器是关闭的,信号直接到ADC输入;
STM32的模拟输入通道的配置则更加简单,信号从左边编号1的端口进入,从右边编号2的一端直接进入ADC模块。
这里我们看到所有的上拉、下拉电阻和施密特触发器,均处于断开状态,因此输入数据寄存器将不能反映端口上的电平状态,也就是说,模拟输入配置下,CPU不能在输入数据寄存器上读到有效的数据。

GPIO_Mode_IN_FLOATING 浮空输入

这里写图片描述
图中施密特触发器是开启的,IO口的状态可以直接送到输入寄存器中,CPU可以直接读取输入寄存器;
在上图中,阴影的部分处于不工作状态,尤其是下半部分的输出电路,实际上是与端口处于隔离状态。
黄色的高亮部分显示了数据传输通道,外部的电平信号通过左边编号1的IO端口进入STM32,经过编号2的施密特触发器的整形送入编号3的输入数据寄存器,在输入数据寄存器的另一端编号4,CPU可以随时读出IO端口的电平状态。

GPIO_Mode_IPD 下拉输入

这里写图片描述

GPIO_Mode_IPU 上拉输入

这里写图片描述
上图是STM32的GPIO带上拉输入模式的配置。与前面的浮空输入模式相比,仅仅是在数据通道上部,接入了一个上拉电阻,根据STM32的数据手册,这个上拉电阻阻值介于30K~50K。
同样,CPU可以随时在输入数据寄存器的另一端,读出IO端口的电平状态。

GPIO_Mode_Out_OD 开漏输出

这里写图片描述
当CPU在编号1端通过“位设置/清楚寄存器”或“输出数据寄存器”写入数据后,该数据位通过编号2的输出控制电路传送到编号4的IO端口。
如果CPU写入的是逻辑1,则编号3的N-MOS管将处于关闭状态,此时IO端口的电平将由外部的上拉电阻决定,如果CPU写入的是逻辑0,则编号3的N-MOS管将处于开启状态,此时IO端口的电平被编号3的N-MOS管拉到了VSS的零电位。
在上图的上半部,施密特触发器处于开启状态,这意味着CPU可以在“输入数据寄存器”的另一端,随时监控IO端口的状态;通过这个特性,还实现了虚拟的IO端口双向通信,只要CPU输出逻辑1,由于编号3的N-MOS管处于关闭状态,IO端口的电平将完全由外部电路决定,因此,CPU可以在“输入数据寄存器”读到外部电路的信号,而不是它自己输出的逻辑1。
GPIO口的输出模式下,有3种输出速度可选(2MHz、10MHz和50MHz),这个速度是指GPIO口驱动电路的响应速度,而不是输出信号的速度,输出信号的速度与程序有关(芯片内部在IO口的输出部分安排了多个响应速度不同的输出驱动电路,用户可以根据自己的需要选择合适的驱动电路)。通过选择速度来选择不同的输出驱动模块,达到最佳的噪声控制和降低功耗的目的。高频的驱动电路,噪声也高,当不需要高的输出频率时,请选用低频驱动电路,这样非常有利于提高系统的EMI性能。当然如果要输出较高的频率的信号,但却选用了较低频率的驱动模块,很可能会得到失真的输出信号。

GPIO_Mode_Out_PP 推挽输出

这里写图片描述

GPIO_Mode_AF_OD 复用开漏输出

这里写图片描述

GPIO_Mode_AF_PP 复用推挽输出

GPIO推挽复用输出模式,编号2的输出控制电路的输入,与复用功能的输出端相连,此时输出数据寄存器被从输出通道断开了,并和片上外设的输出信号连接。我们将GPIO配置成复用输出功能后,如果外设没有被激活,那么它的输出将不确定,其它部分与前述模式一致,包括对“输入数据寄存器”的读取。

4、应用场合

①上拉输入、下拉输入可以用来检测外部信号;例如,按键等;
②浮空输入模式,由于输入阻抗较大,一般把这种模式用于标准通信协议的I2C、USART的接收端;
普通推挽输出模式一般应用在输出电平为0和3.3V的场合。而普通开漏输出模式一般应用在电平不匹配的场合,如需要输出5V的高电平,就需要在外部一个上拉电阻,电源为5V,把GPIO设置为开漏模式,当输出高阻态时,由上拉电阻和电源向外输出5V电平。
④对于相应的复用模式(复用输出来源片上外设),则是根据GPIO的复用功能来选择,如GPIO的引脚用作串口的输出(USART/SPI/CAN),则使用复用推挽输出模式。如果用在I2C、SMBUS这些需要线与功能的复用场合,就使用复用开漏模式
⑤在使用任何一种开漏模式时,都需要接上拉电阻。

三、GPIO 寄存器

1、GPIO 寄存器

每组IO口含下面7个寄存器。也就是7个寄存器,一共可以控制一组GPIO的16个IO口。
configuration register low: GPIOx->CRL :端口配置低寄存器
configuration register high: GPIOx->CRH:端口配置高寄存器
input date register: GPIOx->IDR:端口输入寄存器
output date register: GPIOx->ODR:端口输出寄存器
bit Set/Reset register: GPIOx->BSRR:端口位设置/清除寄存器
bit reset register GPIOx->BRR :端口位清除寄存器
lock Key register: GPIOx->LCKR:端口配置锁存寄存器

2、程序定义

下面有个volatile 被宏定义为 __IO,volatile 起到什么作用?
参看:C语言再学习 – 关键字volatile

#define __IO volatile /!< defines ‘read / write’ permissions /
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_TypeDef;

C语言中“.”与“->”有什么区别?
一般情况下用“.”,只需要声明一个结构体。格式是,结构体类型名+结构体名。然后用结构体名加“.”加域名就可以引用域 了。因为自动分配了结构体的内存。如同 int a;一样。
而用“->”,则要声明一个结构体的指针,还要手动开辟一个该结构体的内存,然后把返回的指针给声明的结构体指针,才能用“->”正确引用。否则内存中只分配了指针的内存,没有分配结构体的内存,导致想要的结构体实际上是不存在。这时候用“->”引用自然出错了,因为没有结构体,自然没有结构体的域了。
此外,(*a).b 等价于 a->b。
".“一般情况下读作"的”。
“->”一般读作"指向的结构体的”。
调用示范
GPIO_TypeDef * GPIOB;
GPIOx->LCKR = tmp;

3、详解各个寄存器

参看:STM32F103学习记录—–GPIO篇
这些寄存器有集成到各个函数里的。
比如:
GPIO_SetBits 置高
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_Pin;
}

aasert_param()它的作用就是检测传递给函数的参数是否是有效的参数
#define IS_USART_ALL_PERIPH(PERIPH) (((PERIPH) == USART1) ||
((PERIPH) == USART2) ||
((PERIPH) == USART3) ||
((PERIPH) == USART4) ||
((PERIPH) == USART5) ||
((PERIPH) == USART6) ||
((PERIPH) == USART7) ||
((PERIPH) == USART8))
宏定义的功能是参数USARTx是USART1~USART8其中的一个,表示参数USARTx有效,返回true,否则返回false。


参看:C语言再学习 – 位操作
当然也可以这么用:
//使用寄存器结构体指针点亮LED
int main(void)
{
#if 0 //直接通过操作内存来控制寄存器
RCC_APB2ENR |= (1<<3);// 开启 GPIOB 端口时钟
GPIOB_CRL &= ~( 0x0F<< (4*0));//清空控制 PB0 的端口位
GPIOB_CRL |= (1<<4*0);// 配置 PB0 为通用推挽输出,速度为 10M
GPIOB_ODR |= (0<<0);// PB0 输出 低电平
while (1);
#else// 通过寄存器结构体指针来控制寄存器
RCC->APB2ENR |= (1<<3);// 开启 GPIOB 端口时钟
GPIOB->CRL &= ~( 0x0F<< (4*0));//清空控制 PB0 的端口位
GPIOB->CRL |= (1<<4*0);// 配置 PB0 为通用推挽输出,速度为 10M
GPIOB->ODR |= (0<<0);// PB0 输出 低电平
while (1);
#endif
}

注意
ODR 这些位可读可写并只能以字(16位)的形式操作
对GPIOx_BSRR(x = A…E),可以分别地对各个ODR位进行独立的设置/清除

端口配置低寄存器(GPIOx->CRL)

这里写图片描述
这里写图片描述

端口配置高寄存器(GPIOx->CRH)

这里写图片描述

端口输入数据寄存器(GPIOx->IDR)

这里写图片描述

端口输出数据寄存器(GPIOx->ODR)

这里写图片描述
这里写图片描述

端口位设置/清除寄存器(GPIOx->BSRR)

这里写图片描述

端口位清除寄存器(GPIOx->BRR)

这里写图片描述

四、大同小异的初始化

有很多外设的初始化,但是基本上大同小异吧。我们以最简单的点亮LED来看一下。

1、初始化程序

GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOE, ENABLE); //使能 PB,PE 端口时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //LED0–>PB.5 推挽输出
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_SetBits(GPIOB,GPIO_Pin_5); //PB.5 输出高
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //LED1–>PE.5 推挽输出
GPIO_Init(GPIOE, &GPIO_InitStructure);
GPIO_SetBits(GPIOE,GPIO_Pin_5); /PE.5 输出高

2、解析

GPIO_InitTypeDef GPIO_InitStructure;

定义一个 GPIO_InitTypeDef 类型的结构体

typedef struct
{
uint16_t GPIO_Pin; /*!< Specifies the GPIO pins to be configured.
This parameter can be any value of @ref GPIO_pins_define */

GPIOSpeed_TypeDef GPIO_Speed; /*!< Specifies the speed for the selected pins.
This parameter can be a value of @ref GPIOSpeed_TypeDef */

GPIOMode_TypeDef GPIO_Mode; /*!< Specifies the operating mode for the selected pins.
This parameter can be a value of @ref GPIOMode_TypeDef */
}GPIO_InitTypeDef;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOE, ENABLE);

使能 GPIOB,GPIOE 端口时钟

启用或禁用高速APB(APB2)外设时钟。
void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState)
{
/* Check the parameters */
assert_param(IS_RCC_APB2_PERIPH(RCC_APB2Periph));
assert_param(IS_FUNCTIONAL_STATE(NewState));
if (NewState != DISABLE)
{
RCC->APB2ENR |= RCC_APB2Periph;
}
else
{
RCC->APB2ENR &= ~RCC_APB2Periph;
}
}

启用或禁用低速APB(APB1)外设时钟。
void RCC_APB1PeriphClockCmd(uint32_t RCC_APB1Periph, FunctionalState NewState)
{
/* Check the parameters */
assert_param(IS_RCC_APB1_PERIPH(RCC_APB1Periph));
assert_param(IS_FUNCTIONAL_STATE(NewState));
if (NewState != DISABLE)
{
RCC->APB1ENR |= RCC_APB1Periph;
}
else
{
RCC->APB1ENR &= ~RCC_APB1Periph;
}
}

这里思考一个问题?哪些该用APB1(低速)、哪些该用APB2(高速)呢?

APB2负责 AD,I/O,高级TIM,串口1。
APB1负责 DA,USB,SPI,I2C,CAN,串口2345,普通TIM,PWR
这里写图片描述
这里写图片描述

高低速时钟频率多大呢?
这个后续讲时钟时再看!!!

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;

选择待设置的GPIO管脚,上面有提到GPIO有16个I/O口。多个I/O中间加位操作符 “|”

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

设置选中GPIO管脚的模式,上面有提到GPIO共有8种工作模式

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

设置选中GPIO管脚的速率

typedef enum
{
GPIO_Speed_10MHz = 1, //最高输出速率10MHz
GPIO_Speed_2MHz, //最高输出速率2MHz
GPIO_Speed_50MHz //最高输出速率50MHz
}GPIOSpeed_TypeDef;

思考,GPIO_Speed GPIO的速度该如何选择呢?
参看:stm32引脚速度GPIO_Speed的区别
I/O口的输出模式下,有3种输出速度可选(2MHz、10MHz和50MHz),这个速度是指I/O口驱动电路的响应速度而不是输出信号的速度,输出信号的速度与程序有关(芯片内部在I/O口 的输出部分安排了多个响应速度不同的输出驱动电路,用户可以根据自己的需要选择合适的驱动电路)。通过选择速度来选择不同的输出驱动模块,达到最佳的噪声 控制和降低功耗的目的。高频的驱动电路,噪声也高当不需要高的输出频率时,请选用低频驱动电路,这样非常有利于提高系统的EMI性能。当然如果要输出较高频率的信号,但却选用了较低频率的驱动模块,很可能会得到失真的输出信号。

举个栗子:
① USART串口,若最大波特率只需115.2k,那用2M的速度就够了,既省电也噪声小。
② I2C接口,若使用400k波特率,若想把余量留大些,可以选用10M的GPIO引脚速度。
③ SPI接口,若使用18M或9M波特率,需要选用50M的GPIO的引脚速度。

GPIO_Init(GPIOB, &GPIO_InitStructure);

根据GPIO_InitStructure中指定的参数初始化外设GPIOX

GPIO_SetBits(GPIOB,GPIO_Pin_5);

将端口GPIOB的第5引脚置1(高电平), 多个I/O中间加位操作符 “|”

五、GPIO常用函数

打开 stm32f10x_gpio.c,可以看到 GPIO 相关函数。我们简单看一下这些函数的功能
参看:STM32中使用GPIO的总结(超强)
下面出现的Bit_RESET = 0,Bit_SET = 1
typedef enum
{ Bit_RESET = 0,
Bit_SET
}BitAction;

1、GPIO_ReadInputDataBit

功能描述:读取指定端口管脚的输入

例:
u8 ReadValue;
ReadValue = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_7);
返回值为:0(低电平)、1(高电平)

函数解析

uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
uint8_t bitstatus = 0x00;

/* Check the parameters */
assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
assert_param(IS_GET_GPIO_PIN(GPIO_Pin));

if ((GPIOx->IDR & GPIO_Pin) != (uint32_t)Bit_RESET)
// GPIOx->IDR:端口输入寄存器
{
bitstatus = (uint8_t)Bit_SET;
}
else
{
bitstatus = (uint8_t)Bit_RESET;
}
return bitstatus;
}

2、GPIO_ReadInputDataBit

功能描述:读取指定的GPIO端口输入

例:
u16 ReadValue;
ReadValue = GPIO_ReadInputData(GPIOC);

函数解析

uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx)
{
/* Check the parameters */
assert_param(IS_GPIO_ALL_PERIPH(GPIOx));

return ((uint16_t)GPIOx->IDR);
}

3、GPIO_ReadOutputDataBit

功能描述:读取指定端口管脚的输出

例:
u8 ReadValue;
ReadValue = GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_7);

函数解析

uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
uint8_t bitstatus = 0x00;
/* Check the parameters */
assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
assert_param(IS_GET_GPIO_PIN(GPIO_Pin));

if ((GPIOx->ODR & GPIO_Pin) != (uint32_t)Bit_RESET)
{
bitstatus = (uint8_t)Bit_SET;
}
else
{
bitstatus = (uint8_t)Bit_RESET;
}
return bitstatus;
}

4、GPIO_ReadOutputData

功能描述:读取指定的GPIO端口输出

例:
u16 ReadValue;
ReadValue = GPIO_ReadOutputData(GPIOC);

函数解析

uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx)
{
/* Check the parameters */
assert_param(IS_GPIO_ALL_PERIPH(GPIOx));

return ((uint16_t)GPIOx->ODR);
}

5、GPIO_SetBits

功能描述:置位指定的数据端口位

例: 将端口GPIOA的第10、15脚置1(高电平)
GPIO_SetBits(GPIOA, GPIO_Pin_10 | GPIO_Pin_15);

函数解析

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_Pin;
}

6、GPIO_ResetBits

功能描述:清除指定的数据端口位

例:将端口GPIOA的第10、15脚置0(低电平)
GPIO_ResetBits(GPIOA, GPIO_Pin_10 | GPIO_Pin_15);

函数解析

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_Pin;
}

7、GPIO_WriteBit

功能描述:设置或者清除指定的数据端口位

例:
GPIO_WriteBit(GPIOA, GPIO_Pin_15, Bit_SET);

函数解析

void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal)
{
/* Check the parameters */
assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
assert_param(IS_GET_GPIO_PIN(GPIO_Pin));
assert_param(IS_GPIO_BIT_ACTION(BitVal));

if (BitVal != Bit_RESET)
{
GPIOx->BSRR = GPIO_Pin;
}
else
{
GPIOx->BRR = GPIO_Pin;
}
}

8、GPIO_Write

功能描述:向指定GPIO数据端口写入数据

例:
GPIO_Write(GPIOA, 0x1101);

函数解析

void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal)
{
/* Check the parameters */
assert_param(IS_GPIO_ALL_PERIPH(GPIOx));

GPIOx->ODR = PortVal;
}

9、GPIO_PinLockConfig

功能描述:锁定GPIO管脚设置寄存器

例:
GPIO_PinLockConfig(GPIOA, GPIO_Pin_0 | GPIO_Pin_1);

函数解析

void GPIO_PinLockConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
uint32_t tmp = 0x00010000;

/* Check the parameters */
assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
assert_param(IS_GPIO_PIN(GPIO_Pin));

tmp |= GPIO_Pin;
/* Set LCKK bit */
GPIOx->LCKR = tmp;
/* Reset LCKK bit */
GPIOx->LCKR = GPIO_Pin;
/* Set LCKK bit */
GPIOx->LCKR = tmp;
/* Read LCKK bit*/
tmp = GPIOx->LCKR;
/* Read LCKK bit*/
tmp = GPIOx->LCKR;
}

10、GPIO_EventOutputConfig

功能描述:选择GPIO管脚用作事件输出

例:
GPIO_EventOutputConfig(GPIO_PortSourceGPIOE, GPIO_PinSource5);

GPIO_PortSource
GPIO_PortSource用以选择用作事件输出的GPIO端口。

函数解析

void GPIO_EventOutputConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource)
{
uint32_t tmpreg = 0x00;
/* Check the parameters */
assert_param(IS_GPIO_EVENTOUT_PORT_SOURCE(GPIO_PortSource));
assert_param(IS_GPIO_PIN_SOURCE(GPIO_PinSource));

tmpreg = AFIO->EVCR;
/* Clear the PORT[6:4] and PIN[3:0] bits */
tmpreg &= EVCR_PORTPINCONFIG_MASK;
tmpreg |= (uint32_t)GPIO_PortSource << 0x04;
tmpreg |= GPIO_PinSource;
AFIO->EVCR = tmpreg;
}

11、GPIO_EventOutputCmd

功能描述:使能或者失能事件输出

例:
GPIO_EventOutputConfig(GPIO_PortSourceGPIOC, GPIO_PinSource6);
GPIO_EventOutputCmd(ENABLE);

函数解析

void GPIO_EventOutputCmd(FunctionalState NewState)
{
/* Check the parameters */
assert_param(IS_FUNCTIONAL_STATE(NewState));

(__IO uint32_t ) EVCR_EVOE_BB = (uint32_t)NewState;
}

12、GPIO_PinRemapConfig

功能描述:改变指定管脚的映射

例:
GPIO_PinRemapConfig(GPIO_Remap_I2C1, ENABLE);

例如:GPIO_PinRemapConfig(GPIO_FullRemap_TIM1,ENABLE);

在这里插入图片描述
上述代码就是完全重映射,本来应该初始化PA8但是现在需要重映射成PE9