STM32单片机:GPIO编程

本节介绍STM32单片机的GPIO编程的方法和步骤。

以STM32L431这颗芯片为例,下图是芯片的引脚图,红线标记的引脚就是GPIO引脚,单片机就是

利用这些引脚与外部相连,实现各种控制功能。

为了让GPIO能执行预定的功能,需要通过对一些GPIO相关的控制寄存器进行设置,与GPIO相关

的寄存器,包括:

《1》时钟使能寄存器:RCC_AHB2ENR

不仅是GPIO模块,芯片内许多其他的模块都会有时钟使能控制,要使模块正常工作,必须要使能

其时钟,这些时钟使能寄存器位于Reset and clock control (RCC模块),寄存器名称前面的字母,

是表示这个寄存器所属的模块。

《2》工作模式寄存器:GPIOx_MODER   X:  A  B  C  D ……

这个寄存器可以设置GPIO的工作模式为:输入模式,输出模式,功能复用模式,模拟信号模式

这里的x表示不同的GPIO组,可以是a b c d等。

《3》IO功能复用寄存器:GPIOx_AFRLGPIOx_AFRH

这个寄存器可以将IO设置为某种复用的功能,IO口的复用功能列表,在器件手册中有详细说明。

《4》输出类型寄存器:GPIOx_OTYPER

可以设置输出类型为:推挽输出,漏极开路输出

《5》输出速度寄存器:GPIOx_OSPEEDR

可以根据具体需求设置输出速度为:低速,中速,高速,超高速

《6》上下拉寄存器GPIOx_PUPDR

设置IO口输出时:上拉,下拉,无上下拉

以上是几个控制GPIO工作的控制寄存器。

《7》输入数据寄存器:GPIOx_IDR

可以通过其读入IO口当前的电平状态。

《8》输出数据寄存器:GPIOx_ODR

可以将需要输出到IO的电平写入此寄存器。

《9》数据位置位/复位寄存器:GPIOx_BSRR

对这个寄存器中相应的位写1,可以使对应的IO输出至1或至0。

《10》配置锁定寄存器:GPIOx_LCKR

如此寄存器中的某位按照特定的流程写1,那么对应的IO口的配置将会被锁定,直到下次芯片复位

才会解锁,可以防止IO的配置在程序运行中被意外修改,造成错误。

《11》数据位复位寄存器GPIOx_BRR

对这个寄存器中相应的位写1,可以使对应的IO输出至0。
 

下面选定端口PA8,来举例说明具体的编程过程。这里将PA8配置成时钟输出,可以使用PA8来输

出各种时钟,下面将详细讲解如何将这几项功能配置到PA8。

1、GPIOA(PA8)时钟使能

首先需要使能PA8的时钟,因为PA8属于GPIOA,所以也就是要使能GPIOA的时钟,那我们如何确

定GPIOA的时钟控制在哪里呢,在前面的章节中,我们提到了两个重要的文档,其中一个是器件

手册,里面列表了各个片内设备的地址区间,找到包含GPIOA的那一部分,如图所示:

发现GPIOA属于AHB2总线,在编程手册的RCC模块中,找到AHB2总线的时钟使能寄存器

RCC_AHB2ENR,如下图:

GPIOA的时钟使能,是此寄存器的bit0,将此位写1就可以使能GPIOA的时钟。 

图中蓝色圆圈处表示此寄存器相对于RCC模块基地址的偏移量是0x4C。

可是,怎么去操作这个RCC_AHB2ENR寄存器呢,我们发现,这个寄存器隶属于RCC模块,那么

再次从器件手册中查到RCC模块的地址区间,如图所示:

蓝色圆圈处,就是RCC模块寄存器的基地址:0x40021000

实现代码如下:

// 定义RCC模块的基地址

#define RCC         ((uint32_t)0x40021000)

// 定义RCC_AHB2ENR寄存器的地址 (相对于RCC模块的基地址偏移量为0x4C):

#define RCC_AHB2ENR     (*(volatile uint32_t *)(uint32_t)(RCC+0x4C))

// 定义GPIOA时钟使能位

#define RCC_AHB2ENR_GPIOAEN       BIT(0)

// RCC_AHB2ENR【0】位置1,即使能GPIOA的时钟

RCC_AHB2ENR |= RCC_AHB2ENR_GPIOAEN;

2、GPIOA(PA8)的工作模式

在器件手册上找到GPIOA的地址区间,如下图:

蓝色圆圈处,就是GPIOA模块寄存器的基地址:0x48000000

查阅编程手册,在GPIO模块的章节中找到GPIOx_MODER寄存器说明,如下图:

蓝色圆圈处,就是GPIOx_MODER寄存器地址相对于GPIOA模块基地址的偏移量:0x00

红色圆圈处,就是用来设置PA8端口工作模式的对应位。

红线处为PA8选择的工作模式:“10” 功能复用模式

实现代码如下:

#define  GPIOA                                ((uint32_t)0x48000000)

#define  GPIO_MODER(gpiox     (*(volatile uint32_t *)(uint32_t)(gpiox + 0x00))

#define  GPIO_MODE_AF                   (BITS(0,1) & (uint32_t)0x02)

#define  GPIO_MODE_MASK(n)        ((uint32_t)((uint32_t)(3) << (2 * n)))

#define  GPIO_MODE_SET(n, val)     ((uint32_t)((uint32_t)(val) << (2 * n)))

// GPIOA_MODER【1716】位清0,即清除PA8的工作模式控制位

// 清零的目的是:保证新的模式用或的方式写入时不会出现其他的值

 GPIO_MODER(GPIOA)  &=  ~GPIO_MODE_MASK(8);

 // GPIOA_MODER【1716】位写入PA8工作模式=GPIO_MODE_AF,即复用功能模式

 GPIO_MODER(GPIOA)  |=  GPIO_MODE_SET (8 GPIO_MODE_AF);

3、GPIOA(PA8)的IO复用功能

PA8用于时钟输出,是利用PA8的IO复用功能,查阅芯片手册,找到PA8的复用功能列表如下:

由上图得到PA8的AF0的输出的功能是MCO(时钟输出)。

查阅编程手册,找到设置复用功能的寄存器GPIOx_AFRH,因为是用4个bit来设定一个IO的复用功

能所以PA0到PA7用GPIOx_AFRL来设置,PA8到PA15用GPIOx_AFRH来设置:

蓝色圆圈处表示GPIOx_AFRH相对于GPIOA基地址的偏移量是0x24,红色圆圈处的4个bit用来设置PA8的复用功能,红线处表示AF0的设置值为b0000。实现代码如下:

#define  GPIO_AFRH(gpiox)          (*(volatile uint32_t *)(uint32_t)(gpiox + 0x24))

#define  GPIO_AF_0                        (BITS(0,3) & (uint32_t)0x00)

#define   GPIO_AFR_MASK(n)       ((uint32_t)((uint32_t)(0xf)<< (4 * n)))

#define  GPIO_AFR_SET(n, val)     ((uint32_t)((uint32_t)(val) << (4 * n)))

//GPIOA_AFRH【3 : 0】位清0,即清除PA8的复用功能控制位

GPIO_AFRH(GPIOA)  &=  ~GPIO_AFR_MASK(0);

//GPIOA_AFRH【3 : 0】写入:即设置PA8复用功能 = GPIO_AF_0,就是MCO

GPIO_AFRH(GPIOA)  |=  GPIO_AFR_SET(0 GPIO_AF_0);

4、GPIOA(PA8)的输出类型

PA8用于时钟输出,所以输出类型为输出模式,查阅编程手册找到寄存器GPIOx_OTYPER: 

 设置PA8为漏极开路输出,实现代码如下:

#define  GPIO_OTYPER(gpiox)      (*(volatile uint32_t *)(uint32_t)(gpiox + 0x04))

// GPIOA_OTYPER【8】位置1 PA8开漏输出

GPIO_OTYPER(GPIOA)  |=  BIT(8);

5、GPIOA(PA8)的输出速度

将PA8设置为超高速输出,查阅编程手册找到寄存器GPIOx_OSPEEDR:

实现代码如下:

#define  GPIO_OSPEEDR(gpiox)             (*(volatile uint32_t *)(uint32_t)(gpiox + 0x08))

#define  GPIO_OSPEED_VERYHIGH       (BITS(0,1) & (uint32_t)0x03)

#define  GPIO_OSPEED_MASK(n)          ((uint32_t)((uint32_t)(0x3)<< (2 * n)))

#define  GPIO_OSPEED_SET(n, val)       ((uint32_t)((uint32_t)(val) << (2 * n)))

// GPIOA_OSPEEDR【17 : 16】位清0,即清除PA8的输出速度控制位

GPIO_OSPEEDR(GPIOA)  &=  ~GPIO_OSPEED_MASK(8);

// GPIOA_OSPEEDR【17 : 16】位写入

// 即设置PA8的输出速度=GPIO_OSPEED_VERYHIGH,超高速

GPIO_OSPEEDR(GPIOA)  |=  GPIO_OSPEED_SET(8 GPIO_OSPEED_VERYHIGH);

6、GPIOA(PA8)的上下拉

将PA8设置为上拉,查阅编程手册找到寄存器GPIOx_PUPDR:

实现代码如下:

#define  GPIO_PUPDR(gpiox)             (*(volatile uint32_t *)(uint32_t)(gpiox + 0x0C))

#define  GPIO_PUPD_PULLUP           (BITS(0,1) & (uint32_t)0x01)

#define  GPIO_PUPD_MASK(n)          ((uint32_t)((uint32_t)(0x3)<< (2 * n)))

#define  GPIO_PUPD_SET(n, val)       ((uint32_t)((uint32_t)(val) << (2 * n)))

// GPIOA_PUPDR【17 : 16】位清0,即清除PA8的上下拉控制位

GPIO_PUPDR(GPIOA)  &=  ~GPIO_PUPD_MASK(8);

// GPIOA_PUPDR【17 : 16】位写入即设置PA8上下拉=GPIO_PUPD_PULLUP,上拉

GPIO_PUPDR(GPIOA)  |=  GPIO_PUPD_SET(8 GPIO_PUPD_PULLUP);

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

btzhy

您的鼓励是我最大的动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值