STM32的GPIO(General-purpose I/O,通用输入输出端口)引脚都可以由软件配置成输出(推挽或开漏)、输入(带或不带上拉或下拉)或复用的外设功能端口。
STM32F103VE有GPIOA、GPIOB、GPIOC、GPIOD、GPIOE共5个GPIO端口,分别简称PA、PB、PC、PD、PE。
STM32F103xx的引脚数量不同,因此GPIO端口数不同。STM32F103ZE型号具有144个引脚,提供7个GPIO端口,其中包括GPIOF和GPIOG端口。在使用STM3210E-EVAL评估板的范例程序时,要特别注意这一点。
每个GPIO端口有16个端口位,如GPIOA的16个端口位简称为PA0,PA1,PA2,…,PA15。
在STM32F103xx中,I/O端口位的英文是I/O port bit,引脚的英文是pin。I/O引脚实际上是I/O端口位的外部引脚,是I/O端口位的一部分。
每个GPIO端口有7个寄存器,分别是
1.端口配置低寄存器(GPIOx_CRL) (x=A..E)
偏移地址:0x00
复位值:0x4444 4444
CNFy[1:0]:端口x配置位(y = 0…7) (Port x configuration bits) ,软件通过这些位配置相应的I/O端口。
在输入模式(MODE[1:0]=00):
00:模拟输入模式
01:浮空输入模式(复位后的状态)
10:上拉/下拉输入模式
11:保留
在输出模式(MODE[1:0]>00):
00:通用推挽输出模式
01:通用开漏输出模式
10:复用功能推挽输出模式
11:复用功能开漏输出模式
MODEy[1:0]:端口x的模式位(y = 0…7) (Port x mode bits) ,软件通过这些位配置相应的I/O端口。
00:输入模式(复位后的状态)
01:输出模式,最大速度10MHz
10:输出模式,最大速度2MHz
11:输出模式,最大速度50MHz
2. 端口配置高寄存器(GPIOx_CRH) (x=A..E)
偏移地址:0x04
复位值:0x4444 4444
CNFy[1:0]:端口x配置位(y = 8…15),与CRL相同含义。
MODEy[1:0]:端口x的模式位(y = 8…15), 与CRL相同含义。
3. 端口输入数据寄存器(GPIOx_IDR) (x=A..E)
地址偏移:0x08
复位值:0x0000 XXXX
位31:16 保留,始终读为0。
位15:0 IDRy[15:0]:端口输入数据(y = 0…15) (Port input data) 这些位为只读并只能以字(16位)的形式读出。读出的值为对应I/O口的状态。
4. 端口输出数据寄存器(GPIOx_ODR) (x=A..E)
地址偏移:0Ch
复位值:0x0000 0000
位31:16 保留,始终读为0。
位15:0 ODRy[15:0]:端口输出数据(y = 0…15) (Port output data) 这些位可读可写并只能以字(16位)的形式操作。
注:对GPIOx_BSRR(x = A…E),可以分别地对各个ODR位进行独立的设置/清除。
5. 端口位设置/清除寄存器(GPIOx_BSRR) (x=A..E)
地址偏移:0x10
复位值:0x0000 0000
位31:16 这些位只能写入并只能以字(16位)的形式操作。
0:对对应的ODRy位不产生影响。
1:清除对应的ODRy位为0。
注:如果同时设置了BSy和BRy的对应位,BSy位起作用。
位15:0 BSy: 设置端口x的位y (y = 0…15) (Port x Set bit y), 这些位只能写入并只能以字(16位)的形式操作。
0:对对应的ODRy位不产生影响。
1:设置对应的ODRy位为1。
6. 端口位清除寄存器(GPIOx_BRR) (x=A..E)
地址偏移:0x14
复位值:0x0000 0000
位31:16 保留。
位15:0 BRy: 清除端口x的位y (y = 0…15) (Port x Reset bit y), 这些位只能写入并只能以字(16位)的形式操作。
0:对对应的ODRy位不产生影响。
1:清除对应的ODRy位为0。
7. 端口配置锁定寄存器(GPIOx_LCKR) (x=A..E)
当执行正确的写序列设置了位16(LCKK)时,该寄存器用来锁定端口位的配置。位[15:0]用于锁定GPIO端口的配置。在规定的写入操作期间,不能改变LCKP[15:0]。当对相应的端口位执行了LOCK序列后,在下次系统复位之前将不能再更改端口位的配置。 每个锁定位锁定控制寄存器(CRL, CRH)中相应的4个位。
地址偏移:0x18
复位值:0x0000 0000
位31:17 保留。
位16 LCKK:锁键 (Lock key), 该位可随时读出,它只可通过锁键写入序列修改。
0:端口配置锁键位激活。
1:端口配置锁键位被激活,下次系统复位前GPIOx_LCKR寄存器被锁住。
锁键的写入序列: 写1 -> 写0 -> 写1 -> 读0 -> 读1 最后一个读可省略,但可以用来确认锁键已被激活。
注:在操作锁键的写入序列时,不能改变LCK[15:0]的值。 操作锁键写入序列中的任何错误将不能激活锁键。
位15:0 LCKy: 端口x的锁位y (y = 0…15), (Port x Lock bit y) 这些位可读可写但只能在LCKK位为0时写入。
0:不锁定端口的配置。
1:锁定端口的配置。
GPIO端口的每个端口位可以由软件分别配置成以下8种模式。
• 输入浮空(IN_FLOATING,Input floating)。
• 输入上拉(IPU,Input pull-up)。
• 输入下拉(IPD,Input-pull-down)。
• 模拟输入(AIN,Analog)。
• 开漏输出(Out_OD,Output open-drain)。
• 推拉(推挽)式输出(Out_PP,Output push-pull)。
• 推拉式复用功能(AF_PP,Alternate function push-pull)。
• 开漏复用功能(AF_OD,Alternate function open-drain)
I/O端口位的内部结构框图如图3-1所示。
I/O端口位的输入是CPU读出I/O端口输入数据寄存器(GPIOx_IDR)的数据。
I/O端口位的输出是CPU直接写入数据到输出数据寄存器(GPIOx_ODR);也可以是CPU通过先写入数据到位设置/清除寄存器(GPIOx_BSRR)后,再间接写入数据到输出数据寄存器;也可以是CPU通过先写入数据到位清除寄存器(GPIOx_BRR,图3-1中省略)后,再间接写入数据到输出数据寄存器。
参考阅读:
推挽电路(push-pull)就是两个不同极性晶体管间连接的输出电路。推挽电路采用两个参数相同的功率BJT管或MOSFET管,以推挽方式存在于电路中,各负责正负半周的波形放大任务,电路工作时,两只对称的功率开关管每次只有一个导通,所以导通损耗小效率高。
推挽放大器的输出级有两个“臂”(两组放大元件),一个“臂”的电流增加时,另一个“臂”的电流则减小,二者的状态轮流转换。对负载而言,好像是一个“臂”在推,一个“臂”在拉,共同完成电流输出任务。尽管甲类放大器可以采用推挽式放大,但更常见的是用推挽放大构成乙类或甲乙类放大器。
实验3-1 点亮或熄灭LED(标准库)
这里使用的是STM32的V3.5.0标准外设库的范例程序GPIO_IOToggle,将其修改后实现点亮或者熄灭LED。
1.硬件设计
STM32F103VE驱动LED电路的局部原理图如图3-2所示,完整原理图参见2.2.4节的图2-26~图2-28,STM32的GPIO I/O 特性参见1.3.4节的内容。
2.软件设计(编程)
PC6输出高电平时点亮LED1、输出低电平时熄灭LED1。
使用库函数进行GPIO编程通常涉及3个步骤,分别是使能端口GPIOC的时钟;设置端口位PC6的工作模式为50MHz的推挽输出;PC6输出高电平或输出低电平。
使用STM32的库函数编程方法时,完整源程序如下。
#include"stm32f10x.h" //包含头文件
GPIO_InitTypeDefGPIO_InitStructure;
int main(void) //主函数
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE); //使能GPIOC的时钟
GPIO_InitStructure.GPIO_Pin =GPIO_Pin_6;
GPIO_InitStructure.GPIO_Speed= GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode= GPIO_Mode_Out_PP;
GPIO_Init(GPIOC,&GPIO_InitStructure);
while (1) //无限循环
{
GPIO_SetBits(GPIOC, GPIO_Pin_6); //设置端口位库函数。PC6输出高电平,点亮LED1
GPIO_ResetBits(GPIOC, GPIO_Pin_6); //清除端口位库函数。PC6输出低电平,熄灭LED1
}
}
实验3-2 点亮或熄灭LED(HAL库)
使用STM32CubeMX创建MDK工程后,在MDK环境中进行后续开发。
STM32CubeMX配置STM32F103VET6的相应初始化C代码并建立MDK工程。
在生成的MDK工程中, main.c文件已经包含了初始化函数HAL_Init、系统时钟配置函数SystemClock_Config和GPIO端口初始化函数MX_GPIO_Init,用户只需要增加设置或清除指定的端口位函数HAL_GPIO_WritePin,就可以使PC6输出高电平或低电平,从而点亮或熄灭LED1。
1.硬件设计 。
STM32F103VE驱动LED电路的局部原理图如图3-2所示,完整原理图参见2.2.4节的图2-26~图2-28,STM32的GPIO I/O 特性参见1.3.4节的内容。
2.软件设计(编程)
使用STM32CubeMX和HAL库函数的程序如下。
include "main.h"
include "stm32f1xx_hal.h"
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
int main(void)
{
HAL_Init(); //复位所有外设、初始化Flash接口和Systick
SystemClock_Config(); //配置系统时钟为72MHz
MX_GPIO_Init(); //初始化GPIO
while (1)
{
/* USER CODE BEGIN 3 (用户程序代码开始3)*/
HAL_GPIO_WritePin (GPIOC, GPIO_PIN_6, GPIO_PIN_SET); //PC6输出高电平
HAL_GPIO_WritePin (GPIOC, GPIO_PIN_6, GPIO_PIN_RESET); //PC6输出低电平
}
/ * USER CODE END 3 (用户程序代码结束3)*/
}
初始化GPIO,调用的函数是MX_GPIO_Init,函数功能与标准库类似,具体程序如下。
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOC_CLK_ENABLE(); //使能GPIOC的时钟
/* Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_6, GPIO_PIN_RESET); //PC6输出低电平
/* Configure GPIO pin : PC6 */
GPIO_InitStruct.Pin = GPIO_PIN_6;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); //初始化GPIOC
}