一、点灯实验简介
在嵌入式系统开发中,点亮 LED 灯如同编程世界的 "Hello World",是最基础也是最重要的入门实验。通过这个实验,我们可以了解单片机 GPIO(通用输入输出)端口的基本操作原理和配置方法。本文将详细介绍如何基于 STM32 单片机,使用寄存器和库函数两种方式实现 LED 点灯。
二、硬件连接与原理图分析
1. LED 连接原理图
在我们的实验中,LED(D0)连接在 STM32 芯片的 PB5 引脚上。LED 的阳极通过限流电阻连接到 VCC(3.3V),阴极连接到 PB5 引脚。根据电路原理,当 PB5 引脚输出低电平时,LED 两端形成电压差,电流流过 LED,使其点亮;反之,当 PB5 引脚输出高电平时,LED 熄灭。
2. GPIO 与时钟控制原理
STM32 的 GPIO 端口需要先使能相应的时钟才能正常工作。PB 端口(GPIOB)由 APB2 总线控制,其时钟由 RCC_APB2ENR 寄存器控制。具体来说,我们需要将 RCC_APB2ENR 寄存器的第 3 位置 1,才能开启 GPIOB 的时钟。
3. GPIO 端口配置原理
对于 PB5 引脚的配置,我们需要设置其工作模式为通用推挽输出。在 STM32 中,每个 GPIO 端口的配置由两个 32 位寄存器控制:CRL(低 16 位引脚,对应 Pin0~Pin7)和 CRH(高 16 位引脚,对应 Pin8~Pin15)。由于我们使用的是 PB5 引脚,属于低 8 位引脚,因此需要配置 GPIOB_CRL 寄存器的 20~23 位。
三、寄存器方式实现 LED 点灯
1. 时钟使能
// GPIOB时钟使能
RCC->APB2ENR |= (0x1 << 3);
这段代码的作用是将 RCC_APB2ENR 寄存器的第 3 位置 1,从而开启 GPIOB 的时钟。0x1 << 3 表示将二进制数 00000001 左移 3 位,得到 00001000(即十进制的 8),然后通过按位或操作将该位设置为 1。
2. 端口配置
// GPIOB配置通用推挽输出
GPIOB->CRL &= ~(0xf << 20); // 清除原来的配置
GPIOB->CRL |= (0x2 << 20); // 设置为通用推挽输出,最大速度2MHz
这里首先清除 GPIOB_CRL 寄存器的 20~23 位(通过按位与操作和取反),然后将其设置为 0x2(即二进制的 0010),表示通用推挽输出模式,最大输出速度为 2MHz。
3. 控制 LED 点亮
// 端口输出0,点亮灯泡
GPIOB->ODR &= ~(0x1 << 5); // 将ODR寄存器的第5位清零,输出低电平
这段代码通过清除 GPIOB_ODR 寄存器的第 5 位,使 PB5 引脚输出低电平,从而点亮 LED。
四、库函数方式实现 LED 点灯
1. 引入必要的头文件
#include "stm32f10x.h"
2. 时钟使能
// 时钟使能
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
使用 STM32 标准外设库提供的函数 RCC_APB2PeriphClockCmd 来使能 GPIOB 的时钟,相比寄存器方式更加直观和安全。
3. 端口配置
// PB的GPIO配置 通用推挽输出 输出1灯熄灭 输出0灯点亮
GPIO_InitTypeDef led_D0;
led_D0.GPIO_Pin = GPIO_Pin_5; // PB5
led_D0.GPIO_Mode = GPIO_Mode_Out_PP; // 通用推挽输出
led_D0.GPIO_Speed = GPIO_Speed_2MHz; // 2MHz
GPIO_Init(GPIOB, &led_D0);
这里定义了一个 GPIO_InitTypeDef 类型的结构体变量 led_D0,并设置其成员变量。然后调用 GPIO_Init 函数将配置应用到 GPIOB 端口。
4. 控制 LED 点亮
// 端口输出0,点亮灯泡
GPIO_ResetBits(GPIOB, GPIO_Pin_5);
使用 GPIO_ResetBits 函数将 GPIOB 的第 5 位(即 PB5 引脚)置为低电平,点亮 LED。
五、完整代码实现
下面是使用库函数方式实现 LED 点灯的完整代码:
#include "stm32f10x.h"
int main(void)
{
// 时钟使能
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
// PB的GPIO配置 通用推挽输出 输出1灯熄灭 输出0灯点亮
GPIO_InitTypeDef led_D0;
led_D0.GPIO_Pin = GPIO_Pin_5; // PB5
led_D0.GPIO_Mode = GPIO_Mode_Out_PP; // 通用推挽输出
led_D0.GPIO_Speed = GPIO_Speed_2MHz; // 2MHz
GPIO_Init(GPIOB, &led_D0);
// 点亮LED
GPIO_ResetBits(GPIOB, GPIO_Pin_5);
while (1)
{
// 主循环可以留空,LED将持续点亮
}
}