第03章 点亮LED案例
约 671 字大约 2 分钟
2026-01-19
① 基础版
直接表示寄存器地址。
#include <stdint.h>
// 主函数
int main()
{
// 1. 对 GPIOA 时钟使能;RCC_APB2ENR 寄存器中的 IOPA 控制位置 1
*(uint32_t *)(0x40021000 + 0x18) = 0x00000004;
// 2. 设置 PA0 的 GPIO 模式,设置为通用推挽输出;GPIOA_CRL 中的 CNF=00,MODE0=11 低4位为0011,其他为默认值 0100
*(uint32_t *)(0x40010800 + 0x00) = 0x44444443;
// 3. 设置 PA0 输出低电平
*(uint32_t *)(0x40010800 + 0x0C) = 0;
// 死循环,防止程序跑飞
while (1)
;
}② 优化1
使用 stm32f10x.h 头文件中已定义好的宏表示寄存器地址。
#include <stdint.h>
#include "stm32f10x.h"
// 点亮LED2(连接MCU的PA1引脚)
// 主函数
int main()
{
// 1. 对 GPIOA 时钟使能;RCC_APB2ENR 寄存器中的 IOPA 控制位置 1
RCC->APB2ENR = 0x00000004;
// 2. 设置 PA1 的 GPIO 模式,设置为通用推挽输出;GPIOA_CRL 中的 CNF=00,MODE0=11 低4位为0011,其他为默认值 0100
GPIOA->CRL = 0x44444434;
// 3. 设置 PA1 输出低电平,其他引脚输出高电平
GPIOA->ODR = 0xFFFFFFFD;
// 死循环,防止程序跑飞
while (1)
;
}③ 优化2
利用位运算只修改寄存器中对应的位,其他位保持不变。
给寄存器R的第n位置1:
R |= (1 << n)
给寄存器R的第n位置0:
R &= ~(1 << n)#include <stdint.h>
#include "stm32f10x.h"
// 点亮LED3(连接MCU的PA8引脚)
// 主函数
int main()
{
// 1. 对 GPIOA 时钟使能;RCC_APB2ENR 寄存器中的 IOPA 控制位(第2位)置 1
RCC->APB2ENR |= (1 << 2);
// 2. 设置 PA8 的 GPIO 模式,设置为通用推挽输出;GPIOA_CRH 中的 CNF8=00(2、3位),MODE8=11(0、1位) 低4位为0011,其他为默认值 0100
GPIOA->CRH |= (1 << 0); // MODE8_0 = 1
GPIOA->CRH |= (1 << 1); // MODE8_1 = 1
GPIOA->CRH &= ~(1 << 2); // CNF8_0 = 0
GPIOA->CRH &= ~(1 << 3); // CNF8_1 = 0
// 3. 设置 PA8 输出低电平 (ODR寄存器的ODR8位置0),其他引脚输出高电平
GPIOA->ODR &= ~(1 << 8);
// 死循环,防止程序跑飞
while (1)
;
}③ 优化3
stm32f10x.h头文件中给寄存器中的每个位(掩码)都定义了宏
#include <stdint.h>
#include "stm32f10x.h"
// 点亮LDE1、LED2、LED3(PA0、PA1、PA8)
// 主函数
int main()
{
// 1. 对 GPIOA 时钟使能;RCC_APB2ENR 寄存器中的 IOPA 控制位(第2位)置 1
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
// 2. 设置 PA0、PA1、PA8 的 GPIO 模式,设置为通用推挽输出,CNF=00,MODE=11
// 2.1 设置PA0
GPIOA->CRL |= GPIO_CRL_MODE0;
GPIOA->CRL &= ~GPIO_CRL_CNF0;
// 2.2 设置PA1
GPIOA->CRL |= GPIO_CRL_MODE1;
GPIOA->CRL &= ~GPIO_CRL_CNF1;
// 2.3 设置PA8
GPIOA->CRH |= GPIO_CRH_MODE8;
GPIOA->CRH &= ~GPIO_CRH_CNF8;
// 3. 设置 PA0、PA1、PA8 输出低电,其他引脚输出高电平
GPIOA->ODR &= ~(GPIO_ODR_ODR0 | GPIO_ODR_ODR1 | GPIO_ODR_ODR8);
// 死循环,防止程序跑飞
while (1)
;
}