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) //输入
上一篇:STM32的位带操作分析
下一篇:STM32时钟基础知识
推荐阅读最新更新时间:2024-03-16 16:23
设计资源 培训 开发板 精华推荐
- 51奇趣DIY(LC测试仪已完成)
- 学习 Mentor 白皮书《端到端车辆验证》,涨知识赢好礼!
- 【分享成长,10月有奖】EEWORLD优秀主题/回复第15期活动开始啦!!!
- 【EEWORLD第三十九届】2012年06月社区明星人物揭晓!
- 聊聊你眼中的仙童,超值极品拿到手!
- 有奖直播:基于GaN 的高频(1.2MHz)高效率 1.6kW 高密度临界模式 (CrM) 图腾柱功率因数校正 (PFC)转换器的应用介绍
- 有奖活动:晒出你的电子心头好
- 力源带你了解安森美半导体开发神器——高度灵活的物联网开发套件( IDK )!看视频轻松答题享好礼!
- 有奖直播:新科技、新课堂、新学期~ ADI软件定义无线电ADALM-Pluto入门实战
- 年终大冲关!第二期光荣榜活动震撼登场!