STM32的位段操作
来源:互联网 发布:java项目名命名规则 编辑:程序博客网 时间:2024/06/06 02:31
开始STM32的学习!在学校的时候粗略学过STM32,但是很多外设没去涉猎。
STM32应该是现如今用得最火的单片机,作为一个嵌入式开发者还是很有必要去学习下。不论是硬件基础,还是软件角度来看标准库的设计技巧,都是值得研究研究。行吧,作为STM32学习记录的第一篇文章,说下我学习的参考资料:
刘平《深入浅出玩转51单片机》《Cortex-M3权威指南(中文).pdf》《STM32中文参考手册_V10.pdf》正点原子《STM32不完全手册_库函数版本_V3.1.pdf》秉火《零死角玩转STM32—F103指南者.pdf》
第一篇文章写位段操作。
位操作就是可以读/写单独的一个比特位,在STM32中没有像51单片机的sbit来实行位定义,但是它可以通过位带别名区来实现。
在STM32中有两个地方实现了位带操作,一个是SRAM区的最低1MB空间,另一个是外设区最低1MB空间。
0x2000 0000 ~ 0x200f ffff (SRAM区中的最低1MB)0x4000 0000 ~ 0x400f ffff (片上外设区中的最低1MB,已覆盖了全部的片上外设的寄存器)
这两个1MB的空间可以像普通RAM一样操作外(修改内容时用读-改-写),它们还有自己的位带别名区,位带别名区把这1MB的空间的每一位膨胀为一个32位的字。确切的说,这个字就是一个地址,当操作这个地址时,就可以达到操作这个位带区某个位的目的。
在位带区中,每个比特位都映射到别名地址区的一个地址,注意,这只是只有LSB有效的字(最低一位有效的字)。当一个别名地址被访问时,会把该地址转换为为位带操作。
对片上外设位带区的某个比特位,记它的所在字节的地址为A,位序号为n(0<=n<=7),则该比特位在别名区的地址为:
AliasAddr = 0x42000000 + ((A - 0x40000000) * 8 + n) * 4 = 0x42000000 + (A - 0x40000000) * 32 + n * 4
上式中,4表示一个字4个字节,8表示一个字节8个比特。
一开始,我对n(0<=n<=7)很不理解,既然n表示位序号,为什么不是0<=n<=31呢?其实是我忽略了“所在字节”四个字,也就是说在位带区中,不是以一个寄存器一个寄存器为分隔单元,而是以一个字节一个字节来分隔单元的。
(1) A - 0x40000000 = 当前字节偏离外设基地址的偏移字节数
(2) 偏移字节数 * 8 = 偏移了多少位
(3) 因为位带区每一位对应位带别名区的一个地址(4字节),而地址是以字节计算的,所以位带别名区对应偏移量最后一个的地址 = 偏移了多少位 * 4
(4) n * 4 = 偏移量后面的n位对应位带别名区的地址
计算如下位带区寄存器地址:0x400000000: 0x42000000 + ((0x40000000 - 0x40000000) * 8 + 0) * 4 = 0x42000000 + 0 = 420000001: 0x42000000 + ((0x40000000 - 0x40000000) * 8 + 1) * 4 = 0x42000000 + 0 = 420000042: 0x42000000 + ((0x40000000 - 0x40000000) * 8 + 2) * 4 = 0x42000000 + 0 = 420000083: 0x42000000 + ((0x40000000 - 0x40000000) * 8 + 3) * 4 = 0x42000000 + 0 = 4200000c4: 0x42000000 + ((0x40000000 - 0x40000000) * 8 + 4) * 4 = 0x42000000 + 0 = 420000105: 0x42000000 + ((0x40000000 - 0x40000000) * 8 + 5) * 4 = 0x42000000 + 0 = 420000146: 0x42000000 + ((0x40000000 - 0x40000000) * 8 + 6) * 4 = 0x42000000 + 0 = 420000187: 0x42000000 + ((0x40000000 - 0x40000000) * 8 + 7) * 4 = 0x42000000 + 0 = 4200001c位带区寄存器地址:0x400000080: 0x42000000 + ((0x40000001 - 0x40000000) * 8 + 0) * 4 = 0x42000000 + 0x8 = 420000201: 0x42000000 + ((0x40000001 - 0x40000000) * 8 + 1) * 4 = 0x42000000 + 0x104 = 420000242: 0x42000000 + ((0x40000001 - 0x40000000) * 8 + 2) * 4 = 0x42000000 + 0x108 = 420000283: 0x42000000 + ((0x40000001 - 0x40000000) * 8 + 3) * 4 = 0x42000000 + 0x10c = 4200002c4: 0x42000000 + ((0x40000001 - 0x40000000) * 8 + 4) * 4 = 0x42000000 + 0x110 = 420000305: 0x42000000 + ((0x40000001 - 0x40000000) * 8 + 5) * 4 = 0x42000000 + 0x114 = 420000346: 0x42000000 + ((0x40000001 - 0x40000000) * 8 + 6) * 4 = 0x42000000 + 0x118 = 420000387: 0x42000000 + ((0x40000001 - 0x40000000) * 8 + 7) * 4 = 0x42000000 + 0x11c = 4200003c
如下图:
同理,对于SRAM位带区的某个比特位,记它所在字节地址为A,位序号为n(0<=n<=7),则该比特位在别名区的地址为:
AliasAddr = 0x22000000 + ((A - 0x20000000) * 8 + n) * 4 = 0x22000000 + (A - 0x20000000) * 32 + n * 4
只是对位带基地址和位带别名区基地址做了改变即可。
再举个例子吧:
1) 往地址为0x40000001的位带区写入0x4466aadd (0b1000100011001101010101011011101)
2) 读取地址为42000020的位带别名区得1
读取地址为42000024的位带别名区得0
读取地址为42000028的位带别名区得1
3) 往地址为42000020的位带别名区写0, 往地址为42000024的位带别名区写1后,地址为0x40000001的位带区的数据为0b1000100011001101010101011011110,即0x4466AADE。
为了方便操作,我们可以把这两个公式合并成一个公式,把“位带地址 + 位序号”转换成别名地址。
//把位带区地址 + 位序号转换成位带别名去的宏#define BITBAND(addr, bit_num) ((addr & 0xf0000000) + 0x02000000 + ((addr & 0x00ffffff) << 5) + (bit_num << 2))
1) (addr & 0xf0000000) + 0x02000000: 区分SRAM还是外设,如果是外设,结果为4,再加0x2000000就等于0x4200000,0x42000000就是外设别名位带区。
如果是SRAM,结果为2,再加上0x2000000就等于0x22000000,0x22000000就是SRAM别名位带区。
2)addr & 0x00ffffff:屏蔽了最高2位,相当于减去0x20000000或者0x40000000。因为位带区的有效范围是1M,即0x100000,这样子就做到了低6位有效。
3) << 5:等价于乘以32
4) << 2:等价于乘以4
运用该计算代码,位带操作示例代码为:
//通过位带区地址和位带区的目标位,找到位带别名区的地址#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x02000000+((addr & 0x00FFFFFF)<<5)+(bitnum<<2))// 把一个地址强制转换成指针#define MEM_ADDR(addr) *((volatile unsigned long *)(addr))// 把位带别名区地址转换成指针#define BIT_ADDR(addr, bitnum) MEM_ADDR(BITBAND(addr, bitnum))//定义GPIOA的ODR寄存器#define GPIOA_ODR_Addr (GPIOA_BASE + 12)//设置GPIOA的引脚5为1,这是位操作BIT_ADDR(GPIOA_ODR_Addr,5) = 1;
位段操作,使得1MB的SRAM就有32MB的对应别名区空间,1位膨胀到32位,但效率更高,(在中断的时候)具有更安全的作用。
- STM32的位段操作
- STM32的位段操作
- STM32的位段操作基础
- stm32的位操作
- STM32 位段
- STM32的位操作的方法
- STM32的位操作的方法
- STM32的位操作的方法
- STM32 8位IO的操作
- STM32位操作
- stm32 位操作
- 位段操作
- 位段操作问题
- 位段操作
- STM32位段和别名区基础知识
- C/C++位操作简介 位段
- STM32 的init段设计
- 位段的声明
- LGTB与序列 状压dp
- d3画时钟
- ie6 半字符攻击
- 安卓学习
- vxworks 421 service not available 解决方法
- STM32的位段操作
- 嵌入式
- 使用sublime text3 连接sftp/ftp(远程服务器)
- 查找——平均查找长度
- java 将list中name,对应的id放入map
- ViewPage
- GTX 1080Ti + cuda8.0 + cuDNN6.0 安装及测试
- 简要分析Android中的Intent,Bundle,Parcel中的数据传递
- Javascript 函数的几种写法