×
单片机 > 单片机程序设计 > 详情

STM32位带操作总结

发布时间:2020-08-25 发布时间:
|

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)  //输入



『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
浅谈AVR中定时器几种工作模式