6.5 寄存器映射
我们知道,存储器本身没有地址,给存储器分配地址的过程叫存储器映射,那什么叫
寄存器映射?寄存器到底是什么?
在存储器 Block2这块区域,设计的是片上外设,它们以四个字节为一个单元,共 32bit,
每一个单元对应不同的功能,当我们控制这些单元时就可以驱动外设工作。我们可以找到
每个单元的起始地址,然后通过 C 语言指针的操作方式来访问这些单元,如果每次都是通
过这种地址的方式来访问,不仅不好记忆还容易出错,这时我们可以根据每个单元功能的
不同,以功能为名给这个内存单元取一个别名,这个别名就是我们经常说的寄存器,这个
给已经分配好地址的有特定功能的内存单元取别名的过程就叫寄存器映射。
比如,我们找到 GPIOB 端口的输出数据寄存器 ODR 的地址是 0x4001 0C0C(至于这
个地址如何找到可以先跳过,后面我们会有详细的讲解),ODR 寄存器是 32bit,低 16bit
有效,对应着 16 个外部 IO,写 0/1 对应的的 IO 则输出低/高电平。现在我们通过 C 语言指
针的操作方式,让 GPIOB 的 16 个 IO 都输出高电平,具体见代码 6-1。
代码 6-1 通过绝对地址访问内存单元
1 // GPIOB 端口全部输出 高电平
2 *(unsigned int*)(0x4001 0C0C) = 0xFFFF;
0x4001 0C0C在我们看来是 GPIOB端口 ODR的地址,但是在编译器看来,这只是一个
普通的变量,是一个立即数,要想让编译器也认为是指针,我们得进行强制类型转换,把
它转换成指针,即(unsigned int *)0x4001 0C0C,然后再对这个指针进行 * 操作。
刚刚我们说了,通过绝对地址访问内存单元不好记忆且容易出错,我们可以通过寄存
器的方式来操作,具体见代码 6-2。
代码 6-2 通过寄存器别名方式访问内存单元
1 // GPIOB 端口全部输出 高电平
2 #define GPIOB_ODR (unsigned int*)(GPIOB_BASE+0x0C)
3 * GPIOB_ODR = 0xFF;
为了方便操作,我们干脆把指针操作“*”也定义到寄存器别名里面,具体见代码 6-3。
代码 6-3 通过寄存器别名访问内存单元
1 // GPIOB 端口全部输出 高电平
2 #define GPIOB_ODR *(unsigned int*)(GPIOB_BASE+0x0C)
3 GPIOB_ODR = 0xFF;