前言
正点原子这一讲实际上讲的是MDK地址名称映射分析和C语言复习,介于C语言的资料也已经很多了,所以我这里就不再重复写一遍了,重点是MDK地址名称的映射,其中一个重要概念——对MCU,一切底层配置,最终都是配置寄存器,即硬件实现的功能的底层操作都是配置寄存器而实现的。
51映射方法
str P0=0x80;//P0映射到地址0x80
P0=0x00;//往寄存器的地址0x80赋值0x00(相当于对P0赋值)
可以看到51的映射是非常简单的,即映射地址和对地址中的变量赋值。
STM32映射方法
STM32的映射关系都是在顶层头文件stm32f10x.h里面的,在第一次听的时候我也听得云里雾里,现在学第二遍稍微思路清晰了一点,主要还是要对C语言地址的概念掌握的扎实。
下面开始讲一下我理解的STM32的映射方法。首先我们知道每一个寄存器都是有自己的地址的,要改变寄存器的值就要对寄存器的地址复制,比如我们进行操作:GPIOA->CRL=0x00000000;他是如何将0这个值映射到了CRL寄存器地址的呢
如下面的代码所示,一个GPIO有7个寄存器,每个寄存器占用的“地址数量”不同,但是没个寄存器的地址依次排列下去的,假设我们找到了GPIOA的地址即找到了CRL…LCKR,就是GPIOA下面的所有寄存器的地址。
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;
而怎么找GPIOA的地址,就要用上层层映射的思路,对51来说,只需要对该变量进行一个地址映射就可以了,但STM32里面的变量太多,所以采用的方法是从一个地址映射到另外一个地址,依次映射下去即可找到所需变量对应的地址。
由下面的代码我们可以知道,GPIO是由GPIO_BASE强制转换而来,所以之后我们要找GPIO_BASE的地址。
#define GPIOA ((GPIO_TypeDef *) GPIOA_BASE)
又由如下宏定义可知,GPIO_BASE的地址是由APB2的地址加上一个值而得的,即是由APB2映射的地址。
#define GPIOA_BASE (APB2PERIPH_BASE + 0x0800)
依次类推,我们可以找到最顶层的地址
#define APB2PERIPH_BASE (PERIPH_BASE + 0x100
#define PERIPH_BASE ((uint32_t)0x40000000)
由此我们可以算到GPIOA的地址为
GPIOA_BASE= 0x40000000+0x10000+0x0800=0x40010800
同理其他的任何一个寄存器也是通过这样的映射方式找到地址的,这就是STM32的映射方法,不同于51的地方是多层映射,但核心思路都是一样的。
参考资料
正点原子的《STM32开发指南-基于库函数》里面的4.1和4.7节有更详细的介绍,不懂的可以去参考一下这本教材。