正在准备做毕业设计,配置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% 了,多数情况下,大家见到的代码,应该是以下这个样子,一共分为三步,

 #define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2))       

2 #define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr))                                                                       

3 #define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum))     

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

 # define ADDR 0x00000001

 *(int *)ADDR = ;

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

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

 # 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. Mac PHPStorm清除SVN配置缓存

  2. php连接数据库并创建数据库表

    先开启本地服务器 1.输入localhost/phpmyadmin 查看本地数据库是否安装 2.在本地服务器上建一个文件夹,里面建一个php文件(如test.php) 3.连接数据库 4.在浏览器上输 ...

  3. yum安装错误:CRITICAL:yum.cli:Config Error: Error accessing file for config file:///home/linux/+

    上网搜了一下然后自己总结一份 : 出现原因:yum可能没有,或者损坏 解决: 第一步:下载   wget  http://yum.baseurl.org/download/3.2/yum-3.2.28 ...

  4. IDEA + Spring boot 单元测试

    1. 创建测试类 打开IDEA,在任意类名,任意接口名上,按ctrl+shift+t选择Create New Test image 然后根据提示操作(默认即可),点击确认,就在项目的/test/jav ...

  5. 改变this指向

    fn.call(obj,参数,参数): call(函数执行过程中this指向,后面的参数就是原函数的参数列表) : 函数下的一个内置方法,当我们申明一个函数的时候,这个函数下就会有一个默认的方法,ca ...

  6. [经典SQL语句]根据父级ID查找所有子级ID,并将所有ID用逗号隔开返回

    树形表结构: id parentID isDel 1 0 0 2 1 0 3 1 1 4 2 0 5 2 0 一)根据父级ID查找所有子级ID,并将所有ID用逗号隔开返回 ID=,需要返回的结果(条件 ...

  7. python关于MySQL的API -- pymysql模块

    1.模块安装 pip install pymysql 2.执行sql语句 import pymysql #添加数据 conn = pymysql.connect(host='127.0.0.1', p ...

  8. javeweb_学生信息添加系统

    在text.jsp中画出界面,以及设置提交选项的限制 <%@ page language="java" contentType="text/html; charse ...

  9. Shell one

    1.shell的运算符包括:算术运算符.关系运算符.布尔运算符.字符串运算符.文件测试运算符 1.1原生bash不支持简单的数学运算,但是可以通过其他命令来实现,例如 awk 和 expr,expr ...

  10. 为什么TCP建立连接协议是三次握手,而关闭连接却是四次握手呢?

    看到了一道面试题:"为什么TCP建立连接协议是三次握手,而关闭连接却是四次握手呢?为什么不能用两次握手进行连接?",想想最近也到金三银四了,所以就查阅了相关资料,整理出来了这篇文章 ...