正在准备做毕业设计,配置LED_Config()的时候,又看到了位带操作的宏定义,我又嘀咕了,什么是位带操作,一年前在使用位带操作的时候,就查阅过好多资料,Core-M3也看过,但是对于博主这种“低能儿”来说,你不把它说的白一点,就是感觉理解的不够透彻,于是今天又一次,查阅了各种手册,也算是基本弄懂了,鉴于博主的个人特点,所以本人的介绍也会十分浅显易懂,希望能帮到各位!

首先,抛砖引玉,来两个问题:

  1)为什么STM32里面会有位带操作?

  2)STM32里面的位带操作是什么意思?

我也不想去弄什么官方定义了,来两个例子,相信各位心里即使不能给出一个确切的定义,也不会再去纠结这个问题,

答:

  1)51单片机相信各位都用过,假设P1.1的IO口上挂了一个LED,那么你单独对LED的操作就是P1.1 = 0或P1.1 = 1,注意,是你可以单独的对P1端的第一个IO口进行操作,然而STM32是不允许这样做的,那么为了像51单片机一样能够单独的对某个端的某一个IO单独操作,就引入了位带操作这样的概念,简而言之,言而总之,就是为了去单独操作32里面PA端的第1个IO口,所以才有了位带这样的操作机制。

  2)打个形象的比方,以某个村,就张村把,该村有3户人家分别为A,B,C,我想给张村的A送礼,但是明文规定,不能给具体的个人送礼,但是可以给村委会送礼,那我该怎么办呢,OK,即日起,A不叫A了,改名叫做村委会1,B和C分别改叫做村委会2和村委会3,哦了,可以给A送礼了,虽然我送礼的对象是村委会1,听起来好像比个人级别高一点,但是最终收到礼物的还是个人A。同理,STM32不允许对某个端的某一个IO口进行操作,也就是PA.1 = 0或者PA.1 = 1这样的操作是非法的,好了,那我就给PA.1起个别名,将原来PA.1的地址扩展成一个32位的字地址,对32位的地址进行操作,这个是STM32允许的,必需可以的,STM32对所有的寄存器配置,都是对某个32位地址的操作,因此说白了,就是某个IO端口进行操作,这就是位带操作。

  大白话说完,还是得回归官方介绍,不过这时候你在看,应该会好很多了。我们一步一步来,首先你应该知道的

  位带区,和位带别名区,位带区,就是就是你想单独操作的IO的区域,也就是PA,PB……等这一堆IO口的内存所在区,而位带别名区,就是你给每一位重新起了个名字的那一片地址区域。可以看下表,M3内核存储器映射表,你能看到1M内存的BitBand区,还有与之对应的32M内存的BitBand别名区,因为你将每一位膨胀成为了一个32位的地址,所以相应的别名区的内存也会是位带区的32倍。

  OK,现在我们应该能够知道,你想进行位带操作去操作某个IO口的某一位,那么在STM32的环境下,你应该去找该位对应的别名区的地址,找到了这个地址,对这个地址进行操作,那么实际上也就是对该位进行操作了,接下来,我们要去找位所对应的地址了。

  官方给出了相应的计算公式,我们以外设部分为例,毕竟用的多的还是外设部分的端口,具体到PA.1把

  AliasAddr= 0x42000000+((A‐0x40000000)*8+n)*4 =0x42000000+ (A‐0x40000000)*32 + n*4

  AliasAddr是别名区的地址,A是GPIOA->ODR的地址,n是该端口的上的某一位,这里就是1,通过这个公式你可以找到对应的别名区的地址,接下来就是对这个地址进行操作了,你给他写1,该位输出1,写0,就输出0。

  在这里我想解释以下,为什么这个公式是这个样子的,因为我也思考了很久!借助于下面这个图:

  

  0x42000000是位带别名区域的起始地址,A是输出数据寄存器GPIOA->ODR的地址,A的地址先减去位带区基地址,得到的是相对于位带区基地址的偏移地址,那么膨胀之后还是一个偏移地址,是相对于位带别名区基地址的偏移量,加上位带别名区域基地址,就得到了其对应的别名区地址,这是总的原理,

  ((A‐0x40000000)*8+n)*4 =0x42000000+ (A‐0x40000000)*32 + n*4  

  这部分是膨胀公式,乘8是先把单元内的每一位上升到字节的高度上,这样,你想设置第二位,就直接在原来的基地址上+2就可以了,确定完是第几位,再乘4,就是把位再上升到字的高度上,也就是每一位对应一个32位的字,这样最终的地址转换就完成,关键还是要注意两点,一是,两部分地址的互相转换,主要是每一部分的基地址。二就是位上升的32位地址这样的一个方法概念。

  说到这里,基本已经介绍了80% 了,多数情况下,大家见到的代码,应该是以下这个样子,一共分为三步,

  1. #define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2))
  2.  
  3. 2 #define MEM_ADDR(addr) *((volatile unsigned long *)(addr))
  4.  
  5. 3 #define BIT_ADDR(addr, bitnum) MEM_ADDR(BITBAND(addr, bitnum))

   第一步,就是我们上面分析的,得到位带别名区域的32位地址,至于第二步嘛,其实就是一个转换,给各位举个例子,如下,我想直接访问0x00000001这个地址,并且给这个地址写1,该怎么做呢,

  1. # define ADDR 0x00000001
  2.  
  3. *(int *)ADDR = ;

  第二步的操作就是将第一步得到的32位地址,给转换成一个指针变量,并且操作这个地址里的值,唯一的区别,就是由于安全的考虑,多加了一个volatile 这样的关键字,但是他不会对我们产生其他的影响,而第三步,就是将前两部,结合在一起,根据传入的addr和bit计算得到32位的地址,然后强制类型转换,使得我们可以去操作这个地址里的值,OK,大功告成,整个的思路基本就是这样,应该不是很难把,至此相信各位已经能够理解什么是位带,以及该怎么去操作位带。

  接下来,再写一种常用的位带操作的用法。由于上面的传入的addr是整个区域的基地址,因此,当你想去使用不同GPIO口的时候,采用上面的写法,你将麻烦需要多写好几个步骤,我自己常用的一种写法是下面这个样子的。

  1.  # define BITBAND_REG(Reg,Bit) (*((uint32_t volatile*)(0x42000000u + (((uint32_t)&(Reg) - (uint32_t)0x40000000u)<<) + (((uint32_t)(Bit))<<))))

  # define LED0 BITBAND_REG(GPIOF->ODR,9)
  # define LED1 BITBAND_REG(GPIOF->ODR,10)

  短短的三行代码,就已经解决了所有问题,输出控制小灯泡,即使再换用其他的端口,改动括号内的内容即可。Reg是操作部分的基地址,Bit就是第几位了。

  原理就是,我已经知道,GPIO部分的基地址是0x42000000u ,那么我每次传入具体的GPIOx->ODR寄存器,在定义中,对其取地址,这样可以灵活访问各个不用IO输出,相当于把我们的操作给具体化了,<<5,<<2这两个就是乘32,乘4这样的概念,只不过位操作,会更快一点。

【ARM】---STM32位带操作总结---浅显易懂的更多相关文章

  1. STM32位带操作总结---浅显易懂

    正在准备做毕业设计,配置LED_Config()的时候,又看到了位带操作的宏定义,我又嘀咕了,什么是位带操作,一年前在使用位带操作的时候,就查阅过好多资料,Core-M3也看过,但是对于博主这种“低能 ...

  2. STM32位带操作

    STM32的位带操作是基于cortex内核自带的,而不是st公司独创.基本的思路就是用一个32位的地址空间访问一个bit,因为stm32只支持32位数据的读取,不像51单片机一样,是可以单独对一位操作 ...

  3. 关于STM32位带操作随笔

    以前在学习STM32时候关注过STM32的位带操作,那时候只是知道位带是啥,用来干嘛用,说句心里话,并没有深入去学习,知其然而不知其所以然.但一直在心中存在疑惑,故今日便仔细看了一下,写下心得供日后参 ...

  4. STM32—位带操作

    STM32中的位带操作: 名字为位带操作,实际上是对位的操作,位操作就是可以单独的对一个比特位读和写,这个在 51 单片机中非常常见. 51 单片机中通过关键字 sbit 来实现位定义, STM32 ...

  5. (stm32学习总结)—GPIO位带操作

    本章参考资料:<STM32F10X-中文参考手册>存储器和总线构架章节.GPIO 章节,<CM3 权威指南 CnR2>存储器系统章节. 位带简介 位操作就是可以单独的对一个比特 ...

  6. STM32之GPIO端口位带操作

    #ifndef __SYS_H #define __SYS_H #include "stm32f10x.h" //位带操作 //把“位带地址+位序号”转换别名地址宏 #define ...

  7. STM32F030系列实现仿位带操作

    1.闲言 最近开发的时候,用到了STM32F030F4P6型号的单片机,它只有20个引脚,价格非常便宜,但是功能齐全:定时器.外部中断.串口.IIC.SPI.DMA和WWDG等等,应用尽有,非常适合用 ...

  8. 玩转X-CTR100 l STM32F4 l 基础例程printf、LED、蜂鸣器、拨码开关、位带操作

    我造轮子,你造车,创客一起造起来!塔克创新资讯[塔克社区 www.xtark.cn ][塔克博客 www.cnblogs.com/xtark/ ]      本文介绍X-CTR100控制器基础板载资源 ...

  9. 玩转X-CTR100 | STM32F4 l GPIO位带操作

    更多塔克创新资讯欢迎登陆[塔克社区 www.xtark.cn ][塔克博客 www.cnblogs.com/xtark/ ]       STM32F4位带概念,及位带的GPIO操作实践应用. 原理介 ...

随机推荐

  1. Python 3里,reduce()函数已经被从全局名字空间里移除了,它现在被放置在fucntools模块里

    reduce函数:在Python 3里,reduce()函数已经被从全局名字空间里移除了,它现在被放置在fucntools模块里 用的话要 先引入:>>> from functool ...

  2. Vmware虚拟机用户密码忘记了怎么办?

    Vmware虚拟机用户密码忘记了怎么办?   虚拟机Linux上用户密码忘记了怎么办? 今天准备再学习一下linux操作系统,由于之前已经安装过vaware和linux(redhat),所以这次认为不 ...

  3. linux ioctl 方法

    ioctl, 我们在第 1 章展示给你如何使用, 是一个系统调用, 作用于一个文件描述符; 它 接收一个确定要进行的命令的数字和(可选地)另一个参数, 常常是一个指针. 作为一个使 用 /proc 文 ...

  4. C# AutoResetEvent 理解

    .. AutoResetEvent在内存中保持着一个bool值值为False,则使线程阻塞:值为True,使线程退出阻塞: 创建AutoResetEvent对象的实例,在函数构造中传递默认的bool值 ...

  5. vue中的computed和watch区别

    在vue.js官方文档中看到computed和watch获取全名的一个例子: var var vm = new Vue({ el: '#demo', data: { firstName: 'Foo', ...

  6. Nodejs之使用express框架搭建WEB应用

      首先创建一个index.js,在里面引入相关的中间件,如果没有这些中间件,则需要在nodejs里进入index.js所在的文件夹安装这些模块,安装命令:npm install express ex ...

  7. 新书《iOS编程(第6版)》抢鲜试读

    我最近翻译了Big Nerd Ranch的<iOS编程(第6版)>.我用了大半年时间,尽可能做到通顺易懂.不足之处请大家多多指正.感谢辛苦审校的丁道骏同学. 这本书得过Jolt大奖,原书在 ...

  8. Struts2 数据标签

    Struts 2 的数据标签主要用于操作页面上显示的数据.下面列出的是重要的数据标签: action标签: 此标记使开发人员能够直接从JSP页面调用动作指定动作的名称和一个可选的命名空间.标签的主体内 ...

  9. git之本地篇(用tortoisegit操作)

    下载: git:https://git-scm.com/downloads tortoisegit(小乌龟):https://tortoisegit.org/ ortoisegit中文语言包 v2.9 ...

  10. 深入浅出 Viewport 设计原理

    Viewport 是 HTML5 针对移动端开发新增的一个 meta 属性, 它的作用是为同一网页在不同设备的呈现,提供响应式解决方案.这篇文章尝试通过循序渐进的方式,逐层探索 Viewport 的设 ...