STM32 中 BIT_BAND(位段/位带)和别名区使用入门

本文详细介绍了STM32中的位带操作概念及其应用场景,包括位带操作的基本原理、如何利用位带别名区提高代码效率,以及具体的实现方法。通过对比不同的操作方式,展示了位带操作的优势。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、 什么是位段和别名区

    是这样的,记得MCS51吗? MCS51就是有位操作,以一位(BIT)为数据对象的操作,MCS51可以简单的将P1口的第2位独立操作: P1.2=0;P1.2=1 ;这样就把P1口的第三个脚(BIT2)置0置1。而现在STM32的位段、位带别名区就为了实现这样的功能。

    它的对象可以是SRAM、I/O和外设空间。要实现对这些地方的某一位的操作。它是这样做的:在寻址空间(32位对应的地址空间为 4GB )的另一地方,取个别名区空间,从这个地址开始处,每一个字(32BIT)对应SRAM或I/O的一位。
     
    这样,1MB SRAM 就可以有 32MB 的对应别名区空间,就是1位膨胀到32位(1 BIT 变为1个字节)。我们对这个别名区空间内的某一字操作(置0或置1),就等于它映射的 SRAM 或 I/O 相应的某地址的某一位的操作。

二、使用位段的好处
     
    简单来说,可以把代码缩小, 速度更快,效率更高,更安全。 一般操作要6条指令,而使用位带别名区只要4条指令。一般操作是 读-改-写的方式, 而位带别名区是 写 操作。防止中断对 读-改-写 的方式的影响。

三、应用说明

    支持了位带操作(bit_band),有两个区中实现了位带。其中一个是SRAM 区的最低1MB 范围,第二个则是片内外设区的最低1MB 范围。这两个区中的地址除了可以像普通的RAM 一样使用外,它们还都有自己的“位带别名区”,位带别名区把每个比特膨胀成一个 32 位的字。 每个比特膨胀成一个32 位的字,就是把 1M 扩展为 32M 。

    于是,位于 RAM 地址 0X200000000 的一个字节扩展为8个32 位的字,扩展后每位相对应的的地址是:0X220000000,0X220000004,0X220000008,0X22000000C,0X220000010,0X220000014, 0X220000018,0X22000001C


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

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

    对 SRAM 位带区的某个比特,记该比特所在字节的地址为A,位序号为 n (0<=n<=7),则它在别名区的地址为:

AliasAddr = 0x22000000 + ((A‐0x20000000)*8+n)*4 =0x22000000 + (A‐0x20000000)*32 + n*4

对于片上外设位带区的某个比特,记该比特所在字节的地址为A,位序号为 n (0<=n<=7),则该比特在别名区的地址为:

AliasAddr = 0x42000000 + ((A‐0x40000000)*8+n)*4 = 0x42000000 + (A‐0x40000000)*32 + n*4

上式中,“*4”表示一个字为 4 个字节,“*8”表示一个字节中有 8 个比特。


    把“位带地址+位序号”转换别名地址宏为:

#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000 + ((addr &0xFF FFF)<<5) + (bitnum<<2))

    把该地址转换成一个指针:

#define MEM_ADDR(addr) *((volatile unsigned long *)(addr))
MEM_ADDR(BITBAND( (u32)&CRCValue,1)) = 0x1;

例如点亮LED

使用STM32库:
   GPIO_ResetBits(GPIOC, GPIO_Pin_4); //关LED5
   GPIO_SetBits(GPIOC, GPIO_Pin_7);   //开LED2

一般读操作:
    STM32_Gpioc_Regs->bsrr.bit.BR4 =1;// 1:清除对应的ODRy位为0
    STM32_Gpioc_Regs->bsrr.bit.BS7 =1;// 1:设置对应的ODRy位为1

如果使用位带别名区操作:
STM32_BB_Gpioc_Regs->BSRR.BR[4] =1;// 1:清除对应的ODRy位为0
STM32_BB_Gpioc_Regs->BSRR.BS[7] =1;// 1:设置对应的ODRy位为1

代码比STM32库高效十倍 !

对内存变量的位操作:

SRAM 变量:long CRCValue;

把“位带地址+位序号”转换别名地址宏:

#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2))

把该地址转换成一个指针:

#define MEM_ADDR(addr) *((volatile unsigned long *)(addr))

对32位变量 的BIT1 置 1 :

MEM_ADDR(BITBAND( (u32)&CRCValue,1)) = 0x1;

对任意一位( 第23位 ) 判断:

if(MEM_ADDR(BITBAND( (u32)&CRCValue,23))==1)
{

}

四、Cortex-M3中关于位段的定义

    Cortex-M3 存储器映像包括两个位段(bit-band)区。这两个位段区将别名存储器区中的每个字映射到位段存储器区的一个位,在别名存储区写入一个字具有对位段区的目标位执行读-改-写操 作的相同效果。

    所有STM32F10x外设寄存器都被映射到一个位段(bit-band)区。这个特性在各个函数中对单个比特进行置1/置0操作时被大量使用,用以减小和优化代码尺寸。

映射公式映射

公式给出别名区中的每个字是如何对应位带区的相应位的,公式如下:

bit_word_offset = (byte_offset x 32) + (bit_number × 4)
bit_word_addr = bit_band_base + bit_word_offset

其中:
bit_word_offset是目标位在存取器位段区中的位置
bit_word_addr 是别名存储器区中字的地址,它映射到某个目标位。
bit_band_base 是别名区的起始地址。
byte_offset 是包含目标位的字节在位段中的序号
bit_number 是目标位所在位置(0-31)

### 如何在STM32中定义变量 在STM32开发中,变量的定义遵循C语言的标准规则。以下是一个详细的说明以及示例代码,展示如何在STM32中定义不同类型的变量。 #### 1. 基本数据类型变量 STM32支持标准C语言中的所有基本数据类型,例如`int`、`float`、`char`等。以下是定义这些变量的示例: ```c int integerVariable = 10; // 定义一个整型变量并赋初值为10 float floatVariable = 3.14; // 定义一个浮点型变量并赋初值为3.14 char characterVariable = 'A'; // 定义一个符型变量并赋初值为'A' ``` #### 2. 变量的实现 由于STM32架构不直接支持处理[^1],因此需要通过结构体的方式来实现变量。以下是一个变量的定义示例: ```c typedef struct { unsigned char b0 : 1; // 定义第0 unsigned char b1 : 1; // 定义第1 unsigned char b2 : 1; // 定义第2 unsigned char b3 : 1; // 定义第3 unsigned char b4 : 1; // 定义第4 unsigned char b5 : 1; // 定义第5 unsigned char b6 : 1; // 定义第6 unsigned char b7 : 1; // 定义第7 } BIT8; BIT8 bitVariable; // 使用该结构体定义一个变量 bitVariable.b0 = 1; // 设置b0为1 bitVariable.b7 = 0; // 设置b7为0 ``` #### 3. 定时器相关的变量 如果需要定义定时器相关的变量(如PWM输出),可以参考如下代码。以下是一个用于控制PWM占空比的变量定义示例[^2]: ```c uint16_t duty_num = 0; // 定义一个无符号短整型变量用于存储PWM占空比 // 在循环中更新PWM占空比 duty_num += 10; if (duty_num > 500) { duty_num = 0; } __HAL_TIM_SetCompare(&htim2, TIM_CHANNEL_2, duty_num); // 更新TIM2通道2的比较值 ``` #### 4. 指针变量 在嵌入式开发中,指针变量常用于直接操作硬件寄存器。以下是一个指针变量的定义示例: ```c uint32_t *registerPointer = (uint32_t *)0x40020C00; // 定义一个指向地址0x40020C00的32无符号整型指针 *registerPointer = 0xA5; // 向该地址写入值0xA5 ``` #### 5. 数组变量 数组变量在STM32中同样遵循C语言的规则。以下是一个数组变量的定义示例: ```c int arrayVariable[5] = {1, 2, 3, 4, 5}; // 定义一个包含5个元素的整型数组 arrayVariable[0] = 10; // 修改数组的第一个元素为10 ``` ### 总结 以上展示了在STM32中定义不同类型变量的方法,包括基本数据类型、变量、定时器相关变量、指针变量数组变量。每种变量的定义方式都基于C语言的标准语法,并结合了STM32的具体应用场景。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值