位带操作
位带操作的概念其实很多年前就有了,那还是 8051 单片机开创的先河。如今,CM3 将此能力进化,这里的位带操作是 8051 位寻址区的威力大幅加强版。
官方解释
先来看一下Cortex-M3权威指南中描述的位带操作:
支持了位带操作后,可以使用普通的加载/存储指令来对单一的比特进行读写操作。在CM3中,有两个区中实现了位带。其中一个是 SRAM 区的最低1MB 范围,第二个则是片内外设区的最低 1MB 范围。这两个区中的地址除了可以像普通的 RAM 一样使用外,它们还都有自己的“位带别名区”,位带别名区把每个比特膨胀成一个 32 位的字。当你通过位带别名区访问这些字时,就可以达到访问原始比特的目的。
正点原子库函数指导书解释
位带操作简单的说,就是把每个比特膨胀为一个 32 位的字,当访问这些字的时候就达到了访问比特的目的,比如说 BSRR 寄存器有 32 个位,那么可以映射到 32 个地址上,我们去访问这 32 个地址就达到访问 32 个比特的目的。这样我们往某个地址写 1 就达到往对应比特位写 1 的目的,同样往某个地址写 0 就达到往对应的比特位写 0 的目的。
对比下来还是下面写的更容易理解一些,现在我们知道了位带操作是将一位是数据膨胀为32位的字,那么他是怎么实现的呐?
位带操作地址转换计算
大家先看一下这个图注意一下,下面为位带区(就是原来的位置,占一位),而上面位带别名区(新地址,站32位)。(这里真的不知道咋解释了,试着理解一下吧)
CM3中支持位带操作的地址
首先我们要了解在STM32中有两个区域可以进行位带操作,支持位带操作的两个内存区的范围是:
0x2000 0000-0x200F FFFF (SRAM区中的最低1MB)
0x4000 0000-0x400F FFFF (片上外设区中的最低1MB)
对应别名区的范围为:
0x2200 0000-0x23FF FFFF
0x4200 0000-0x43FF FFFF
从这连个范围就可以看出点问题,支持位带操作的区域大小,差不多比位带别名区小32倍。
这也就表明了确实是位带区的一位,在别名区是32位。那么是怎么转换的那。
官方给了计算公式:
是不是感觉不太好理解,那我们就一起来算一下,到地是不是这么回事。
首先一个官方给的图来做对比,看看结果对不对。
我们就计算两个位置,分别为0x20000000的第0位和0x20000000的第1位.
因为这两个位置都是SRAM位带区的数据所以我们要用对应的公式:
AliasAddr = 0x22000000+((A-0x20000000)*8+n)*4= 0x22000000+(A-0x20000000)32+n4
首先我们需要注意的一点是,A是SRAM位带区的某个比特的字节地址,注意是字节地址,我们都知道STM32中每个寄存器是32位的,所以每个寄存器站用4个字节,而0x20000000是总线地址,也就是基地址,寄存器地址是在这个基地址的基础上偏移的。如下图:
OK,了解这些就可以进行计算了。
要计算数据:0x20000000的第0位
A = 0x20000000
n = 0
公式:
AliasAddr = 0x22000000+((A-0x20000000)*8+n)*4= 0x22000000+(A-0x20000000)*32+n*4
第一步:带入数据
AliasAddr = 0x22000000+(0x20000000-0x20000000)*32+0*4
这里将一下计算规则:
加/减运算,只需要对应的位进行减就可以了
乘除运算:需要化为十进制进行计算。
结果:
AliasAddr = 0x22000000
对应上面的图片:
位带区 —> 等效的别名地址
0x20000000.0 --> 0x22000000.0
说明我们计算正确了,有人可能认为我们取得值太简单,那我们就在换一个再进行一次计算。
要计算数据:0x20000004的第2位
代入数据
AliasAddr = 0x22000000+(0x20000004-0x20000000)*32+2*4
这里计算就要借助计算器了,大家可以自行计算一下,注意在乘的时候一定要转化为十进制。计算结束后在转化为16进制
经过计算结果:
AliasAddr = 0x22000088
对照上表说明我们计算的只是正确的。这样我们就了解是如何进行转化的了,但是这就有新的问题了,32位的位带地址是如何给的位带区传递值的呐。
官方文档给出了解释:
在位带区中,每个比特都映射到别名地址区的一个字,这是只有一个 LSB有效的字。当一个别名地址被访问时,会先把该地址变换成位带地址。对于读操作,读取位带地址中的一个字,再把需要的位右移到LSB,并把LSB返回。对于写操作,把需要写的位左移至对应的位序号处,然后执行一个原子的“读一改一写”过程。
注释:LSB–最低有效位
这样位带操作就显得很简单了嘛,最后再看一下位带操作的实现
#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))
//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
#define GPIOF_IDR_Addr (GPIOF_BASE+8) //0x40011A08
#define GPIOG_IDR_Addr (GPIOG_BASE+8) //0x40011E08
//IO¿Ú²Ù×÷,Ö»¶Ôµ¥Ò»µÄIO¿Ú!
//È·±£nµÄֵСÓÚ16!
#define PAout(n) BIT_ADDR(GPIOA_ODR_Addr,n) //Êä³ö
#define PAin(n) BIT_ADDR(GPIOA_IDR_Addr,n) //ÊäÈë
#define PBout(n) BIT_ADDR(GPIOB_ODR_Addr,n) //Êä³ö
#define PBin(n) BIT_ADDR(GPIOB_IDR_Addr,n) //ÊäÈë
#define PCout(n) BIT_ADDR(GPIOC_ODR_Addr,n) //Êä³ö
#define PCin(n) BIT_ADDR(GPIOC_IDR_Addr,n) //ÊäÈë
#define PDout(n) BIT_ADDR(GPIOD_ODR_Addr,n) //Êä³ö
#define PDin(n) BIT_ADDR(GPIOD_IDR_Addr,n) //ÊäÈë
#define PEout(n) BIT_ADDR(GPIOE_ODR_Addr,n) //Êä³ö
#define PEin(n) BIT_ADDR(GPIOE_IDR_Addr,n) //ÊäÈë
#define PFout(n) BIT_ADDR(GPIOF_ODR_Addr,n) //Êä³ö
#define PFin(n) BIT_ADDR(GPIOF_IDR_Addr,n) //ÊäÈë
#define PGout(n) BIT_ADDR(GPIOG_ODR_Addr,n) //Êä³ö
#define PGin(n) BIT_ADDR(GPIOG_IDR_Addr,n) //ÊäÈë
这里开头三行是实现地址转化的,原理就是将位带区的某一位转化位位带别名区的一个32位的字节。大家可以分析一下,看看能不能算出来。
位带操作的优点
位带操作有什么优越性呢?最容易想到的就是通过GPIO的管脚来单独控制每盏LED的点亮与熄灭。另一方面,也对操作串行接口器件提供了很大的方便(典型如74HC165,CD4094)。总之位带操作对于硬件I/0密集型的底层程序最有用处了。
读取比特时传统方法与位带方法的比较
这就很直观的看出位带操作的相对而言更简便一些。
结语
位带操作在实际开发中可能只是用来 IO 口的输入输出还比较方便,其他操作在日常开发中也基本很少用。
上一篇:快速理解STM32位带操作原理和用途
下一篇:STM32位带操作详细介绍
推荐阅读最新更新时间:2024-11-13 10:35
推荐帖子
- Yocto linux
- 有人用过Yoctolinux吗?这种移植方便吗?YoctolinuxIntel的Edison就是用的Yoctolinux只是一种根文件系统,还好把
- hinii23 嵌入式系统
- LPC2131入门.pdf
- 分享~~分享LPC2131入门.pdf好,言简意骇赞个
- 小草~ 单片机
- STM32MPU全国线下培训正式启动,多个城市等您报名!
- 培训主题:基于Buildroot制作STM32MP13启动镜像时间:2024年3月21日9:30-17:30地点:苏州市工业园区星海书香世家酒店(金鸡湖店)桐星阁(具体地点可能会根据实际情况调整)时间:2024年3月26日9:30-17:30地点:郑州市中原区牡丹路与金梭路交叉口2F漫威咖啡(具体地点可能会根据实际情况调整)时间:2024年3月28日9:30-17:30地点:西安市高新区高新二
- eric_wang ST传感器与低功耗无线技术论坛
- 测量铜板电阻
- 测量铜板电阻应该怎么做啊。求助测量铜板电阻本帖最后由maychang于2015-4-2515:11编辑 说“铜板”,大概不是指圆形铜质上有花纹和文字作为钱币使用的物体吧?测量电阻,那就必须指定该物体上面两个位置,所谓电阻,是这两个位置之间的电阻。另外在已经确定的两个位置之外(内外的外)确定另两个位置以接入电流。测量仪器,使用开尔文电桥(双电桥)。如果指定用伏安法测量,那就要在该物体上确定好四个位置后,外面两个位置接入电流,内面两个位置测量电压。就是一个非常小的电阻,
- qqxiaoai 电子竞赛
- 通过MSP430F149的串口配置DS18B20的c语言程序
- 有谁知道写通过MSP430F149的串口配置DS18B20的c语言程序吗?通过MSP430F149的串口配置DS18B20的c语言程序串口配置?我刚跳过单独的串口和DS18B20/*************************************************程序功能:用DS18B20测量室温并在数码管上显示。-------------------------------------------------测试说明:观察显示温度数值。**********
- qiao2012 微控制器 MCU
- 希望厂家出厂就是这款
- 空调罩子的创意,不得不服 哈哈哈希望厂家出厂就是这款111111等要拿下来洗的时候,就会感觉好麻烦,怀疑自己为什么要买这些东西不好意思,接受不了,担心晚上要被吓到空调上面应该也有风口吧,每次擦上面都很费事哦,吼吼~~~这个颜色一定要选好,空调位置也得选好。不然感觉会做噩梦哈哈哈,想到以前的彩灯充电器啊啊啊,你们这么说我忽然感觉也有点害怕,但是明明是初音未来啊哈哈,我家娃最爱哈哈,看到这个图心情好一点了啊,不过不同的人喜欢的样式不太一样
- 吾妻思萌 创意市集
设计资源 培训 开发板 精华推荐
- 电子琴
- PCB特斯拉线圈初级次级线圈
- STEVAL-MET001V1,适配器评估板旨在促进 LPS22HB 产品系列中的 MEMS 器件的评估
- LTM8031,采用 15mm 9mm 模块封装的 EMI 认证降压转换器从 3.6VIN -36VIN 产生 1A、0.8VOUT 10V 输出
- 2寸X6叠桨穿越机机架
- NCV78825R1GEVK:带助推器的 NCV78825 套件
- LTM4631IV 4.5 至 15Vin、1V 和 1.2V、10A 输出降压稳压器的典型应用电路
- LT1617 的典型应用 - SOT-23 中的微功率反相 DC/DC 转换器
- L7809C 分体式稳压器的典型应用 (± 15 V - 1 A)
- ZXLD1356 具有内部开关的高精度 550mA、60V LED 驱动器的典型应用