EmbeddedSystemDevelopment聊城大学理工学院曹银杰caoyinjie@lcu.edu.cn嵌入式系统与应用第7章CMSIS架构与STM32库开发方式7.1STM32库简介7.2STM32结构及库层次关系7.3库文件及使用简介7.4GPIO7.5stm32f10x.h中GPIO代码剖析7.6GPIO控制LED灯实验7.7时钟设置与开启外设时钟7.1STM32库简介STM32外设资源丰富,寄存器的数量多、设置复杂度高,直接配置寄存器方式开发程序效率低。STM32库是由ST公司针对STM32提供的函数接口,即API(ApplicationProgramInterface),库是架设在寄存器与用户驱动层之间的代码,向下处理与寄存器直接相关的配置,向上为用户提供配置寄存器的接口。STM32库简介开发者可调用这些函数接口来配置STM32的寄存器,开发快速,易于阅读,维护成本低等优点。事实上,库函数的底层实现恰恰是直接配置寄存器方式的最佳例子,想深入了解芯片是如何工作的话,只要追踪到库的最底层实现就能理解。想修炼C语言,就从ST的库开始。7.2STM32结构及库层次关系解决不同的芯片厂商生产的Cortex微控制器软件的兼容性问题,ARM与芯片厂商建立了一个软件抽象层。CMSIS标准:CortexMicroControllerSoftwareInterfaceStandard。CMSIS架构STM32结构及库层次关系CMSIS标准中最主要的为CMSIS核心层,它包括了:内核函数层:其中包含用于访问内核寄存器的名称、地址定义,主要由ARM公司提供。设备外设访问层:提供了片上的核外外设的地址和中断定义,主要由芯片生产商提供可见CMSIS层位于硬件层与操作系统或用户层之间,提供了与芯片生产商无关的硬件抽象层,可以为接口外设、实时操作系统提供简单的处理器软件接口,屏蔽了硬件差异,这对软件的移植是有极大的好处的。STM32的库,就是按照CMSIS标准建立的。7.3库文件及使用简介新建工程---选择芯片后—选择运行环境、用的库、驱动文件、RTX等—编译时自动添加其他用的库文件库文件及使用简介ARM公司提供的:如core_cm3.h、及core_前缀的头文件,核内设备函数层,进入M3内核的接口。stdin.h头文件,这是一个ANSIC文件,是独立于处理器之外的,就像我们熟知的C语言头文件stdio.h文件一样。misc.h和misc.c是和CM3内核有关的NVIC和SysTick的驱动代码。自行添加到工程。ST公司提供的:stm32f10x.h重要文件,定义寄存器地址、寄存器数据结构、中断向量表。stm32f10x_adc.c、stm32f10x_adc.h,针对模数转换(ADC)外设,还有很多其他设备外设的驱动程序。每个外设对应一个.c和.h后缀的文件。库文件及使用简介startup_stm32f10x_xx.s启动文件,作用是:1.初始化堆栈指针SP;2.初始化程序计数器指针PC;3.设置堆、栈的大小;4.设置异常向量表的入口地址;5.配置外部SRAM作为数据存储器(这个由用户配置,一般的开发板可没有外部SRAM);6.设置C库的分支入口__main(最终调用main函数);7.启动文件还调用了在system_stm32f10x.c文件中的SystemIni()函数配置系统时钟。system_stm32f10x.c文件提供了两个函数和一个全局变量库文件及使用简介stm32f10x.h头文件中重要的内容就是把STM32的所有寄存器进行地址映射。如同51单片机的reg52.h头文件一样,stm32f10x.h像一个大表格,我们在使用的时候就是通过宏定义进行类似查表的操作。没有这个文件的话,怎样访问STM32的寄存器,有什么缺点?-1、需要查手册来确定哪个地址对应哪个寄存器。-2、地址易写错、可读性差、易出错、开发效率低。库文件及使用简介库函数,就是STM32的库文件中为我们编写好的函数接口,调用这些库函数,就可以对STM32进行配置。我们可以不知道库函数是如何实现的,但必须要知道函数的功能、可传入的参数及其意义、和函数的返回值。库函数很多,学会查阅库帮助文档就行!库帮助文档:stm32f10x_stdperiph_lib_um.chm–层层打开文档的目录标签即可。–在用库函数的地方,直接从库帮助文档复制即可。思考题:1、没有stm32f10x.h头文件的话,怎样访问STM32的寄存器,有什么缺点?2、从STM32库的实现原理上解答库到底是什么?为什么要用库?用库函数与直接配置寄存器的区别等问题。7.4GPIOGPIO(GeneralPurposeI/O)通用型输入/输出,主要用于需要用到数字量输入/输出的场合。如:–继电器、LED、蜂鸣器等的控制;–传感器状态、高低电平等信息的输入等。1、GPIO简介大部分GPIO为推挽输出,具有完整I2C功能的是开漏结构;正常拉出灌入电流为4mA,短时间极限值40mA;管脚可承受最大5V的输入电压。GPIO寄存器位于AHB总线上,可以进行高性能的CPU快速访问,支持Cortex-M3位带操作。GPIO允许进行DMA数据操作。GPIO简介GPIO引脚又被分为GPIOA、GPIOB…GPIOG不同的组,每组端口分为0~15,共16个不同的引脚,不同芯片的端口组数不同。GPIO结构图:端口配置寄存器GPIO简介I/O引脚可通过端口配置寄存器设置成不同的功能。四种输入模式(结构图上半部分):上拉输入与下拉输入:与VDD相连的为上拉电阻,与VSS相连的为下拉电阻。再经施密特触发器就把信号转化为0、1存储在输入数据寄存器。浮空输入:不接上拉与下拉电阻,直接由触发器输入,由于其输入阻抗较大,一般把这种模式用于标准的通讯协议如I2C、USART的接收端。模拟输入:把电压信号直接传送到片上外设模块,如ADC。GPIO简介结构图下半部分为输出模式结构:推挽输出模式:在输出高电平时,P-MOS导通,低电平时,N-MOS管导通。开漏输出模式:输出0时为低电平,1为高阻状态。在使用任何一种开漏模式,都需要接上拉电阻。GPIO简介STM32P0.xP2.xGPIO都可配置为中断功能,并可设置为上升沿、下降沿或边沿触发。下降沿中断边沿中断GPIO中断还具有掉电唤醒功能2、GPIO端口配置寄存器端口配置低寄存器GPIOx_CRL(配置0~7引脚),端口配置高寄存器GPIOx_CRH(配置8~15引脚)(x=A…G)。可将I/O口配置为输入、输出或模拟模式;PIOx_CRL复位值:44444444h,偏移地址:00h。每个引脚的模式由寄存器的4个位控制,又分引脚配置(CNFy[1:0]),引脚的模式(MODEy[1:0]),其中y表示第y个引脚。GPIOx_CRLGPIO端口配置寄存器例:CRH高寄存器的配置PIOx_CRH复位值:44444444h,偏移地址:04h。例:GPIOx_CRH寄存器的第28至29位设置为11,并在第30至31位设置为00答:则把x端口第15个引脚的模式配置成了:输出的最大速度为50MHz的通用推挽输出模式。3、端口输入数据寄存器GPIOx_IDR端口输入数据寄存器(GPIOx_IDR)(x=A..E)复位值:44444444h,地址偏移:08h高位31:16保留,始终读为0。IDRx[15:0]:端口输入数据(x=0…15)这些位为只读并只能以字的形式读出。读出的值为对应I/O口的状态。4、端口输出数据寄存器GPIOx_ODR端口输出数据寄存器(GPIOx_ODR)(x=A..E)设置I/O口的方向输入还是输出。复位值:44444444h,地址偏移:0Ch高位31:16保留,始终为0。ODRx[15:0]:端口输出数据方向(x=0…15)这些位可读可写并只能以字的形式操作。通过GPIOx_BSRR(x=A…E),可以分别地对各个ODR位进行独立的置位/清零。5、端口置位/清零寄存器GPIOx_BSRR端口置位/清零寄存器(GPIOx_BSRR)(x=A..E)复位值:44444444h,地址偏移:10h6、端口位复位寄存器(GPIOx_BRR)端口位复位寄存器(GPIOx_BRR)(x=A..E)复位值:44444444h,地址偏移:14h7、端口配置锁定寄存器GPIOx_LCKR端口配置锁定寄存器(GPIOx_LCKR)(x=A..E)复位值:44444444h,地址偏移:14h当执行正确的写序列设置了位16(LCKK)时,该寄存器用来锁定端口位的配置。位[15:0]用于锁定GPIO端口的配置。在规定的写入操作期间,不能改变LCKP[15:0]。当对相应的端口位执行了LOCK序列后,在下次系统复位之前将不能再更改端口位的配置。每个锁定位锁定控制寄存器(CRL,CRH)中相应的4个位。例:要控制引脚电平高低,需要对寄存器进行什么操作?一个引脚y的输出数据由GPIOx_BSRR寄存器位的2个位来控制分别为BRy(BitResety)和BSy(BitSety),BRy位用于写1清零,使引脚输出低电平;BSy位用来写1置1,使引脚输出高电平。8、GPIO输入输出演示GPIOx_IDR10BRy写1Bsy写1INOUT10GPIOx_ODRGPIOx_PUPDRvccGPIOGPIOx_CRL设置引脚为GPIO功能1配置引脚模式2设置GPIO的方向3设置GPIO输出电平4GPIO输入GPIO输出1高电平1输出操作流程输入操作流程1读取GPIO引脚电平4GPIOx_BSRR7.5stm32f10x.h库中GPIO代码剖析以外设GPIOC为例,文件中包含如下宏定义:#defineGPIOC_BASE(APB2PERIPH_BASE+0x1000)#defineAPB2PERIPH_BASE(PERIPH_BASE+0x10000)#definePERIPH_BASE((uint32_t)0x40000000)首先看外设基地址PERIPH_BASE这个宏,宏展开为0x40000000,并把它强制转换为uint32_t类型数据;总线基地址宏APB2PERIPH_BASE指向地址0x40010000;最后到了宏GPIOC_BASE为APB2PERIPH_BASE加上偏移量0x1000得到了GPIOC端口的寄存器组的基地址。stm32f10x.h中GPIO代码剖析stm32f10x.h文件,还可以发现以下类似的宏:#defineGPIOA_BASE(APB2PERIPH_BASE+0x0800)#defineGPIOB_BASE(APB2PERIPH_BASE+0x0C00)#defineGPIOC_BASE(APB2PERIPH_BASE+0x1000)#defineGPIOD_BASE(APB2PERIPH_BASE+0x1400)GPIOA、GPIOB、GPIOC、GPIOD寄存器组的起始地址,都对应着独立的一组寄存器。typedefstruct{__IOuint32_tCRL;__IOuint32_tCRH;__IOuint32_tIDR;__IOuint32_tODR;__IOuint32_tBSRR;__IOuint32_tBRR;__IOuint32_tLCKR;}GPIO_TypeDef;#defineGPIOA((GPIO_TypeDef*)GPIOA_BASE)#defineGPIOB((GPIO_TypeDef*)GPIOB_BASE)……(GPIO_TypeDef*)把GPIOA_BASE地址转换为GPIO_TypeDef结构体指针类型。对每个GPIOx是用结构封装了寄存器组,stm32f10x.h中代码:GPIO_TypeDef,这个结构体的首地址(变量CRL的地址)若为