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

2019-07-20 23:21发布

本帖最后由 warship 于 2018-7-16 19:56 编辑

在原子例程的sys.h中,使用宏定义建立了位带操作的基础,
使得操作IO端口可以像51一样实现位操作。
其实深入了解了位带操作的原理,几乎就可以实现对STM32所有外设寄存器的访问,
极端情况下,什么库函数版本,什么寄存器版本都可以不用,直接精准地操控所有寄存器的每一位的读写!!!

知道了STM32将所有外设寄存器的每一位都建立了位带别名区,
你只要再花一点点时间,彻底搞明白下面的三句宏定义,位带操作就都不在话下了:
#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))



************************************************************************************************
注:本文后文所探索的寄存器位段操作宏定义包含在另文所附范例(外部中断试验的工程包)中,并随时更新。
有需要研究探讨的网友,可移步下载http://www.openedv.com/forum.php ... d=274724&extra=


友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
49条回答
gotofly21
1楼-- · 2019-07-26 07:22
warship 发表于 2018-7-9 17:06
那可能是别名地址没有计算正确,
对照寄存器基址、偏移量和比特位,
编出一份别名地址宏定义的头文件后 ...

大部分时间是对的
warship
2楼-- · 2019-07-26 11:31
 精彩回答 2  元偷偷看……
正点原子
3楼-- · 2019-07-26 15:59
不错。。。
warship
4楼-- · 2019-07-26 16:18
正点原子 发表于 2018-7-11 02:16
不错。。。

多谢夸奖。
给个酷呗
warship
5楼-- · 2019-07-26 18:22
从第1463行开始就是各个外设寄存器的比特定义了:
对于具独立意义的比特定义采取了32位字中其它无关比特为0,自身所在比特为1的方式,如:
#define  RCC_CSR_LSIRDY                      ((uint32_t)0x00000002)
说明RCC外设的CSR寄存器中的比特位是第1位,而这样的定义正说明了STM官方的工程师们在编制库函数时,
完全放弃了位段操作的思想精髓,而捡起了用“与”、“或”操作来清位/置位的传统的、效率较低的方法。
唯一我可以为他们找到的理由是:因为有许多同时多比特操作的场合,所以二者同时兼顾起来有困难。
不管他了,我们要想定义位别名,就可以借用这个名称定义,并加一个前缀b,用来表示位别名。
即#define  bRCC_CSR_LSIRDY     BIT_ADDR(RCC_BASE+n, 1)  
括号中的1为比特位号,表示该比特在寄存器CSR中的第1比特,
RCC_BASE就是RCC的基址,直接借用就可以了。
还缺少一个数字,就是n, 这个n是某个特定寄存器在其外设基址基础之上的偏移量,
我没有在文件中找到,但偏移量以及比特位都可以在参考手册上查到。
warship
6楼-- · 2019-07-26 19:01
还有一个需要统一约定的问题,那就是有些同类的外设可能有多个,但它们的寄存器名称及位定义是一致的。
如多个GPIO、多个TIM、多个DMA通道、多个SPI等等,则需要在宏定义名称中增加我们习惯的数字或字母以示区分,
如bGPIOE_ODR_ODR0、bSPI1_SR_BSY、bTIM2_SMCR_ECE等,它们各自的区别是基址不同,如TIM2_BASE、TIM3_BASE等等。

一周热门 更多>