STM32 Getting Started Series - bit operating description

To introduce STM32F1 bit-band operation, so that the STM32 51-bit operations and bit microcontroller as simple.

Bit operation

在学习 51 单片机的时候就使用过位操作,通过关键字 sbit 对单片机 IO 口进行位定义。但是 STM32 没有这样的关键字,而是通过访问位带别名区来实现。即将每个比特位膨胀成一个 32 位字,当访问这些字的时候就达到了访问比特的目的。比方说 BSRR 寄存器有 32 个位,那么可以映射到 32 个地址上,当我们去访问这 32 个地址就达到访问 32 个比特的目的。
STM32F1 中有两个区域支持位带操作,一个是 SRAM 区的最低 1MB 范围,一个是片内外设区的最低 1MB 范围(APB1、APB2、AHB 外设)。如下图所示:

Here Insert Picture Description

从图中可知,SRAM 的最低 1MB 区域,地址范围是 0X2000 0000-0X200FFFFF。片内外设最低 1MB 区域,地址范围是 0X4000 0000-0X400F FFFF,在这个地址范围内包括了 APB1、APB2、AHB 总线上所有的外设寄存器。
在 SRAM 区中还有 32MB 空间,其地址范围是 0X2200 0000-0X23FF FFFF,它是 SRAM 的 1MB 位带区膨胀后的位带别名区,前面已经说过位带操作,要实现位操作即将每一位膨胀成一个 32 位的字,因此 SRAM 的 1MB 位带区就膨胀为 32MB的位带别名区,通过访问位带别名区就可以实现访问位带中每一位的目的。
片内外设区的 32MB 的空间也是一样的原理。 片内外设区的 32MB 地址范围是0X4200 0000-0X43FF FFFF。
通常我们使用位带操作都是在外设区,在外设区中应用比较多的也就是GPIO 外设,SRAM 区内很少使用位操作。

Bit-band bit-band alias region area address

前面已经说过, 位带操作就是将位带区中的每一位膨胀成位带别名区中的一个 32 位的字,通过访问位带别名区中的字就实现了访问位带区中位的目的。因此我们就可以使用指针来访问位带别名区的地址, 从而实现访问位带区内位的目的。那么位带别名区与位带区地址是如何转换的,我们下面就来介绍下。

(1) the peripheral region bit-band alias address
for a bit position with on-chip peripheral area, in which it is referred to as the byte address A, bit number is n, the value of n ranges 0-7, the bits in the address region is an alias:
AliasAddr = 0x42000000 + (a-0x40000000) . 8 . 4 n-+ . 4
0x42000000 bit start address is the peripheral band alias region, 0x40000000 start address bits with the peripheral region, (a-0x40000000) represents the number of bytes in front of the bit, a byte is 8 bits, so that
8, after the expansion of a 4-bit bytes, 4, n represents the number of bits in the address a, because a four-bit after expansion bytes, so it is 4.
(2) with the alias region SRAM bit address
for a certain bit SRAM bit-band region, in which it is referred to as the byte address A, bit number is n, the value of n ranges 0-7, the bit in the alias region address:
AliasAddr = 0x22000000 = + (a-0x20000000) . 8 . 4 n-+ . 4
0x22000000 is an SRAM bit start address with the alias region, 0x20000000 is the start address of the SRAM bit-band region, (a-0x20000000) indicates that the bit has number of bytes, a byte is 8 bits, so that
8, after the expansion of a 4-bit bytes, 4, n represents the number of bits in the address a, because a four-bit bytes after expansion, so it 4.
We have above the peripheral region bit-band alias address and the SRAM address bits band alias region using the formula represented for convenience of operation, we combined the two formulas, defined by a macro, and the bit address and bit number this parameter is defined as a macro. Formula is as follows:
#define BitBand (addr, bitnum) ((addr & 0xF0000000) 0x2000000 + + ((addr & 0xFFFFF) <<. 5) + (bitnum << 2))
addr & 0xF0000000 is to distinguish our operation is an SRAM or a peripheral, in fact, get the value of the highest level is 4 or 2. If the operation is peripheral, then addr & 0xF0000000 result 0x40000000, rear + 0x2000000 start address is equal to 0X42000000,0X42000000 peripheral alias region. If the operation is the SRAM, then addr & 0xF0000000 result 0x20000000, rear + 0x2000000 start address is equal to 0X22000000,0X22000000 SRAM alias region.
addr & 0x000FFFFF shielded three high, or the equivalent of subtracting 0X20000000
0x40000000, shielded three high because the highest address bit SRAM and peripheral band is arbitrary address 0X200F FFFF and 0X400F FFFF, SRAM bit-band region or peripheral subtracting the corresponding start address, the lower 5 bits are always active, so here is equivalent to shielding the high three or subtracted 0X20000000 0X40000000. << 5 equivalent . 8 4, 4 * << 2 corresponds, in its role already analyzed.
Finally these bits may be operated with the alias address region, to achieve the bit-band operation by the bit pointer form. code show as below:
// the address addr cast to an unsigned long pointer
#define mem_addr (addr) * ((volatile unsigned long *) (addr))
// the address translation bit-band alias region pointer, the data acquired in the address
# define BIT_ADDR (addr, bitnum) mEM_ADDR (BITBAND (addr, bitnum))
described here under the volatile keyword, volatile remind compiler variables defined behind it could change at any time, so the compiled program each time you need to store or read take this variable, the variable will be read directly from the address data. Without the volatile keyword, the optimizing compiler may read and store, may temporarily use the value in the register, if this variable is updated by the other program, it will appear inconsistencies. More details you can Baidu search.

Bit operating advantages

在 STM32 应用程序开发中虽然可以使用库函数操作外设, 但如果加上位操作就如虎添翼。想想 51 单片机内位操作的方便,就可以理解为什么要对 STM32 使用位操作。STM32 位操作优点非常多,我们这里就列举几个突出的:

(1) for controlling input and output GPIO very simple.
(2) operation of the serial interface chip is very convenient (DS1302,74HC595, etc.), if a library function, then the timing is very inconvenient to write.
(3) code is simple and easy to read.

GPIO bit operation

我们已经知道 STM32F1 支持的位带操作区有两个, 其中应用最多的还是外设位带区,在外设位带区中包含了 APB1、APB2 还有 AHB 总线上的所有外设寄存器,使用位带操作应用最多的外设还属 GPIO,通过位带操作控制 STM32 引脚输入与输出,因此我们就以 GPIO 中 IDR 和 ODR 这两个寄存器的位操作进行讲解。
根据《STM32F10x 中文参考手册》对应的 GPIO 寄存器章节中可以知道,IDR和 ODR 寄存器相对于 GPIO 基地址的偏移量是 8 和 12。所以可以通过宏定义实现这两个寄存器的地址映射,具体代码如下:

//IO 口地址映射
#define GPIOA_ODR_Addr (GPIOA_BASE+12) //0x4001080C
#define GPIOB_ODR_Addr (GPIOB_BASE+12) //0x40010C0C
#define GPIOC_ODR_Addr (GPIOC_BASE+12) //0x4001100C
#define GPIOD_ODR_Addr (GPIOD_BASE+12) //0x4001140C
#define GPIOE_ODR_Addr (GPIOE_BASE+12) //0x4001180C
#define GPIOF_ODR_Addr (GPIOF_BASE+12) //0x40011A0C
#define GPIOG_ODR_Addr (GPIOG_BASE+12) //0x40011E0C
#define GPIOA_IDR_Addr (GPIOA_BASE+8) //0x40010808
#define GPIOB_IDR_Addr (GPIOB_BASE+8) //0x40010C08
#define GPIOC_IDR_Addr (GPIOC_BASE+8) //0x40011008
#define GPIOD_IDR_Addr (GPIOD_BASE+8) //0x40011408
#define GPIOE_IDR_Addr (GPIOE_BASE+8) //0x40011808
GPIOF_IDR_Addr #define (+ GPIOF_BASE. 8) // 0x40011A08
#define GPIOG_IDR_Addr (+ GPIOG_BASE. 8) // 0x40011E08
from the above code can see GPIOx_BASE, this is a macro, which is a respective package GPIO port base address, library the function is defined.
After obtaining the address register, bit manipulation methods can be employed to operate the GPIO input and output, the following code:
// IO port operation, only a single IO port
// Make sure the value of n is less than 16
#define PAout (n) BIT_ADDR (GPIOA_ODR_Addr, n) // output
#define PAin (n) BIT_ADDR (GPIOA_IDR_Addr , n) // input
#define PBout (n) BIT_ADDR (GPIOB_ODR_Addr , n) // output
#define pBin (n) BIT_ADDR (GPIOB_IDR_Addr , n ) // input
#define PCout (n) BIT_ADDR (GPIOC_ODR_Addr , n) // output
#define PCin (n) BIT_ADDR (GPIOC_IDR_Addr , n) // input
#define PDout (n) BIT_ADDR (GPIOD_ODR_Addr , n) // output
# define PDin (n) BIT_ADDR (GPIOD_IDR_Addr , n) // input
#define PEout (n) BIT_ADDR (GPIOE_ODR_Addr , n) // output
#define PEin (n) BIT_ADDR (GPIOE_IDR_Addr , n) // input
#define PFout (n) BIT_ADDR (GPIOF_ODR_Addr , n) // output
#define PFin (n ) BIT_ADDR (GPIOF_IDR_Addr, n) // input
#define pGout (n) BIT_ADDR (GPIOG_ODR_Addr , n) // output
#define PGin (n) BIT_ADDR (GPIOG_IDR_Addr , n) // enter
all of the above code chip we have STM32F1 port bit definitions package carried out, if the output pins PC0 to be used, then it can call PCout (n) macro, n-value is the 0. If PC0 is used as an input pin, then you can call PCin (n) macro, n-value is the 0. Other methods similar port calls.
In addition, I receive this free core board need or want to exchange my private friends can learn WBL (One Triple Wu Lu II, II-VI zero-zero II Jiu)

Guess you like

Origin blog.csdn.net/weixin_42832780/article/details/92816255