从STM32的位带操作重谈嵌入式中寻址与对齐的理解
发布日期:2021-05-14 09:05:43 浏览次数:11 分类:精选文章

本文共 2160 字,大约阅读时间需要 7 分钟。

转载自:http://www.cnblogs.com/apollius/archive/2012/12/02/2797604.html

觉得这篇文章很不错,普及知识:

【@.1 从位带操作开始】

初接触STM32的人可能会花不少时间来理解位带操作(bit banding)的原理与步骤。位带操作允许编程人员以字的单位读/写单个bit位。想想我们平时对于一个bit位的操作就如下面代码所示:

```c@---> PIN0 |= (1 << 3);@---> PIN0 &= ~(1 << 5);```

虽然这段代码看起来只有一行,但实际上做了很多工作。例如,第一行代码首先读取当前PIN0的值并存储到缓存区,然后将1左移三位放入缓存区,接着进行“或”操作,更新PIN0的值。汇编语言中这些步骤可能不那么明显,但这些工作都是必然要做的。

对于位带操作,STM32将每个bit位重新映射到一个单独的地址,只需对这个新地址进行写操作,就可以自动将原PIN0对应位设置或清零。例如,假设PIN0的第3bit位重新映射的地址用变量PIN0BIT3表示,那么上述操作可以写成:

```c@---> PIN0BIT3 = 1; // 等同于PIN0 |= (1 << 3)```

这一行代码通过写入PIN0BIT3所在的地址,确保了PIN0的第3bit位被置1。这样操作比之前简单快捷,处理速度也更快。

接下来,我们自然会想知道PIN0第三bit位重新映射的地址在哪里?位带操作的地址重映射是否有限制?原地址和重映射地址之间有什么转换公式?

我们可以参考STM32官方手册。STM32F1系列及其编程参考书中都有关于位带操作的详细说明,包括地址重映射的计算公式。

【@.2 字,字节,半字与寻址方式】

先回顾一些基本概念。在计算机中,二进制的单位包括比特(bit)、字节(byte)和半字(half-word)。这些概念直接关系到内存寻址方式和数据存储方式。

比特(bit)是计算机中最基本的单位,每个比特只能有0或1两个值。字节(byte)是8个比特的集合,常用来衡量存储单元的大小。半字(half-word)则是16个比特或32个比特的集合,具体取决于处理器的架构。每个字可以对应一个寄存器的大小,如ARM处理器的32位寄存器就需要4个字节(32bit)来存储。

在ARM架构中,数据和指令是以字(word)为单位存储和访问的。每个寄存器占用4个字节(32bit)的空间,这样多个寄存器可以连续存放到物理地址中,提高访问效率。例如,GPIO寄存器通常会被定义为连续的32bit值,确保快速访问和操作。

【@.3 字节对齐,字节序 Endianness】

在计算机中,字节对齐和字节序(endianness)是数据存储和访问的关键问题。字节对齐确保数据在内存中的存储位置是正确的,字节序决定了多字节数据在内存中的排列顺序。

以GPIO寄存器为例,假设地址0xE0028000存储了一个32bit的值。该地址的实际存储内容可能是0xDD, 0xCC, 0xBB, 0xAA等四个字节组成的值。读取时,我们需要明确字节序是大端(big-endian)还是小端(little-endian)。大端的高位数存放在地址的低位,小端则相反。ARM架构通常使用小端字节序,这在读取和写入寄存器时非常重要,确保数据的正确性和一致性。

【@.4 再看位带操作】

位带操作的核心原理在于将单个bit位映射到一个独立的地址。STM32中的位带操作区(bit band region)允许每个bit位扩展到一个32bit的别名地址(bit band alias)。这样,每个bit位的操作都可以通过简单的读写操作完成,极大提升了操作效率。

位带操作区的实现涉及到内存的物理地址重映射。编程参考书中提到,允许位带操作的区域有两处:一个是SRAM区,另一个是Peripheral区(外设区),每处均有1MB的空间。通过地址重映射,每个bit位被扩展到一个32bit的别名地址,实现快速的单bit位操作。

例如,在GPIO应用中,通过宏定义可以轻松实现位带操作。定义如下:

```c#define BITBAND(addr, bitnum) ((addr & 0xF0000000) + 0x2000000 + ((addr & 0xFFFFF) << 5) + (bitnum << 2))#define MEM_ADDR(addr) *((volatile unsigned long *)(addr))#define BIT_ADDR(addr, bitnum) MEM_ADDR(BITBAND(addr, bitnum))#define GPIOA_ODR_Addr (GPIOA_BASE + 12) // 0x4001080C#define PAout(n) BIT_ADDR(GPIOA_ODR_Addr, n) // Output```

使用时,只需调用PAout函数传入bit位数即可实现对相应PIN的控制:

```c@---> PAout(4) = 1;```

这种方法简洁高效,充分利用了位带操作的优势,实现了对GPIO引脚状态的快速控制。

上一篇:如何注释你的文档-doxygen版
下一篇:单片机的调试的快捷方式

发表评论

最新留言

初次前来,多多关照!
[***.217.46.12]2025年04月21日 15时13分51秒