stm32f10x库文件中的端口时钟使能方程如下:
void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState)
{
/* Check the parameters */
assert_param(IS_RCC_APB2_PERIPH(RCC_APB2Periph));
assert_param(IS_FUNCTIONAL_STATE(NewState));
if (NewState != DISABLE)
{
RCC->APB2ENR |= RCC_APB2Periph;
}
else
{
RCC->APB2ENR &= ~RCC_APB2Periph;
}
}
当时我看到RCC->APB2ENR |= RCC_APB2Periph;命令时不是很理解,于是我右键go to definition of "RCC"其定义如下:
#define RCC ((RCC_TypeDef *) RCC_BASE)
同样右键go to definition of发现RCC_TypeDef和RCC_BASE定义如下:
typedef struct
{
__IO uint32_t CR;
__IO uint32_t CFGR;
__IO uint32_t CIR;
__IO uint32_t APB2RSTR;
__IO uint32_t APB1RSTR;
__IO uint32_t AHBENR;
__IO uint32_t APB2ENR;
__IO uint32_t APB1ENR;
__IO uint32_t BDCR;
__IO uint32_t CSR;#ifdef STM32F10X_CL
__IO uint32_t AHBRSTR;
__IO uint32_t CFGR2;
#endif /* STM32F10X_CL */#if defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || defined (STM32F10X_HD_VL)
uint32_t RESERVED0;
__IO uint32_t CFGR2;
#endif /* STM32F10X_LD_VL || STM32F10X_MD_VL || STM32F10X_HD_VL */
} RCC_TypeDef;
#define RCC_BASE (AHBPERIPH_BASE + 0x1000)
显然RCC_TypeDef是一个typedef声明的结构体类型,而RCC_BASE表示(AHBPERIPH_BASE + 0x1000)继续看AHBPERIPH_BASE定义:
#define AHBPERIPH_BASE (PERIPH_BASE + 0x20000)
#define PERIPH_BASE ((uint32_t)0x40000000)
/*!< Peripheral base address in the alias region */
从上面两个定义可以知道RCC_BASE表示0X4002100。
综上可把
#define RCC ((RCC_TypeDef *) RCC_BASE)
改为
#define RCC ((RCC_TypeDef *) 0X40021000)
当时看了一些文章才知道上面一段代码是将RCC定义为指向RCC_TypeDe结构体类型的指针且RCC=0X40021000,也就是RCC是一个结构体指针且该结构体首地址为0X40021000类型为RCC_TypeDe(若还不理解可以看看这篇文章https://blog.csdn.net/joysyang520/article/details/52681473)
接下来分析RCC->APB2ENR ,它代表的是RCC所指向的结构体的成员APB2ENR的数据,在定义RCC_TypeDe的代码中我们知道APB2ENR是uint32类型占4个字节(一个字节8位),而且CR、CFGR、CIR、APB1RSTR、APB1RSTR、AHBENR也是uint32类型占4个字节,那么APB2ENR的数据存储在地址为0X40021018~0X4002101B的这4个字节上(结构体的前24个字节存储CR、CFGR、CIR、APB1RSTR、APB1RSTR、AHBENR),在《stm32中文参考手册v10》28页,77页可以得到寄存器RCC_APB2RSTR的首地址为0X40021018(寄存器起始地址+偏移量:0X40021000+018)。
0X4002100C~0X40021010刚好就是RCC_APB2RSTR寄存器的数据,这就很完美了,RCC所指向的结构体中每一个成员的数据存储地址就对应着相应寄存器的地址,也就是RCC寄存器的所有寄存器 RCC_CR、RCC_CFGR、RCC_CIR、RCC_APB2RSTR、RCC_APB1RSTR、RCC_AHBENR、RCC_APB2ENR、RCC_APB1ENR、RCC_BDCR、RCC_CSR的地址与RCC所指向的结构体的成员一一对应。其他的CRC、GPIO、AFIO、EXTI等寄存器的定义与上面方法相同。
接着往下看
RCC->APB2ENR |= RCC_APB2Periph;
RCC->APB2ENR等于寄存器RCC_APB2ENR的数据为0X00000000(复位值也就是未对寄存器操作时寄存器的默认值),RCC_APB2Periph是形参,若实参为RCC_APB2Periph_GPIOB,
#define RCC_APB2Periph_GPIOB ((uint32_t)0x00000008)
RCC->APB2ENR=0x00000008|0X00000000=0x00000008,寄存器RCC_APB2ENR的数据为0X00000008,也就是使能PB端口时钟