为了学习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 intuint32;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 intuint32;2 typedef unsigned short intuint16;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)
原理跟上面不一样只不过,固件库利用总线的首地址来寻找每个外设的地址。