通过操作地址,来进行STM32的写入GPIO端口值

在STM32F103C8T6中通过操作地址的方式进行端口写入,就是直接操作GPIO的寄存器地址。这是最底层、最高效的控制方式。

一.预先准备

1. 首先找到GPIO端口的基地址

#define GPIOA_BASE 0x40010800

#define GPIOB_BASE 0x40010C00

#define GPIOC_BASE 0x40011000

#define GPIOD_BASE 0x40011400

2. GPIO相关寄存器偏移地址

// 每个GPIO端口的寄存器偏移量

#define GPIO_CRL_OFFSET 0x00 // 端口配置低寄存器

#define GPIO_CRH_OFFSET 0x04 // 端口配置高寄存器

#define GPIO_IDR_OFFSET 0x08 // 端口输入数据寄存器

#define GPIO_ODR_OFFSET 0x0C // 端口输出数据寄存器

#define GPIO_BSRR_OFFSET 0x10 // 端口位设置/清除寄存器

#define GPIO_BRR_OFFSET 0x14 // 端口位清除寄存器

二. 通过ODR寄存器写入1

方法1:直接操作ODR寄存器

// 定义GPIOA的ODR寄存器地址

#define GPIOA_ODR (*(volatile uint32_t *)(GPIOA_BASE + GPIO_ODR_OFFSET))

// 向PA0写入1

void Write_PA0_High(void)

{

GPIOA_ODR |= (1 << 0); // 将第0位置1,其他位保持不变

}

// 向PA5写入1

void Write_PA5_High(void)

{

GPIOA_ODR |= (1 << 5); // 将第5位置1

}

方法2:使用BSRR寄存器

// 定义GPIOA的BSRR寄存器地址

#define GPIOA_BSRR (*(volatile uint32_t *)(GPIOA_BASE + GPIO_BSRR_OFFSET))

// 向PA0写入1(设置位)

void Set_PA0_High(void)

{

GPIOA_BSRR = (1 << 0); // 设置第0位为1

}

// 向PA5写入1

void Set_PA5_High(void)

{

GPIOA_BSRR = (1 << 5); // 设置第5位为1

}

三. 完整的使用示例

1.方法1

#include "stm32f10x.h"

// 定义寄存器地址

#define GPIOA_BASE 0x40010800

#define GPIOA_CRL (*(volatile uint32_t *)(GPIOA_BASE + 0x00))

#define GPIOA_ODR (*(volatile uint32_t *)(GPIOA_BASE + 0x0C))

#define GPIOA_BSRR (*(volatile uint32_t *)(GPIOA_BASE + 0x10))

// 开启时钟的地址

#define RCC_BASE 0x40021000

#define RCC_APB2ENR (*(volatile uint32_t *)(RCC_BASE + 0x18))

void GPIO_Init_By_Address(void)

{

// 1. 开启GPIOA时钟

RCC_APB2ENR |= (1 << 2); // 开启IOPA时钟

// 2. 配置PA5为推挽输出,最大速度50MHz

// CRL寄存器每4位控制一个引脚(0-7),PA5在[23:20]位

GPIOA_CRL &= ~(0xF << 20); // 先清零配置位

GPIOA_CRL |= (0x3 << 20); // 输出模式,最大速度50MHz

GPIOA_CRL |= (0x0 << 22); // 推挽输出模式

}

// 向PA5写入1

void PA5_Set_High(void)

{

GPIOA_BSRR = (1 << 5); // 使用BSRR设置位

}

// 向PA5写入0

void PA5_Set_Low(void)

{

GPIOA_BSRR = (1 << (5 + 16)); // 使用BSRR清除位(位16-31是清除位)

}

// 翻转PA5电平

void PA5_Toggle(void)

{

if (GPIOA_ODR & (1 << 5)) {

PA5_Set_Low(); // 当前为高,设为低

} else {

PA5_Set_High(); // 当前为低,设为高

}

}

这样子就可以写入了。

2.方法2

// 同时设置多个引脚为1

void Set_Multiple_Pins_High(void)

{

// 同时设置PA0、PA5、PA10为1

GPIOA_BSRR = (1 << 0) | (1 << 5) | (1 << 10);

}

// 使用ODR寄存器同时设置多个引脚(会影响到其他位)

void Set_Multiple_Pins_ODR(void)

{

// 设置PA0、PA5为1,其他位保持不变

GPIOA_ODR |= (1 << 0) | (1 << 5);

}

3.LED闪烁

// 假设LED连接在PC13上

#define GPIOC_BASE 0x40011000

#define GPIOC_CRH (*(volatile uint32_t *)(GPIOC_BASE + 0x04))

#define GPIOC_BSRR (*(volatile uint32_t *)(GPIOC_BASE + 0x10))

#define RCC_APB2ENR (*(volatile uint32_t *)(0x40021000 + 0x18))

void LED_Init(void)

{

// 开启GPIOC时钟

RCC_APB2ENR |= (1 << 4); // 开启IOPC时钟

// 配置PC13为推挽输出

// PC13在CRH寄存器[23:20]位

GPIOC_CRH &= ~(0xF << 20); // 清零配置位

GPIOC_CRH |= (0x3 << 20); // 输出模式,最大速度50MHz

GPIOC_CRH |= (0x0 << 22); // 推挽输出模式

}

void LED_On(void)

{

GPIOC_BSRR = (1 << 13); // PC13置1,LED亮

}

void LED_Off(void)

{

GPIOC_BSRR = (1 << (13 + 16)); // PC13清0,LED灭

}

void LED_Toggle(void)

{

// 简单的延时函数

volatile uint32_t i;

for(i = 0; i < 1000000; i++);

// 翻转LED

if (GPIOC_ODR & (1 << 13)) {

LED_Off();

} else {

LED_On();

}

}

int main(void)

{

LED_Init();

while(1)

{

LED_Toggle(); // LED闪烁

}

}

四. 关键要点总结

  1. BSRR vs ODR

    • BSRR:原子操作,只影响指定的位,推荐使用

    • ODR:需要读-修改-写操作,可能影响其他位

  2. BSRR寄存器特点

    • 位0-15:设置位(写1对应引脚输出高电平)

    • 位16-31:清除位(写1对应引脚输出低电平)

    • 写0的位没有任何效果

  3. 操作步骤

    • 开启对应GPIO端口的时钟

    • 配置GPIO为输出模式

    • 通过BSRR或ODR寄存器控制输出电平

最后我们来看一看数据手册

这也是详细的介绍过程。

相关推荐
代码游侠9 小时前
学习笔记——设备树基础
linux·运维·开发语言·单片机·算法
xuxg200511 小时前
4G 模组 AT 命令解析框架课程正式发布
stm32·嵌入式·at命令解析框架
CODECOLLECT12 小时前
京元 I62D Windows PDA 技术拆解:Windows 10 IoT 兼容 + 硬解码模块,如何降低工业软件迁移成本?
stm32·单片机·嵌入式硬件
BackCatK Chen13 小时前
STM32+FreeRTOS:嵌入式开发的黄金搭档,未来十年就靠它了!
stm32·单片机·嵌入式硬件·freertos·低功耗·rtdbs·工业控制
全栈游侠16 小时前
STM32F103XX 02-电源与备份寄存器
stm32·单片机·嵌入式硬件
Lsir10110_16 小时前
【Linux】中断 —— 操作系统的运行基石
linux·运维·嵌入式硬件
深圳市九鼎创展科技18 小时前
瑞芯微 RK3399 开发板 X3399 评测:高性能 ARM 平台的多面手
linux·arm开发·人工智能·单片机·嵌入式硬件·边缘计算
辰哥单片机设计18 小时前
STM32项目分享:车辆防盗报警系统
stm32·单片机·嵌入式硬件
風清掦19 小时前
【江科大STM32学习笔记-05】EXTI外部中断11
笔记·stm32·学习
小龙报19 小时前
【51单片机】从 0 到 1 玩转 51 蜂鸣器:分清有源无源,轻松驱动它奏响新年旋律
c语言·数据结构·c++·stm32·单片机·嵌入式硬件·51单片机