STM32------C语言对寄存器的封装
为了学习STM32时比较踏实,有必要了解固件库底层是怎么操作的
GPIOA~F首地址
GPIOA | 0x4002 0000 |
GPIOB | 0x4002 0400 |
GPIOC | 0x4002 0800 |
GPIOD | 0x4002 0C00 |
GPIOE | 0x4002 1000 |
GPIOF | 0x4002 1400 |
以GPIOF口的GPIO_OSPEEDR寄存器为例
1 typedef unsigned int uint32; 2 //GPIOF内存块的首地址 3 #define GPIOF_BASE (0x4002 1400) 4 //GPIO口寄存器 5 #define GPIO_MODER *(uint32 *)(GPIO_BASE+0x00) 6 #defien GPIO_OTYPER *(uint32 *)(GPIO_BASE+0x04) 7 #define GPIO_OSPEEDR *(uint32 *)(GPIO_BASE+0x08) 8 #define GPIO_PUPDR *(uint32 *)(GPIO_BASE+0x0C) 9 #define GPIO_IDR *(uint32 *)(GPIO_BASE+0x10) 10 #define GPIO_ODR *(uint32 *)(GPIO_BASE+0x14) 11 #define GPIO_LCKR *(uint32 *)(GPIO_BASE+0x1C) 12 #define GPIO_AFRL *(uint32 *)(GPIO_BASE+0x20) 13 #define GPIO_AFRH *(uint32 *)(GPIO_BASE+0x24)
这样的话,我们如果要令GPIO_MODE寄存器的值全为F,GPIO_MODE=0xFFFF FFFF.
像上面这样定义寄存器有一个缺点,就是这只是定义了一个GPIO口,如果要把所有GPIO口都定义了,那将会有很多这样的定义,这样太麻烦,而且也不太好阅读。为了方便定义寄存器,我将用结构体,从上面寄存器的偏移地址可以看出,每个寄存器都是一个接着一个有序的排列,这就类似于C语言中的结构体。所以我们可以利用结构体来简化定义。
1 typedef unsigned int uint32; 2 typedef unsigned short int uint16; 3 #define GPIOA_BASE (0x4002 0000) 4 #define GPIOB_BASE (0x4002 0400) 5 #define GPIOC_BASE (0x4002 0800) 6 typedef struct 7 { 8 uint32 GPIO_MODER; 9 uint32 GPIO_OTYPER; 10 uint32 GPIO_OSPEEDR; 11 uint32 GPIO_PUPDR; 12 uint32 GPIO_IDR; 13 uint32 GPIO_ODR; 14 uint32 GPIO_LCKR; 15 uint16 GPIO_AFRL; 16 uint16 GPIO_AFRH; 17 }GPIO_TypeDef; 18 19 #define GPIOA (GPIO_TypeDef *)GPIOA_BASE; 20 #define GPIOB (GPIO_TypeDef *)GPIOB_BASE; 21 #define GPIOC (GPIO_TypeDef *)GPIOC_BASE; 22 23 GPIOA->GPIO_MODER=0xffffff;
首先,我们定义每个GPIO的内存块的首地址,然后定义一个结构体,里面的成员要按顺序写好寄存器的别名,接着我们用第19的宏定义,将GPIO的内存块首地址强制转换成指向结构体的指针,也就是结构体的首地址就是GPIO内存块的首地址,最后我们可以利用成员符号,对每个寄存器进行写入数据或者读取数据。
STM32中固件库到底是什么
STM32内部里有一个叫总线的东西有APB1,APB2,APB3,AHB1,AHB2总线,总线也是有地址的,固件库是怎么利用总线的地址来寻到每个寄存器呢?
1 #define PERIPH_BASE ((uint32_t)0x40000000) 2 #define APB1PERIPH_BASE PERIPH_BASE 3 #define APB2PERIPH_BASE (PERIPH_BASE + 0x00010000) 4 #define AHB1PERIPH_BASE (PERIPH_BASE + 0x00020000) 5 #define AHB2PERIPH_BASE (PERIPH_BASE + 0x10000000) 6 7 #define GPIOA_BASE (AHB1PERIPH_BASE + 0x0000) 8 #define GPIOB_BASE (AHB1PERIPH_BASE + 0x0400) 9 #define GPIOC_BASE (AHB1PERIPH_BASE + 0x0800) 10 #define GPIOD_BASE (AHB1PERIPH_BASE + 0x0C00) 11 #define GPIOE_BASE (AHB1PERIPH_BASE + 0x1000) 12 #define GPIOF_BASE (AHB1PERIPH_BASE + 0x1400) 13 #define GPIOG_BASE (AHB1PERIPH_BASE + 0x1800) 14 #define GPIOH_BASE (AHB1PERIPH_BASE + 0x1C00) 15 #define GPIOI_BASE (AHB1PERIPH_BASE + 0x2000) 16 #define GPIOJ_BASE (AHB1PERIPH_BASE + 0x2400) 17 #define GPIOK_BASE (AHB1PERIPH_BASE + 0x2800)
原理跟上面不一样只不过,固件库利用总线的首地址来寻找每个外设的地址。
crazyyang