51单片机估计都用过,可以单独对P1口的第一个IO进行操作,然而STM32是不允许这样做的,为了像51单片机一样能够单独的对某一个IO单独操作,就引入了位带操作这样的概念,简而言之,言而总之,就是为了单独操作32里面的某个端口,所以才有了位带这样的操作机制。

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

官方给出的相应的计算公式,以外设为例

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  

  每一位对应一个32位的字,这样最终的地址转换就完成,关键还是要注意两点,一是,两部分地址的互相转换,主要是每一部分的基地址。二就是位上升的32位地址这样的一个方法概念。
//位带操作,实现51类似的GPIO控制功能
//具体实现思想,参考《CM3权威指南》第五章(87页~92页)。M3同M4类似,只是寄存器地址变了

//IO口操作宏定义
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr
&0xFFFFF)<<5)+(bitnum<<2)) 
#define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr)) 
#define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum)) 
//IO口地址映射
#define GPIOA_ODR_Addr    (GPIOA_BASE+20) //0x40020014
#define GPIOB_ODR_Addr    (GPIOB_BASE+20) //0x40020414 
#define GPIOC_ODR_Addr    (GPIOC_BASE+20) //0x40020814 
#define GPIOD_ODR_Addr    (GPIOD_BASE+20) //0x40020C14 
#define GPIOE_ODR_Addr    (GPIOE_BASE+20) //0x40021014 
#define GPIOF_ODR_Addr    (GPIOF_BASE+20) //0x40021414    
#define GPIOG_ODR_Addr    (GPIOG_BASE+20) //0x40021814   
#define GPIOH_ODR_Addr    (GPIOH_BASE+20) //0x40021C14    
#define GPIOI_ODR_Addr    (GPIOI_BASE+20) //0x40022014     

//IO口操作,只对单一的IO口

//确保n的值小于16
#define GPIOA_IDR_Addr    (GPIOA_BASE+16) //0x40020010 
#define GPIOB_IDR_Addr    (GPIOB_BASE+16) //0x40020410 
#define GPIOC_IDR_Addr    (GPIOC_BASE+16) //0x40020810 
#define GPIOD_IDR_Addr    (GPIOD_BASE+16) //0x40020C10 
#define GPIOE_IDR_Addr    (GPIOE_BASE+16) //0x40021010 
#define GPIOF_IDR_Addr    (GPIOF_BASE+16) //0x40021410 
#define GPIOG_IDR_Addr    (GPIOG_BASE+16) //0x40021810 
#define GPIOH_IDR_Addr    (GPIOH_BASE+16) //0x40021C10 
#define GPIOI_IDR_Addr    (GPIOI_BASE+16) //0x40022010 
 

#define PAout(n)   BIT_ADDR(GPIOA_ODR_Addr,n)  //输出
#define PAin(n)    BIT_ADDR(GPIOA_IDR_Addr,n)  //输入

#define PBout(n)   BIT_ADDR(GPIOB_ODR_Addr,n)  //输出
#define PBin(n)    BIT_ADDR(GPIOB_IDR_Addr,n)  //输入

#define PCout(n)   BIT_ADDR(GPIOC_ODR_Addr,n)  //输出
#define PCin(n)    BIT_ADDR(GPIOC_IDR_Addr,n)  //输入 

#define PDout(n)   BIT_ADDR(GPIOD_ODR_Addr,n)  //输出
#define PDin(n)    BIT_ADDR(GPIOD_IDR_Addr,n)  //输入 

#define PEout(n)   BIT_ADDR(GPIOE_ODR_Addr,n)  //输出 
#define PEin(n)    BIT_ADDR(GPIOE_IDR_Addr,n)  //输入

#define PFout(n)   BIT_ADDR(GPIOF_ODR_Addr,n)  //输出 
#define PFin(n)    BIT_ADDR(GPIOF_IDR_Addr,n)  //输入

#define PGout(n)   BIT_ADDR(GPIOG_ODR_Addr,n)  //输出
#define PGin(n)    BIT_ADDR(GPIOG_IDR_Addr,n)  //输入

#define PHout(n)   BIT_ADDR(GPIOH_ODR_Addr,n)  //输出 
#define PHin(n)    BIT_ADDR(GPIOH_IDR_Addr,n)  //输入

#define PIout(n)   BIT_ADDR(GPIOI_ODR_Addr,n)  //输出
#define PIin(n)    BIT_ADDR(GPIOI_IDR_Addr,n)  //输入

技术
©2020 ioDraw All rights reserved
自制整人电脑小程序华为鸿蒙系统学习笔记9-开发者生态建设PHP调用shell命令比特币突破8000美元 背后暗藏杀机使用函数实现两个数的交换(C语言)log4j打印异常堆栈信息的方法少儿编程孩子的学习路线分享一场黑客帝国代码雨脚本,简单好玩!三分钟看懂神经网络机器翻译 疫情过后 学哪个编程有前景