1. 什么是位带操作?

学习 51 单片机的时候就使用过位操作,通过关键字 sbit 对单片机IO口进行位定义。但STM32没有这样的关键字,于是便要通过访问位带别名区的方式来实现。即:将每一位膨胀成一个32位字,因此SRAM的1MB位带区就膨胀为32MB的位带别名区,通过访问位带别名区来实现访问位带中每一位的目的。 比如 BSRR 寄存器有 32 个位,那么可以映射到 32 个地址上(变成32个字),当我们去访问这 32 个地址字就达到了访问 32 个比特的目的。

由图,SRAM最低1MB区域地址范围0X2000 0000-0X200F FFFF,它是SRAM的位带区。
而片内外设最低1MB区域地址范围是0X4000 0000-0X400F FFFF(这个地址范围包括APB1、APB2、AHB总线上所有外设寄存器)。
SRAM区还有32MB空间地址范围是0X2200 0000-0X23FF FFFF,它是SRAM中1MB位带区膨胀后的位带别名区。
片内外设区也还有32MB地址范围是0X4200 0000-0X43FF FFFF,它是片内外设中1MB位带区膨胀后的位带别名区。
通常我们使用位带操作都是在外设区,在外设区中应用比较多的也就是GPIO 外设,在SRAM区内很少使用位操作。

.
.
.

2. 位带区与位带别名区地址转换

1)外设位带别名区地址

对于片上外设位带区的某个比特, 若它所在的字节地址为 A,位序号为 n (0~8), 则该比特在别名区地址:
AliasAddr = 0x4200 0000 + [ (A-0x4000 0000) * 8 + n ] * 4
0x42000000:外设位带别名区起始地址
0x40000000:外设位带区起始地址
A-0x40000000:该比特前面有多少个字节
(A-0x40000000) * 8:该比特所在字节的第0位在外设位带区的位序号
(A-0x40000000) * 8 + n:该比特在外设位带区的位序号
一个位膨胀后是4字节,所以地址*4(地址的单位是字节)

2)SRAM位带别名区地址

对于SRAM位带区的某个比特, 若它所在的字节地址为 A,位序号为 n (0~8), 则该比特在别名区地址:
AliasAddr = 0x2200 0000 + [ (A-0x2000 0000) * 8 + n ] * 4
0x22000000:SRAM位带别名区起始地址
0x20000000:SRAM位带区起始地址
A-0x20000000:该比特前面有多少个字节
(A-0x20000000) * 8:该比特所在字节的第0位在SRAM位带区的位序号
(A-0x20000000) * 8 + n:该比特在SRAM位带区的位序号
一个位膨胀后是4字节,所以地址*4(地址的单位是字节)

为了操作方便,我们将这两个公式合并,通过一个宏来定义,并把位带地址和位序号作为这个宏的参数。公式如下:
AliasAddr = 0x□2000000 + (A-0x□0000000) * 32 + n * 4

//求位带别名区地址
#define BITBAND(addr, bitnum)   ((addr&0xF0000000)+0x2000000 + ((addr&0xFFFFF)<<5) + (bitnum<<2))

FFFFF(H)=1048575(D) > 1000000(位带区共1M字节),*32即左移5位,*4即左移2位。
(addr&0xF0000000)+0x2000000:外设(SRAM)位带别名区的首地址
(addr&0xFFFFF):外设(SRAM)位带区最高地址为0x400FFFFF(0x200FFFFF),保留低5位相当于减去0x40000000(0x20000000)。
.
.
.

3. 代码实现

最后通过指针形式来操作这些位带别名区地址, 实现位带区对应位的操作。 代码如下:

/*位带操作,实现类似51的GPIO控制功能*/
#define BITBAND(addr, bitnum)   ((addr&0xF0000000)+0x2000000+((addr&0xFFFFF)<<5)+(bitnum<<2))
//求取位带别名区地址后,把地址强制转换为unsigned long型指针
#define MEM_ADDR(addr)          *((volatile unsigned long *)(addr))
//把位带别名区地址转换为指针,获取地址内数据从而操作位带区对应位
#define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum))/*IO口地址映射*/
#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    输入
#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    输出/*IO口操作,只对单一IO口*/
#define PAin(n)     BIT_ADDR(GPIOA_IDR_Addr,n)  //输入
#define PBin(n)     BIT_ADDR(GPIOB_IDR_Addr,n)  //输入
#define PCin(n)     BIT_ADDR(GPIOC_IDR_Addr,n)  //输入
#define PDin(n)     BIT_ADDR(GPIOD_IDR_Addr,n)  //输入
#define PEin(n)     BIT_ADDR(GPIOE_IDR_Addr,n)  //输入
#define PFin(n)     BIT_ADDR(GPIOF_IDR_Addr,n)  //输入
#define PGin(n)     BIT_ADDR(GPIOG_IDR_Addr,n)  //输入
#define PAout(n)    BIT_ADDR(GPIOA_ODR_Addr,n)  //输出
#define PBout(n)    BIT_ADDR(GPIOB_ODR_Addr,n)  //输出
#define PCout(n)    BIT_ADDR(GPIOC_ODR_Addr,n)  //输出
#define PDout(n)    BIT_ADDR(GPIOD_ODR_Addr,n)  //输出
#define PEout(n)    BIT_ADDR(GPIOE_ODR_Addr,n)  //输出
#define PFout(n)    BIT_ADDR(GPIOF_ODR_Addr,n)  //输出
#define PGout(n)    BIT_ADDR(GPIOG_ODR_Addr,n)  //输出

volatile关键字,volatile提醒编译器它后面所定义的变量随时可能改变, 因此编译后的程序每次需要存储或读取这个变量的时候,都会直接从变量地址中读取数据。如果没有volatile关键字,则编译器可能优化读取和存储,可能暂时使用寄存器中的值, 如果这个变量由别的程序更新了的话,将出现不一致的现象。

----------------------------------------------------------------------------------------------------->以上部分内容援引自《STM32F10xxx参考手册》

STM32的位带操作相关推荐

  1. 我对STM32所用位带操作宏的超详细剖析、优势分析及应用推广探索研究(持续更新,欢迎讨论交流)

    在原子例程的sys.h中,使用宏定义建立了位带操作的基础, 使得操作IO端口可以像51一样实现位操作. 其实深入了解了位带操作的原理,几乎就可以实现对STM32所有外设寄存器的访问, 极端情况下,什么 ...

  2. STM32 的 “位带”操作Bit-banding--学习笔记

    利用2个32MB大小的"虚拟"内存空间实现对2个1MB大小的物理内存空间进行"位"的置位和清除操作. 这样就可以有效地对设备寄存器和位于SRAM中的数据变量进行 ...

  3. STM32笔记 GPIO介绍及IO口操作 STM32F0 利用C语言位域实现仿位带操作

    文章目录 GPIO简介 工作方式 相关寄存器介绍 IO 操作步骤 IO口三种操作细解 附录:C语言相关 偏移地址与绝对地址 GPIO简介 GPIO:每个连接到I/O总线上的设备都有自己的I/O地址集, ...

  4. Cortex‐M3和Cortex‐M0是否都能位带操作

    最近在进行stm32l011f4的编程,想到stm32有位带操作,便想试一试,但是事与愿违,先贴下位带操作代码 Cortex‐M0的位带操作代码 //IO输出方向设置 #define SDA_IN() ...

  5. STM32 进阶教程 8 - 位带操作

    前言 有过51单片机开发经历的朋友应该都对51的IO口或一些特殊寄存器可以直接按位操作的方式不陌生吧,那么在stm32中有没有类似的操作呢,答案是肯定的,本节将给大家介绍如何在STM32中实现位带操作 ...

  6. STM32(五)------GPIO位带操作

    GPIO位带操作 介绍 位带简介 外设位带区 SRAM位带区 位带区和位带别名区地址转换 GPIO 位带操作 代码解析 GPIO 寄存器映射 GPIO位操作 主函数 介绍 位带简介 位操作就是可以单独 ...

  7. 【STM32】标准库与HAL库对照学习教程六--位带操作

    [STM32]标准库与HAL库对照学习教程六--位带操作 一.前言 二.准备工作 三.位带介绍 1.位带操作 2.STM32位带及位带别名区域 四.位带区与位带别名区地址转换 五.GPIO的位带操作 ...

  8. STM32:内存单元,一个单元一个字节--------位带操作

    学到了位带操作,发现不懂0~0x10 0000 地址内如何保存1MB的数据,分析了一会明白了. 起初我以为STM32内存单元里是每个单元都是32位的,其实都是8位的,也就是一个字节一个单元. 0x00 ...

  9. STM32位带操作实现过程解析

    编辑这篇文档时候,听说相关的解析过程在<Cortex-M3权威指南>里有详细讲解. 前几日被一个跑马灯语句勾引 LED1=!LED1; 于是深入探究一下这句话的实现过程. #include ...

最新文章

  1. angularjs源码笔记(3)--injector
  2. python读取raw数据文件_在python下读取并展示raw格式的图片实例
  3. 使用Java代码连接SAP ABAP Netweaver服务器
  4. [SpringBoot2]Thymeleaf
  5. pks系统如何添加服务器,pks服务器的上电步骤.pdf
  6. 【XML】XML树形结构
  7. php函数查询sprintf,PHPsprintf函数用例解析
  8. ESP32 ESP-IDF开发环境搭建,Windows下基于ESP-IDF | Cmake | VScode插件的 ESP32 开发环境搭建
  9. 缓冲文件系统和非缓冲文件系统
  10. 【二分图】【最大匹配】【匈牙利算法】bzoj1191 [HNOI2006]超级英雄Hero
  11. mysql 最小值对应的其他属性_查询最小值对应的非group by字段
  12. 64位oracle plsql developer 下载地址,plsql developer
  13. 有什么推荐的软件工程本科的毕业设计题目嘛?
  14. Spring子项目了解
  15. CentOS7 网络安装版本 设置基础软件仓库出错
  16. 牛客练习赛53 E.老瞎眼 pk 小鲜肉(离线+BIT单点修改)
  17. 2019最新升级【超能版】 vbox硬件级虚拟机系统 去虚拟化去vm标识 支持批量启动 批量克隆 CPA网赚挂机电商 virtualbox
  18. 海信IP202H-晨星9385芯片-9.0-免拆卡刷固件包
  19. [UOJ198][CTSC2016]时空旅行
  20. 赛门铁克软件恢复服务器系统,网络版赛门铁克杀软服务器重装恢复

热门文章

  1. jquerymobile iscrollview
  2. ROS-PCL读取pcd点云数据并在rviz中进行显示
  3. LVM以及挂载一块新硬盘
  4. 考研复习(2)链表操作
  5. html二维坐标系转换,旋转坐标系 转换工具
  6. 气门组的结构组成有哪些_挖机破碎钳子,液压粉碎钳都有哪些结构组成,你知道吗...
  7. GDAL不支持创建PCIDSK的面状矢量格式
  8. SQL那些事儿(十一)--ODBC,OLE-DB,ADO.NET区别
  9. FlashDevelop打包IOS应用教程
  10. [推荐]HLSL编程实现PhotoShop滤镜效果