【STM32】位带操作

【STM32】位带操作

1.位带操作介绍

为了减少 " 读-改-写 " 操作的次数,Cortex-M3处理器提供了一个可以执行单原子比特操作的位带功能。

存储器映射包含了两个支持位带操作的区域。

其中一个是SRAM区的最低1MB范围,第二个是片内外设区的最低1MB范围。

这两个区域中的地址除了普通应用外,还有自己的 " 位带别名区 " 。

位带别名区把每个比特扩展成一个32位的字。当用户访问位带别名区时,就可以达到访问原始比特的目的。
总结就是CPU不能直接对位带区中的单个数据位位寻址,只能通过对位带别名区的访问(或读/写)实现对位带区单个数据位的访问(或读/写),这种操作被称为位带操作。

使用位带操作的目的是能够像51单片机那样直接给IO口拉高拉低,例如 PCout(13) = 1 这种操作。

【简单来说,这两块区域支持位带操纵,但是得通过操作它们得别名区才能修改它们的值】

2.位带操作内存地址

关于支持位带操作的两个内存区的范围是:

0x2000 0000 ‐ 0x200F FFFF(SRAM 区的最低1MB)

0x4000 0000 ‐ 0x400F FFFF(片上外设区的最低 1MB)

对应的位段别名区的起始地址分别为 0x2200 0000 和 0x4200 0000 ,这个在编程的时候需要使用。



3.完整代码

c 复制代码
// 位带区域基地址定义
#define PERIPH_BASE       0x40000000U  // 外设基地址
#define SRAM_BASE         0x20000000U  // SRAM基地址
#define PERIPH_BB_BASE    0x42000000U  // 外设位带别名基地址
#define SRAM_BB_BASE      0x22000000U  // SRAM位带别名基地址

// 位带地址计算宏(通用)
#define BITBAND_ADDR(base, alias_base, addr, bit) \
    ((alias_base) + (((uint32_t)(addr) - (base)) << 5) + ((bit) << 2))


// SRAM位带地址计算
#define BITBAND_SRAM_ADDR(addr, bit) \
    BITBAND_ADDR(SRAM_BASE, SRAM_BB_BASE, (uint32_t)(addr), bit)

// SRAM位带访问(直接取值/赋值)
#define BITBAND_SRAM(addr, bit) \
    (*(volatile uint32_t*)BITBAND_SRAM_ADDR(addr, bit))

// 外设位带地址计算
#define BITBAND_PERIPH_ADDR(addr, bit) \
    BITBAND_ADDR(PERIPH_BASE, PERIPH_BB_BASE, (uint32_t)(addr), bit)

// 外设位带访问(直接取值/赋值)
#define BITBAND_PERIPH(addr, bit) \
    (*(volatile uint32_t*)BITBAND_PERIPH_ADDR(addr, bit))
c 复制代码
#include <stdio.h>

// 使用示例
int main(void) {
    // 1. SRAM位带操作示例
    volatile uint32_t flags = 0;
    volatile uint32_t status_reg = 0x12345678;
    
    printf("=== SRAM位带操作演示 ===\n");

    // 使用宏方式操作SRAM位
    BITBAND_SRAM(&flags, 0) = 1;  // 设置第0位
    BITBAND_SRAM(&flags, 3) = 1;  // 设置第3位
    printf("设置第0、3位后: 0x%08X\n", flags);
    
    // 读取位状态
    uint32_t bit0 = BITBAND_SRAM(&flags, 0);
    uint32_t bit1 = BITBAND_SRAM(&flags, 1);
    printf("第0位: %d, 第1位: %d\n", bit0, bit1);
    
    // 2. 外设位带操作示例(GPIO控制)
    printf("\n=== GPIO位带操作演示 ===\n");
    
    // 假设GPIO已初始化
    // 设置PA5为高电平
    BITBAND_PERIPH(&GPIOA->ODR, 5) = 1;
    
    // 读取PA5
    if (BITBAND_PERIPH(&GPIOA->IDR, 5)) {
        printf("PA5为高电平\n");
    } else {
        printf("PA5为低电平\n");
    }

}

需要注意的是当你使用位带功能时,要访问的变量必须用volatile来定义。因为c编译器并不知道同一个比特可以有两个地址。通过volatile使得编译器每次都如实地把新数值写入存储器,避免语句被优化。
注意输入的时候,一定要输入地址,而不是变量名。

相关推荐
单片机杂货铺34 分钟前
【单片机毕业设计选题】基于stm32单片机儿童公路车速度检测报警
stm32·单片机·嵌入式硬件·51单片机·硬件工程·课程设计
振南的单片机世界2 小时前
看门狗硬核拆解:1.6秒不喂狗,硬件强制“掀桌子”
arm开发·stm32·单片机·嵌入式硬件
嵌入式阿蔡2 小时前
Linux_01:交叉编译与开发环境实战——从单片机跨到 Linux 的第一道坎
linux·运维·网络·单片机·嵌入式硬件·嵌入式实时数据库
NYFEA3 小时前
徕飞 FCA系列全面上新,一站式I/O扩展国产替代方案
单片机·嵌入式硬件
国科安芯4 小时前
ASL622S:把“信号失真“挡在门外的航天级运放
网络·单片机·嵌入式硬件·架构·状态模式·低轨卫星星座
XiHongShi20164 小时前
STM32H7 FLASH和SRAM标准例程
stm32·单片机·嵌入式硬件
单片机杂货铺5 小时前
【单片机毕业设计选题】基于单片机的智能牛奶保鲜箱设计
人工智能·stm32·单片机·物联网·毕业设计·课程设计
捷瑞电子工坊16 小时前
FreeRTOS任务管理:从入门到实践(标准库版)
stm32·嵌入式·freertos·实时操作系统·任务管理·标准外设库·任务挂起与恢复
莫浅子21 小时前
day01-USB架构与枚举
c++·单片机·嵌入式驱动
恒锐丰科技韩生21 小时前
SS8844T|8.2‑40V 四通道独立半桥驱动 ETSSOP28 带散热焊盘 工业自动化机器人专用
嵌入式硬件·硬件工程