我对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条回答
warship
1楼-- · 2019-07-24 19:59
本帖最后由 warship 于 2018-7-9 11:07 编辑

用到的寄存器位:
RCC寄存器基址  4002 1000
RCC->CR   +0
RCC_CR_HSEON    位16
RCC_CR_HSERDY   位17
RCC_CR_PLLON     位24
RCC_CR_PLLRDY   位25

RCC->CFGR +4
RCC_CFGR_SW0      位0
RCC_CFGR_SW_PLL  位1
RCC_CFGR_SWS_PLL  位3
现在定义一下位别名地址:
// #define RCC_BASE   0x40021000    //这个官方已有定义
#define bRCC_CR_HSEON   BIT_ADDR(RCC_BASE, 16)  
#define bRCC_CR_HSERDY   BIT_ADDR(RCC_BASE, 17)
#define bRCC_CR_PLLON   BIT_ADDR(RCC_BASE, 24)
#define bRCC_CR_PLLRDY    BIT_ADDR(RCC_BASE, 25)

#define bRCC_CFGR_SW0       BIT_ADDR(RCC_BASE+4, 0)
#define bRCC_CFGR_SW_PLL   BIT_ADDR(RCC_BASE+4, 1)
#define bRCC_CFGR_SWS_PLL   BIT_ADDR(RCC_BASE+4, 3)

为了与官方定义区别,位地址宏均加上前缀b
话说这种基础性的工作,一个上午就可以全部搞定,做成一个位别名地址宏的头文件。
warship
2楼-- · 2019-07-25 00:19
 精彩回答 2  元偷偷看……
warship
3楼-- · 2019-07-25 01:40
本帖最后由 warship 于 2018-7-9 11:24 编辑

再比较一下,编译出来的目标代码,先看位操作版本:
   506:   bRCC_CR_HSEON=1;
   507:   
   508:   /* 等待HSE时钟就绪 */
0x08000D58 2001      MOVS     r0,#0x01
0x08000D5A 490F      LDR      r1,[pc,#60]  ; @0x08000D98
0x08000D5C 6408      STR      r0,[r1,#0x40]
   509:   while (!bRCC_CR_HSERDY){}
   510:   
   511:   /* 使能 PLL */
0x08000D5E BF00      NOP      
0x08000D60 480D      LDR      r0,[pc,#52]  ; @0x08000D98
0x08000D62 6C40      LDR      r0,[r0,#0x44]
0x08000D64 2800      CMP      r0,#0x00
0x08000D66 D0FB      BEQ      0x08000D60
   512:   bRCC_CR_PLLON=1;
   513:   
   514:   /* 等待直到 PLL 就绪 */
0x08000D68 2001      MOVS     r0,#0x01
0x08000D6A 490B      LDR      r1,[pc,#44]  ; @0x08000D98
0x08000D6C 6608      STR      r0,[r1,#0x60]
   515:   while(!bRCC_CR_PLLRDY){}
   516:   
   517:   /* 把 PLL 作为系统时钟源 */      
0x08000D6E BF00      NOP      
0x08000D70 4809      LDR      r0,[pc,#36]  ; @0x08000D98
0x08000D72 6E40      LDR      r0,[r0,#0x64]
0x08000D74 2800      CMP      r0,#0x00
0x08000D76 D0FB      BEQ      0x08000D70
   518:   bRCC_CFGR_SW0=0;       //系统时钟选择SW0位复位   
0x08000D78 2000      MOVS     r0,#0x00
0x08000D7A 4907      LDR      r1,[pc,#28]  ; @0x08000D98
0x08000D7C 3180      ADDS     r1,r1,#0x80
0x08000D7E 6008      STR      r0,[r1,#0x00]
   519:   bRCC_CFGR_SW_PLL=1;    //系统时钟选择PLL(BIT1位)置1
   520:  
   521:   /* 等待,直到 PLL 被用作系统时钟源 */
0x08000D80 2001      MOVS     r0,#0x01
0x08000D82 4905      LDR      r1,[pc,#20]  ; @0x08000D98
0x08000D84 F8C10084  STR      r0,[r1,#0x84]
   522:   while (!bRCC_CFGR_SWS_PLL) //BIT3为1指示PLL已为钟源
   523:    {} 0x08000D88 BF00      NOP      
0x08000D8A 4803      LDR      r0,[pc,#12]  ; @0x08000D98
0x08000D8C 308C      ADDS     r0,r0,#0x8C
0x08000D8E 6800      LDR      r0,[r0,#0x00]
0x08000D90 2800      CMP      r0,#0x00
0x08000D92 D0FA      BEQ      0x08000D8A
   524: }

warship
4楼-- · 2019-07-25 07:26
本帖最后由 warship 于 2018-7-9 11:26 编辑

再看一下31楼的STM官方惯用的寄存器版本,编译结果为:        469:   RCC->CR |= ((uint32_t)RCC_CR_HSEON);
   470:   
   471:   /* 等待HSE时钟就绪 */
0x08000D58 4816      LDR      r0,[pc,#88]  ; @0x08000DB4
0x08000D5A 6800      LDR      r0,[r0,#0x00]
0x08000D5C F4403080  ORR      r0,r0,#0x10000
0x08000D60 4914      LDR      r1,[pc,#80]  ; @0x08000DB4
0x08000D62 6008      STR      r0,[r1,#0x00]
   472:   while ((RCC->CR & RCC_CR_HSERDY) == 0)
   473:    {}
   474:   
   475:   /* 使能 PLL */
0x08000D64 BF00      NOP      
0x08000D66 4813      LDR      r0,[pc,#76]  ; @0x08000DB4
0x08000D68 6800      LDR      r0,[r0,#0x00]
0x08000D6A F4003000  AND      r0,r0,#0x20000
0x08000D6E 2800      CMP      r0,#0x00
0x08000D70 D0F9      BEQ      0x08000D66
   476:   RCC->CR |= RCC_CR_PLLON;
   477:   
   478:   /* 等待直到 PLL 就绪 */
0x08000D72 4810      LDR      r0,[pc,#64]  ; @0x08000DB4
0x08000D74 6800      LDR      r0,[r0,#0x00]
0x08000D76 F0407080  ORR      r0,r0,#0x1000000
0x08000D7A 490E      LDR      r1,[pc,#56]  ; @0x08000DB4
0x08000D7C 6008      STR      r0,[r1,#0x00]
   479:   while((RCC->CR & RCC_CR_PLLRDY) == 0)
   480:    {}
   481:   
   482:   /* 把 PLL 作为系统时钟源 */      
0x08000D7E BF00      NOP      
0x08000D80 480C      LDR      r0,[pc,#48]  ; @0x08000DB4
0x08000D82 6800      LDR      r0,[r0,#0x00]
0x08000D84 F0007000  AND      r0,r0,#0x2000000
0x08000D88 2800      CMP      r0,#0x00
0x08000D8A D0F9      BEQ      0x08000D80
   483:     RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW)); //系统时钟选择位(BIT1:0)复位(00为HSI 01为HSE 10为PLL)
0x08000D8C 4809      LDR      r0,[pc,#36]  ; @0x08000DB4
0x08000D8E 6840      LDR      r0,[r0,#0x04]
0x08000D90 F0200003  BIC      r0,r0,#0x03
0x08000D94 4907      LDR      r1,[pc,#28]  ; @0x08000DB4
0x08000D96 6048      STR      r0,[r1,#0x04]
   484:     RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;    //系统时钟选择PLL(BIT1位)置1
   485:  
   486:   /* 等待,直到 PLL 被用作系统时钟源 */
0x08000D98 4608      MOV      r0,r1
0x08000D9A 6840      LDR      r0,[r0,#0x04]
0x08000D9C F0400002  ORR      r0,r0,#0x02
0x08000DA0 6048      STR      r0,[r1,#0x04]
   487:   while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08) //BIT3为1指示PLL已为钟源
   488:    {}
0x08000DA2 BF00      NOP      
0x08000DA4 4803      LDR      r0,[pc,#12]  ; @0x08000DB4
0x08000DA6 6840      LDR      r0,[r0,#0x04]
0x08000DA8 F000000C  AND      r0,r0,#0x0C
0x08000DAC 2808      CMP      r0,#0x08
0x08000DAE D1F9      BNE      0x08000DA4
   489: }

warship
5楼-- · 2019-07-25 07:55
 精彩回答 2  元偷偷看……
d1z1y2
6楼-- · 2019-07-25 11:53
以前的RAM都是省着用,标志位全部是定义成bit,不像现在的单片机资源那么丰富,只要能快速的把项目做出来,谁还去花时间去研究代码效率啊

一周热门 更多>