stm32f10x.h 是stm32 的外设的地址映射,把抽象的内存通过一个个宏,映射 到了见名知义的程度。
通过 typedef 兼容了st公司的3.0版的库 中的一些数据类型。
typedef int32_t s32;
typedef int16_t s16;
typedef int8_t s8;
typedef const int32_t sc32; /*!< Read Only */
typedef const int16_t sc16; /*!< Read Only */
typedef const int8_t sc8; /*!< Read Only */
typedef __IO int32_t vs32;
typedef __IO int16_t vs16;
typedef __IO int8_t vs8;
typedef __I int32_t vsc32; /*!< Read Only */
typedef __I int16_t vsc16; /*!< Read Only */
typedef __I int8_t vsc8; /*!< Read Only */
typedef uint32_t u32;
typedef uint16_t u16;
typedef uint8_t u8;
定义了一个结构体 , GPIOX 的各个寄存器(每个是32位,准确的说BRR 是一个16位的寄存器(这里定义32我目前不是很清楚,))
typedef struct
{
__IO uint32_t CRL;
__IO uint32_t CRH;
__IO uint32_t IDR;
__IO uint32_t ODR;
__IO uint32_t BSRR;
__IO uint32_t BRR;
__IO uint32_t LCKR;
} GPIO_TypeDef;
定义宏 来吧 STM32 复杂的内存,简单化清晰化,以及在以后的程序中用到的时候方便化。
采用的是 定义一个 基址 地址,每个外设的地址 等于 基址地址 +偏移地址,从而计算出外设的地址。
#define PERIPH_BASE ((uint32_t)0x40000000)
#define APB1PERIPH_BASE PERIPH_BASE
#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000)
#define AHBPERIPH_BASE (PERIPH_BASE + 0x20000)
#define GPIOA_BASE (APB2PERIPH_BASE + 0x0800)
#define GPIOB_BASE (APB2PERIPH_BASE + 0x0C00)
#define GPIOC_BASE (APB2PERIPH_BASE + 0x1000)
#define GPIOD_BASE (APB2PERIPH_BASE + 0x1400)
#define GPIOE_BASE (APB2PERIPH_BASE + 0x1800)
#define GPIOF_BASE (APB2PERIPH_BASE + 0x1C00)
#define GPIOG_BASE (APB2PERIPH_BASE + 0x2000)
宏定义 GPIOA= ((GPIO_TypeDef *)GPIOA_BASE);
把 GPIOA_BASE 强制转换成 指向 GPIO_TypeDef 型的指针。 GPIO_TypeDef 是一个结构体,上面的代码已经贴出了。
#define GPIOA ((GPIO_TypeDef *) GPIOA_BASE)
#define GPIOB ((GPIO_TypeDef *) GPIOB_BASE)
#define GPIOC ((GPIO_TypeDef *) GPIOC_BASE)
#define GPIOD ((GPIO_TypeDef *) GPIOD_BASE)
#define GPIOE ((GPIO_TypeDef *) GPIOE_BASE)
#define GPIOF ((GPIO_TypeDef *) GPIOF_BASE)
#define GPIOG ((GPIO_TypeDef *) GPIOG_BASE)
现在把 目光转向 外设的驱动文件,承接上面贴出的代码,我选择 GPIO 外设的驱动文件 stm32f10x_gpio.c
选择 void GPIO_Init() 函数(我省略了函数的形参,以后会详细分析下这个函数的具体实现,感受下ST公司工程师给我们创造美丽的艺术品) 节选一部分代码 贴出来。 主要看下加粗的部分,
if (((uint32_t)GPIO_InitStruct->GPIO_Pin & ((uint32_t)0x00FF)) != 0x00)
{
**tmpreg = GPIOx->CRL;**
for (pinpos = 0x00; pinpos < 0x08; pinpos++)
{
pos = ((uint32_t)0x01) << pinpos;
/* Get the port pins position */
currentpin = (GPIO_InitStruct->GPIO_Pin) & pos;
if (currentpin == pos)
{
pos = pinpos << 2;
/* Clear the corresponding low control register bits */
pinmask = ((uint32_t)0x0F) << pos;
tmpreg &= ~pinmask;
/* Write the mode configuration in the corresponding bits */
tmpreg |= (currentmode << pos);
/* Reset the corresponding ODR bit */
if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPD)
{
**GPIOx->BRR** = (((uint32_t)0x01) << pinpos);
}
GPIOA-> CRL (这里我把A给了X)
翻译下这个句子就是 : GPIOA->CRL= ( ((GPIO_TypeDef *) ( (((uint32_t)0x40000000) + 0x10000) + 0x0800)))->(CRL) 就是操作这个寄存器, 其实很想我们51中的
sfr P0 = 0x80;
sfr P1 = 0x90;
sfr P2 = 0xA0;
sfr P3 = 0xB0;
只是由于STM32是32的单片机,寄存器过于庞大,不能像51那么简便的访问了而已,其实质都是一样的。