我对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条回答
xiatianyun
1楼-- · 2019-07-24 07:38
 精彩回答 2  元偷偷看……
warship
2楼-- · 2019-07-24 09:18
 精彩回答 2  元偷偷看……
warship
3楼-- · 2019-07-24 10:03
占用空间情况:
FLASH:两个字,分别用于存放变量MyFlag的地址和别名基址;
SRAM:一个字,存放MyFlag变量本身。
warship
4楼-- · 2019-07-24 15:29
本帖最后由 warship 于 2018-7-9 09:51 编辑

深入剖析了位带操作的机理和优势之后,
有一个疑问,其实外设寄存器都可以通过位带操作,
尤其是寄存器比特位的操作和判别,用位带操作的高效尤其明显。
但是看STM官方的库,却基本不用位带操作:
举个例子,SystemInit()中,把PLL作为系统时钟源,代码如下:
   RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;    //系统时钟选择PLL(BIT1位)置1
这种对整个32位进行读出--逻辑运算--再写回的效率是很低的。
假如用位带操作,则只须 bRCC_CFGR_SW_PLL=1; 就行了
前面要做的准备工作只是定义一个位别名地址宏: #define  bRCC_CFGR_SW_PLL  0x42420040就可以了。
有人可能会想,这是否增加了宏定义的工作量?    我反问:RCC_CFGR_SW_PLL难道就不需要定义吗?
warship
5楼-- · 2019-07-24 16:24
本帖最后由 warship 于 2018-7-9 12:58 编辑

拿前不久我使用的一个从STOP模式中快速恢复时钟的函数为例,
库函数版本如下:
/**
  * 本函数用于从STOP模式唤醒后重新配置系统时钟:使能HSE,PLL并选择PLL作为系统时钟源
  *         
  */
static void SYSCLKConfig_STOP(void)
{  
  /* 从STOP模式唤醒后重新配置系统时钟 */
  /* 使能 HSE */
  RCC_HSEConfig(RCC_HSE_ON);
  
  /* 等待HSE时钟就绪 */
  while (RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET)
  {}  
  
  /* 使能PLL */
  RCC_PLLCmd(ENABLE);
  
  /* 等待PLL就绪 */
  while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
  {}
  
  /* 选择PLL作为系统时钟源 */
  RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
  
  /* 等待时钟源配置就绪 */
  while (RCC_GetSYSCLKSource() != 0x08)
  {}
}
warship
6楼-- · 2019-07-24 19:51
 精彩回答 2  元偷偷看……

一周热门 更多>