上一次我们已经实现了如何直接操作寄存器地址来点亮一盏LED灯,但是这样实在是太麻烦,那么这次要讲的就是,如何实现寄存器映射,更加快捷的实现点灯(怎么又是点灯??)
我们先来看一下上一次的代码。
图中的这些地址都是看着官方给出的文档算出来的,这样做的缺点很明显,就是每一次都要算,算每一个寄存器的位置,实际上我们可以寄存器映射来做到同样的效果。
首先我们先定义所有外设的基地址的宏:
那么这个地址从哪里来的呢?可以看一下面这张图,ST把所有的存储器分成了8个块,直接来看(从下往上数)第三个块(绝对不是我不知道其他块是干哈的!!)
Peripheral块这里存放了所有ST设计的外设,其中,包含了3条总线APB1、APB2和AHB,位置最低的APB1的基地址,也就是所有外设的基地址,也就是0x40000000,所以我们第二步要定义的,就是APB1的地址:
那么APB2的地址在哪呢?
在上图红色框中的位置,0x4001000,那么是直接定义#define APB2PERIPH_BASE 0x4001000这样吗?在这里,我们往往用偏移的方式,也就是这样:
这里我们用外设基地址+0x10000的方式,到达APB2的位置。
那么AHB同理(虽然用不上,但还是写上吧...):
下一步,我们以点亮PB5为例,还记得我们上次说的,GPIOB也是有偏移量的,那么我们就基于APB2 + GPIOB的偏移量得出:
这样就可以操作GPIOB了,下一步,要操作GPIOB的CRL和ODR,GPIOB的基地址加上偏移量得出:
然后我们再回到main.c里面,把上次的地址换成CRL和ODR:
RCC时钟配置同理,先在stm32f10x.h里面定义宏:
再回到main里面更换
那么最终的代码就是:
//main.c#include "stm32f10x.h"int main(void){ // 开启GPIOB 端口时钟 RCC_APB2ENR |= (1<<3); //清空控制PB5的端口位 GPIOB_CRL &= ~( 0x0F<< (4*5)); // 配置PB5为通用推挽输出,速度为10M GPIOB_CRL |= (1<<4*5); // PB5 输出 低电平 GPIOB_ODR |= (0<<5); while(1);}// 函数为空,目的是为了骗过编译器不报错void SystemInit(void){ }
//stm32f10x.h#ifndef __STM32F10X__H#define __STM32F10X__H/*片上外设基地址 */#define PERIPH_BASE ((unsigned int)0x40000000)/*APB1 总线基地址 */#define APB1PERIPH_BASE (PERIPH_BASE)/*APB2 总线基地址 */#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000)/* AHB总线基地址 */#define AHBPERIPH_BASE (PERIPH_BASE + 0x20000)/*GPIOA外设基地址*/#define GPIOA_BASE (APB2PERIPH_BASE + 0x0800)/* GPIOA寄存器地址,强制转换成指针 */#define GPIOA_CRL *(unsigned int*)(GPIOA_BASE+0x00)#define GPIOA_CRH *(unsigned int*)(GPIOA_BASE+0x04)#define GPIOA_IDR *(unsigned int*)(GPIOA_BASE+0x08)#define GPIOA_ODR *(unsigned int*)(GPIOA_BASE+0x0C)#define GPIOA_BSRR *(unsigned int*)(GPIOA_BASE+0x10)#define GPIOA_BRR *(unsigned int*)(GPIOA_BASE+0x14)#define GPIOA_LCKR *(unsigned int*)(GPIOA_BASE+0x18)/*GPIOB外设基地址*/#define GPIOB_BASE (APB2PERIPH_BASE + 0x0C00)/* GPIOB寄存器地址,强制转换成指针 */#define GPIOB_CRL *(unsigned int*)(GPIOB_BASE+0x00)#define GPIOB_CRH *(unsigned int*)(GPIOB_BASE+0x04)#define GPIOB_IDR *(unsigned int*)(GPIOB_BASE+0x08)#define GPIOB_ODR *(unsigned int*)(GPIOB_BASE+0x0C)#define GPIOB_BSRR *(unsigned int*)(GPIOB_BASE+0x10)#define GPIOB_BRR *(unsigned int*)(GPIOB_BASE+0x14)#define GPIOB_LCKR *(unsigned int*)(GPIOB_BASE+0x18)/*RCC外设基地址*/#define RCC_BASE (AHBPERIPH_BASE + 0x1000)/*RCC的AHB1时钟使能寄存器地址,强制转换成指针*/#define RCC_APB2ENR *(unsigned int*)(RCC_BASE+0x18) #endif /*__STM32F10X__H*/
我是谁我在哪,我在干神魔。。>