在学习32中的滴答定时器的时候,我进入底层去分析代码,然后就遇到了拦路虎。我遇到了这样的代码
1 //core_cms.h中的宏定义 2 #define SCS_BASE (0xE000E000) 3 #define SysTick_BASE (SCS_BASE + 0x0010) 4 #define SysTick ((SysTick_Type *) SysTick_BASE) 5 //滴答定时器结构体 6 typedef struct 7 { 8 __IO uint32_t CTRL; /*!< Offset: 0x00 SysTick Control and Status Register */ 9 __IO uint32_t LOAD; /*!< Offset: 0x04 SysTick Reload Value Register */ 10 __IO uint32_t VAL; /*!< Offset: 0x08 SysTick Current Value Register */ 11 __I uint32_t CALIB; /*!< Offset: 0x0C SysTick Calibration Register */ 12 } SysTick_Type; 13 //配置滴答定时器 14 static __INLINE uint32_t SysTick_Config(uint32_t ticks) 15 { 16 if (ticks > SysTick_LOAD_RELOAD_Msk) return (1); /* Reload value impossible */ 17 18 SysTick->LOAD = (ticks & SysTick_LOAD_RELOAD_Msk) - 1; /* set reload register */ 19 NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1); /* set Priority for Cortex-M0 System Interrupts */ 20 SysTick->VAL = 0; /* Load the SysTick Counter Value */ 21 SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | 22 SysTick_CTRL_TICKINT_Msk | 23 SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */ 24 return (0); /* Function successful */ 25 }
在第4行我就不理解结构体指针到底指向的是什么位置,在我一开始的想法中,我觉得应该指向的是结构体变量的地址。按照这个思路的话,在宏定义中就没必要有第1行和第2行。
然后我就对代码进行调试,找到了VAL寄存器,以及内存。调试界面如下:
发现指针指向的地址就是SysTick_BASE 的值,我想了一下指针的定义,*A就是代表去访问A中所存放的地址的内容。这样我就理解了
后来我对比滴答定时器四个寄存器的地址也均正确,然后也就明白了第1行和第2行代码那样设计的含义——在为多个寄存器提供地址的时候,写成基准地址+偏移地址这样的写法更容易后期来维护代码。