你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

查看: 3092|回复: 1

【JESSE】STM32初学(寄存器版)——位段操作

[复制链接]

10

主题

170

回帖

0

蝴蝶豆

金牌会员

最后登录
2020-10-7
发表于 2017-8-23 22:12:18 | 显示全部楼层 |阅读模式
接上篇:【JESSE】STM32初学(寄存器版)——位段操作

前几篇连载中,我们对IO口的读写都是直接操作相应的寄存器位,不免会显得麻烦,有没有简单一点的方法操控它呢。有,我们可以使用位段操作。
现在诸多开发板的例程里都会加入位段操作,但是大部分都是展示了一个实现过程。就算正点原子的教程中也是草草带过(我最早是在正点原子的程序中接触到位段),并没深入讲解位段究竟是个什么样的过程。但是,位段作为内核机制,我觉得还是有必要好好讲讲的。
我将原子的sys.h文件copy到了工程目录下,为了表示对原作者的尊重,我保留了原子的标识(并非打广告),只是将一些用不到的东西以注释的形式进行屏蔽,并且添加了一些原本没有的东西。
3.PNG
原子在STM32F4开发指南中也对其中内容进行了简单介绍
q1.PNG

q2.PNG
中间截掉的部分便是上面的代码部分。
这些文档虽然都展示了位段操作的过程,但是对其中原理还是不懂。
这种时候我们就要借助一些更权威的工具书了,在《ARM Cortex-M3与Cortex-M4权威指南》第6章第7小节对位段操作进行了比较详细的介绍。考虑到可能有很多同学并没有这本书,并且我讲的也没书上说的清楚,这里我要大量贴图了,勿怪
q3.PNG
q4.PNG
q5.PNG
q6.PNG

看到这,什么是位段呢。位段就是Cotex-M3/M4为了方便操作,以一个字大小的寄存器代替了一个位。

STM32中对读写的操作都是以字或半字(stm32中一个字是四个字节)为单位的,如果想要对一个位进行读写,就需要像前面操作的一样,进行移位。
为了简化操作,将位进行膨胀,膨胀到字的层面,不就可以直接进行读写了吗?这就避免了移位操作,但是地址膨胀带来的是地址空间上的占用,所以这种膨胀非常有限,仅仅在SRAM和片上外设区有各有1M的位段区和与之对应的32M别名区。
q7.PNG
现在我们知道,要想操作位段区的某一位,就要去找对应的别名区地址,那别名区的地址怎么算呢,文中有公式,但是如何去理解呢。在这我谈谈我的理解。
位段区和别名区都是连续的地址空间,都有各自的开始地址,这个开始地址肯定是要先去掉的,膨胀的是空间,跟它的起始地址是无关的。将一个位膨胀为一个字,扩大了32倍,这就可以将位段区的每一位和别名区的每个字一一对应。
假如我们要计算字节A中第B位在别名区的地址,那就应该A-位段区起始地址,再将空间膨胀,即(A-起始地址)*32,这就算到了字节A膨胀后在别名区的地址偏移,这时候一个位对应的是一个字(4字节),所以B相对于A的地址偏移应该是B*4,即算得B在别名区的地址偏移为(A-起始地址)*32+B*4;这时候再加上别名区的起始地址便是B在别名区的地址了。
这和文档或是程序中的算法是一致的,我们也可以算算看,
((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2))
((addr & 0xF0000000)这是取得了位段区的起始地址,
((addr & 0xF0000000)+0x2000000这便是取得别名区的起始地址(位段区与相应的别名区的高4位地址是一致的,只是别名区起始地址相对位段区起始地址偏移了0x2000000)。
((addr &0xFFFFF)<<5)这一步便是将空间进行膨胀,因为位段区的大小是1M,所以位段区的地址范围便是0x00000~0xFFFFF,(addr &0xFFFFF)这是获得字节A(按上面的例子加入)的偏移地址,左移了5位,就相当于乘了32倍;
(bitnum<<2)这是获取位B在别名区相对于A的偏移,左移2位,便是相当于乘了4倍。
不知道我讲清楚了没有,也不知道讲的对不对。

讲了实现原理,我们就可以来看看程序效果
  1. void led_toggle(uint8_t led_index)
  2. {
  3.     if((led_index&LED1)==LED1)   GPIOG->ODR ^= 0x01<<6;        
  4.     if((led_index&LED2)==LED2)   GPIOD->ODR ^= 0x01<<4;
  5.     if((led_index&LED3)==LED3)     GPIOD->ODR ^= 0x01<<5;
  6.     if((led_index&LED4)==LED4)     GPIOK->ODR ^= 0x01<<3;
  7. }
复制代码
这是直接操作相应位的方式

  1. void sys_led_toggle(uint8_t led_index)
  2. {
  3.     if((led_index&LED1)==LED1)    PLED1 = !PLED1;
  4.     if((led_index&LED2)==LED2)    PLED2 = !PLED2;
  5.     if((led_index&LED3)==LED3)    PLED3 = !PLED3;
  6.     if((led_index&LED4)==LED4)    PLED4 = !PLED4;
  7. }
复制代码
这是应用了位段的方式,直接对相应寄存器进行赋值即可。

也可用位段的方式对当前状态的读取,但是这里需要注意的是,将一个位膨胀成一个字之后,它所能表示的就不单单只是‘0’和‘1’(尽管它的作用还是用于表示‘0’和‘1’),所以如果想通过读取别名区的寄存器值为‘1’还是不为‘1’来判断相应位的状态,这种做法是非常危险的,别名区里的寄存器非常可能并不是存储的‘1’,而是别的非零数,所以这里要用判‘0’的方式,我就见过别人掉进这个坑里,逻辑上没有任何问题,但是程序死活出不来。

最后上传个工程和PDF版的Cortex-M3/M4权威指南(光pdf就140M

下一篇:【JESSE】STM32初学(寄存器版)——USART


project.rar

下载

188.39 KB, 下载次数: 15, 下载积分: ST金币 -1

清华开发者书库 ARM Cortex-M3与Cortex-M4权威指南 第3版(英)姚文祥著_北京:清华.rar

下载

15 MB, 下载次数: 98, 下载积分: ST金币 -1

清华开发者书库 ARM Cortex-M3与Cortex-M4权威指南 第3版(英)姚文祥著_北京:清华.rar

下载

15 MB, 下载次数: 75, 下载积分: ST金币 -1

清华开发者书库 ARM Cortex-M3与Cortex-M4权威指南 第3版(英)姚文祥著_北京:清华.rar

下载

15 MB, 下载次数: 96, 下载积分: ST金币 -1

清华开发者书库 ARM Cortex-M3与Cortex-M4权威指南 第3版(英)姚文祥著_北京:清华.rar

下载

15 MB, 下载次数: 100, 下载积分: ST金币 -1

清华开发者书库 ARM Cortex-M3与Cortex-M4权威指南 第3版(英)姚文祥著_北京:清华.rar

下载

15 MB, 下载次数: 100, 下载积分: ST金币 -1

清华开发者书库 ARM Cortex-M3与Cortex-M4权威指南 第3版(英)姚文祥著_北京:清华.rar

下载

15 MB, 下载次数: 76, 下载积分: ST金币 -1

清华开发者书库 ARM Cortex-M3与Cortex-M4权威指南 第3版(英)姚文祥著_北京:清华.rar

下载

15 MB, 下载次数: 98, 下载积分: ST金币 -1

清华开发者书库 ARM Cortex-M3与Cortex-M4权威指南 第3版(英)姚文祥著_北京:清华.rar

下载

5.68 MB, 下载次数: 156, 下载积分: ST金币 -1

<
回复

使用道具 举报

0

主题

43

回帖

0

蝴蝶豆

初级会员

最后登录
2018-10-5
发表于 2018-10-3 23:01:24 | 显示全部楼层
感谢楼主的无私分享!
回复 支持 反对

使用道具 举报

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版