众所周知,stm32采取的arm cortex 部分系列支持位寻址操作.
下图源于cortex -m4 内核手册.
位操作的介绍
Bit band region 为支持位寻址的区域, Bit band alias为Bit band region的位编址区 ( 为Bit band region中的每一位都编址 ) .
尽管存储器中支持位寻址的区域有限,但这仍然囊括stm32中大部分常用外设寄存器.
以stm32f4系列为例.
由表可知,以0x4xxx xxxx 开头的外设寄存器地址都是在内核支持的位操作区域内的, 我们可以修改这些外设寄存器中的单独一位,而不用进行 读出寄存器值–>位运算改–>写回寄存器 系列操作.
位寻址操作映射关系如下.
下面是官方给出的例子.
以下是我个人的用法.
/*注意该宏仅支持外设部分的位设置*/
#define __BIT_SET(WORD_ADDR, BIT_ADDR, BIT) *(uint32_t *)(0x42000000 + (((WORD_ADDR) & 0x0fffffff) << 5) + ((BIT_ADDR) << 2)) = (BIT)
官方给出的映射算式可以替换为由移位和逻辑运算组成的版本,提高运算速度.
//eg:
__BIT_SET(GPIOA_ODR, 7, 1);
//可以以极快的速度修改GPIOA Pin7 的输出电平.
接近于软件翻转电平的理论上限(50MHz,100MHz…)
同时相较于下程序所示用法
GPIOA->ODR|=1<<7;
避免了数据读->改->写的繁琐步骤.
消除了程序在多线程运行时,同时修改ODR寄存器导致数据紊乱的情况.
呃…虽然说直接修改BSRR寄存器也可达到同样效果,但是说,可能不太直观?
GPIOA->BSRR = 1<<7;//位设置
GPIOA->BSRR = 1<<(7+16); //位清除
位域指针的应用
得益于cortex 内核可以精细寻址到部分位.
那么是否在STM32中也可以使用位域语法呢?
还是以操作IO口为例.
// GPIOA base: 0x40020000
//ODR偏移: 0x14
/*初始化结构体*/
typedef struct
{
uint32_t p0 : 1;
uint32_t p1 : 1;
uint32_t p2 : 1;
uint32_t p3 : 1;
uint32_t p4 : 1;
uint32_t p5 : 1;
uint32_t p6 : 1;
uint32_t p7 : 1;
uint32_t p8 : 1;
uint32_t p9 : 1;
uint32_t p10 : 1;
uint32_t p11 : 1;
uint32_t p12 : 1;
uint32_t p13 : 1;
uint32_t p14 : 1;
uint32_t p15 : 1;
uint32_t reverse : 16;
} GPIOA_odr_t;
GPIOA_odr_t *gpioa = (GPIOA_odr_t *)(0x40020014);
/*应用*/
gpioa->p7 = 0;//翻转电平
gpioa->p7 = 1;
是否有种51的既视感呢?
集直观与速度与一身的用法,对软件刷屏大有脾益.
好了,今天就分享到这了,新人发帖,感谢观看!
限于编者水平,有误还望海涵,欢迎批评指正.