五、寄存器点亮 LED 灯
配置流程
一般我们使用 GPIO 的端口,都需要有以下几个步骤。
- 开启 GPIO 的端口时钟
- 配置 GPIO 的模式
- 配置 GPIO 的输出
从 LED 介绍那一章节我们了解到用户 LED 接的是单片机的 PB2,下面我们就以用户 LED 接的 PB2 进行介绍。
开启 GPIO 的端口时钟
STM32 的所有外设资源时钟默认都是关闭的,在配置外设之前需要先开 启对应的时钟。
要使能用户 LED,就要先开启 GPIOB 的时钟,从用户手册的第 37 页我们了解到 GPIOB 挂载在 AHB1 总线上,那操作 GPIOB 的时钟肯定要配置 AHB1 使能寄存器。在用户手册的第 114 页,AHB1 使能寄存器如图所示。
从上图可以看到地址偏移量为 0x30,那这个基地址是多少呢?因为 AHB1 使能寄存器是在 RCU 外设的地址范围内,所以 RCU 的外设基地址就是 AHB1 使能寄存器的基地址,在数据手册的第 72 页有明确说明,RCU 基地址:0x4002 3800。那我们 RCU_AHB1EN 寄存器的地址就是基地址加上偏移量,0x4002 3800 + 0x30 = 0x4002 3830。找到要操作的地址了,那我们怎么去配置这个值呢?我们继续看这个寄存器的说明,在用户手册的第 182 页有寄存器说明,如图所示。
可以了解到 RCU_AHB1EN 寄存器的第 3 位就是 GPIOB 端口时钟使能,我们要开启 GPIOB 端口时钟使能,就需要往 RCC_AHB1ENR 的第 1 位写 1,然后为了保持其他位不变,我们可以使用一个或运算,也就是 RCC_AHB1ENR |= 0x00000002,也就是相当于拉高 RCU_AHB1EN 寄存器的第 1 位,其他位保持不变。其实也可以写为 RCC_AHB1ENR |=(1 << 1),是一样的效果,这里的 1 就是寄存器的第 1 位,如果是 2 就是寄存器的第 2 位,依次类推(位数从 0 开始)。
在 STM32 的头文件中已经将大部分的地址定义了,所以我们只需要调用这些地址的定义就可以了。
RCC->AHB1ENR |= ( 0x01 << 1 );
配置 GPIO 模式
GPIO 的模式配置可分为两步,
配置为输出功能
我们要使能用户 LED,自然是配置 GPIO 为输出模式,找到控制寄存器(GPIOx_MODER),如图所示。
图 1-2-1
上图可以看到 GPIOx_MODER 的地址偏移是 0x00,我们要使能的是 GPIOB 的引脚,所以要加上 GPIOB 的基地址 0x4002 0400,即 GPIOx_MODER 寄存器的地址为 0x4002 0400 + 0x00。我们接着看这个寄存器的介绍说明,如图 1-2-2 所示。
可以看到每一个引脚都由 2 位控制,我们要操作的是 PB2 引脚,也就是 pin2,也就是 GPIOB_CTL 寄存器的第 5 位和第 4 位。
我们要配置为输出模式,也就是把这两位配置为 01,我们用二进制来表示一下,0000 0000 0000 0000 0000 0000 0001 0000 ,转换成十六进制就是 0x00000010。所以我们将 GPIOB_MODER 寄存器里面写入 0x00000010,就是把 PB2 这个引脚配置为了输出模式,为了保持其它位的数据不发生变化,我们先清空这两位,然后再往这两位里面写值。
操作为 GPIOB_MODER &= 0xffffffcf; 这句代码是清空第 5 位和第 4 位。GPIOB_MODER |= 0x00000010;这句代码就是把第 5 位和第 4 位配置为 01,这样操作保证了其它位不发生变化。
配置为浮空模式,无上拉下拉
一般输出模式我们都配置为浮空模式,输入模式我们才需要考虑上拉还是下拉,根据默认电平状态进行判断。
第一步配置好为输出模式之后,我们还需要进行第二步配置,配置 PB2 为浮空模式,无上拉和下拉。关于端口上下拉寄存器如图所示。
可以看到端口上下拉寄存器的地址偏移是 0x0C,那 GPIOx_PUPDR 的地址就是 0x4002 0400 + 0x0C。我们接着往下看这个寄存器的介绍,如图所示。
从图可以看到,每一个引脚都由 2 位进行控制,和 GPIOB_MODER 寄存器的配置一样,也是先清空这两位,然后再配置这两位为 00。转化为下面这两句代码。
在 STM32 的头文件中已经将大部分的地址定义了,所以我们只需要调用这些地址的定义就可以了。
GPIOB->MODER |= ( 0x01 << 2 * 2 );
配置 GPIO 的输出
配置 GPIO 的输出也分为两步,第一步配置端口输出模式寄存器 GPIOx_MODER,第二步配置端口速度寄存器 GPIOx_OSPEEDR 。
配置为推挽输出
当我们配置为输出模式的时候,可以有两种输出模式选择,一种是推挽输出模式,一种是开漏输出模式。
- 00: 低速(Low speed):适用于功耗敏感的应用或者那些不需要高速切换的场合。
- 01: 中速(Medium speed):提供了一种平衡的速度和功耗的选项,适合大多数应用。
- 10: 高速(High speed):用于需要较快数据传输或较高频率切换的应用。
- 11: 极高速(Very high speed):提供最快的 GPIO 切换速度,适用于高速通信或快速信号处理的场合。
开漏是需要外接上拉电阻才可以输出高电平,这里并不适合,所以需要设置为推挽输出。
端口输出模式寄存器如图所示。
图 1-3-1
可以看到端口输出模式寄存器的地址偏移为 0x04,那 GPIOB_MODER 寄存器的地址就是 0x4002 0400 + 0x04。我们接着往下看这个寄存器的介绍,如图所示。
可以看到每一个引脚由 1 位进行控制,要配置为推挽输出,只需要往对应的寄存器写 0 即可。转化为代码为 GPIOB_MODER &= ~(0x01 << 2)。
配置速度
我们配置引脚输出模式之后,我们还要选择这个引脚对应的速度,端口输出速度寄存器如图所示。
可以看到端口输出速度寄存器的地址偏移是 0x08,那么 GPIOB_OSPEEDR 寄存器的地址就是 0x4002 0400 + 0x08。我们接着往下看这个寄存器的介绍,如图所示。
从图可以看出每一个引脚由 2 位进行控制,要配置为多少等级,只需要往对应的位写入对应的值即可。从官方提供的代码中查找到了速度等级对应的频率关系,如下所示。
我们这里选择配置为 100MHZ,所以需要配置为等级 2,需要往对应的位写入 00。转化为代码就是:
在 STM32 的头文件中已经将大部分的地址定义了,所以我们只需要调用这些地址的定义就可以了。
GPIOB->OSPEEDR |= ( 0x03 << 2 * 2 );
通过这两句我们就可以把 PB2 引脚的速度配置为 100MHZ。
到此,我们关于 GPIO 的配置就完成了。
配置 GPIO 输出高电平
配置好 GPIO 之后,我们就可以进行点灯了。其实也就是让 GPIO 引脚输出高低电平,到我们的开发板上就是让 PB2 输出高电平。
如何让 PB2 输出高电平呢?通过查阅用户手册的 GPIO 寄存器,这里为大家总结了几种操作的方式。
端口输出控制寄存器
关于端口输出控制寄存器如图所示。
可以看到端口输出控制寄存器的地址偏移为 0x14,那么对应的 GPIOx_ODR 寄存器的地址为 0x4002 0400 + 0x14。我们接着往下看这个寄存器的介绍,如图所示。
从图可以了解到 GPIOB_ODR 寄存器的低 16 位有效,每一个引脚对应一位,往对应的位写 0 就是输出低电平,写 1 就输出高电平。
在 STM32 的头文件中已经将大部分的地址定义了,所以我们只需要调用这些地址的定义就可以了。
输出低电平转换为代码为GPIOB->ODR &= ~ (0x01 << 2);
输出高电平转换为代码为GPIOB->ODR |= ( 0x01 << 2);
2
端口位操作寄存器
关于端口位操作寄存器如图所示。
从图可以看到端口输出控制寄存器的地址偏移为 0x18,那么对应的 GPIOB_BSRR 寄存器的地址为 0x4002 0400 + 0x18。我们接着往下看这个寄存器的介绍,如图所示。
可以了解到 GPIOB_BSRR 寄存器的低 16 位是置 1 位,高 16 位是清 0 位。对于低 16 位每一个引脚对应一位,往对应的位写 1 就是输出高电平,写 0 电平状态不改变。对于高 16 位每一个引脚对应一位,往对应的位写 1 就是输出低电平,写 0 电平状态不改变。
在 STM32 的头文件中已经将大部分的地址定义了,所以我们只需要调用这些地址的定义就可以了。
输出低电平转换为代码为GPIOB->BSRR |= (0x01 << (2 + 16));
输出高电平转换为代码为GPIOB->BSRR |= (0x01 << 2);
2
端口位翻转寄存器
使用端口位翻转寄存器也有类似的功能,从名称就可以知道这个寄存器是把对应的位电平进行翻转,这是一个很不错的操作,使用起来也很方便。但前提是我们要知道当下的引脚电平是一个什么状态,然后我们翻转之后又是一个什么状态。关于这一部分就不过多说明,大家可以自行研究一下。
实验现象
如果用上面的代码需要注意一下,像 RCC 这种宏定义其实在 STM32 的头文件中已经定义了,可以直接使用原来定义的,这样我们就不用再编写,也可以把我们编写的名称稍微修改一下,比如在它们前面加上一个 LED 或者 BSP 等等都可。
这一章节的代码
在开发板介绍百度网盘链接中:立创·梁山派·天空星STM32F407VET6开发板资料/第03章软件资料/代码例程/001 寄存器点灯。
烧写我们的代码之后,可以看到开发板的 LED 这个灯将被点亮。