1. 库的层次结构
库是架设在寄存器与用户驱动层之间的代码,向下直接处理与寄存器直接相关的配置,向上为用户提供寄存器的接口。
一切计算机科学问题都可以用分层来解决;库开发方式就体现了封层的思想;(1)用结构体封装寄存器参数;(2)用宏表示参数;(3)用函数封装对寄存器的操作。下面stm32库层之间的关系图;
(1)内核驱动(核内设备函数层)
core_cm3.c和core_cm3.h文件,为芯片设计商设计的芯片外设提供进入M3内核的接口,所有M3系列的芯片这两个文件相同。core_cm3.c和启动文件一样都是底层文件,都是ARM公司提供的,遵守CMSIS标准。
在core_cm3.c文件中包含了 stdint.h 这个头文件,一般在MDK的安装目录。在这个头文件中,定义了一些新类型,这些新类型屏蔽了,在不同的芯片平台int的大小是16位还是32位。
(2)system_stm32f10x.c
system_stm32f10x.c 由ST公司提供,符合CMSIS标准,该文件主要用来设置系统时钟和总线时钟;
(3) stm32f10x.h
对内存的操作封装成宏;该头文件定义了寄存器的地址和使用的结构体封装。
(4)启动文件
文件名英文缩写意义如下:
cl:互联型产品,stm32f105/107系列
vl:超值型产品,stm32f100系列
xl:超高密度产品,stm32f101/103系列
ld:低密度产品,flash小于64K
md:中密度产品,flash=64K or 128K
hd:高密度产品,flash大于128K
启动文件的作用:
** 初始化堆栈指针SP
** 初始化程序计数器指针PC
** 设置堆、栈的大小
** 设置异常向量表的入口地址
** 配置SRAM作为数据存储器
** 设置C库分支入口__main (最终用来调用main函数)
** 3.5版的启动文件还调用system_stm32f10x.c文件中的 SystemInit()函数配置系统时钟。
(5)外设驱动文件
stm32f10x_ppp.c 和 stm32f10x_ppp.h ppp表示外设的名称。
其中有个特殊文件 misc.c :该文件提供了对内核的NVIC(中断向量控制器)访问函数,因此配置中断时,需要把此函数加进去。
(6) stm32f10x_it.c
文件定义了中断服务函数,中断服务函数的接口可以在启动汇编文件中找到。
(7)stm32f10x_conf.h
该文件用来配置使用了什么外设。处于用户层的文件才会与用户打交道,也就是我们编写程序时,要进行修改的文件。
2.存储器的地址映射
#define PERIPH_BASE ((uint32_t)0x40000000)
#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000)
#define GPIOA_BASE (APB2PERIPH_BASE + 0x0800)
(1)外设基地址
#define APB1PERIPH_BASE PERIPH_BASE
#define APB2PERIPH_BASE (PERIPH_BASE + 0x10000)
#define AHBPERIPH_BASE (PERIPH_BASE + 0x20000)
由上面的宏定义可知,APB1,APB2,AHB总线相对于外设基地址的偏移量分别为0,0x10000,0x20000。
RCC_APB1Periph_TIM3
RCC_APB1Periph_TIM4
RCC_APB1Periph_TIM5
RCC_APB1Periph_TIM6
RCC_APB1Periph_TIM7
RCC_APB1Periph_WWDG
RCC_APB1Periph_SPI2
RCC_APB1Periph_SPI3
RCC_APB1Periph_USART2
RCC_APB1Periph_USART3
RCC_APB1Periph_USART4
RCC_APB1Periph_USART5
RCC_APB1Periph_I2C1
RCC_APB1Periph_I2C2
RCC_APB1Periph_USB
RCC_APB1Periph_CAN1
RCC_APB1Periph_BKP
RCC_APB1Periph_PWR
RCC_APB1Periph_DAC
RCC_APB1Periph_CEC
RCC_APB1Periph_TIM12
RCC_APB1Periph_TIM13
RCC_APB1Periph_TIM14
#define GPIOB_BASE (APB2PERIPH_BASE + 0x0C00)
#define GPIOC_BASE (APB2PERIPH_BASE + 0x1000)
#define GPIOD_BASE (APB2PERIPH_BASE + 0x1400)
#define GPIOE_BASE (APB2PERIPH_BASE + 0x1800)
#define GPIOF_BASE (APB2PERIPH_BASE + 0x1C00)
#define GPIOG_BASE (APB2PERIPH_BASE + 0x2000)
GPIO都对应一组寄存器,包括端口配置低寄存器(GPIOx_CRL),端口配置高寄存器(GPIOx_CRH),端口输入数据寄存器(),端口输出数据寄存器()等,通过查数据手册,可以得到这些知识。
#define GPIOA ((GPIO_TypeDef *) GPIOA_BASE)
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;
#define __IO volatile
volatile 是C语言中的关键字,关于volatile的用法,可以参考下面这篇博文:
不难发现0x00,0x04,0x08正是数据手册里面CRL、CRH、IDR相对于所在寄存器组的偏移地址。此时就可以通过GPIO->CRL 对端口配置低寄存器进行操作,就像开发51单片机一样就行配置寄存器开发。一般不提倡对stm32进行寄存器开发,因为stm32寄存器比较多,配置起来比较繁琐,移植起来比较麻烦。这篇博文就写到这里,后面将对库开发方式就行讲解。。。。。。。。。。。。。。