固件库详解ppt课件_第1页
固件库详解ppt课件_第2页
固件库详解ppt课件_第3页
固件库详解ppt课件_第4页
固件库详解ppt课件_第5页
已阅读5页,还剩60页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、STM32固件库详解,STM32标准外设库概述,STM32标准外设库之前的版本也称固件函数库或简称固件库,是一个固件函数包,它由程序、数据结构和宏组成,包括了微控制器所有外设的性能特征。该函数库还包括每一个外设的驱动描述和应用实例,为开发者访问底层硬件提供了一个中间API,通过使用固件函数库,无需深入掌握底层硬件细节,开发者就可以轻松应用每一个外设。因此,使用固态函数库可以大大减少用户的程序编写时间,进而降低开发成本。每个外设驱动都由一组函数组成,这组函数覆盖了该外设所有功能。每个器件的开发都由一个通用API (application programming interface 应用编程界面)

2、驱动,API对该驱动程序的结构,函数和参数名称都进行了标准化。 ST公司2007年10月发布了V1.0版本的固件库,MDK ARM3.22之前的版本均支持该库。2008年6月发布了V2.0版的固件库,从2008年9月推出的MDK ARM3.23版本至今均使用V2.0版本的固件库。V3.0以后的版本相对之前的版本改动较大,本书使用目前较新的V3.4版本。,使用标准外设库开发的优势,使用标准外设库进行开发最大的优势就在于可以使开发者不用深入了解底层硬件细节就可以灵活规范的使用每一个外设。标准外设库覆盖了从GPIO到定时器,再到CAN、I2C、SPI、UART和ADC等等的所有标准外设。对应的C源代

3、码只是用了最基本的C编程的知识,所有代码经过严格测试,易于理解和使用,并且配有完整的文档,非常方便进行二次开发和应用。,标准外设库的文件结构,Project:标准外设库驱动实例,STM32F10 x_StdPeriph_Driver 标准外设库驱动,Utilities:包含了用于STM32-EVAL评估板的专用驱动,CMSIS 是独立于供应商的Cortex-M 处理器系列硬件抽象层,为芯片厂商和中间件供应商提供了简单的处理器软件接口,STM32F10 x_StdPeriph_Driver则包括了分别对应包括了所有外设对应驱动函数,标准外设库文件夹描述,标准外设库体系结构,标准外设库体系结构,c

4、ore_cm4.h文件位于STM32F4xx_DSP_StdPeriph_Lib_V1.4.0LibrariesCMSISInclude目录下面的, 这个就是CMSIS核心文件,提供进入M4内核接口,这是ARM公司提供,对所有CM4内核的芯片都一样。你永远都不需要修改这个文件,所以这里我们就点到为止。 stm32f4xx.h和system_stm32f4xx.h文件存放在文件夹 STM32F4xx_DSP_StdPeriph_Lib_V1.4.0LibrariesCMSISDeviceSTSTM32F4xxInclude下面。 system_stm32f4xx.h是片上外设接入层系统头文件。主

5、要是申明设置系统及总线时钟相关的函数。与其对应的源文件system_stm32f4xx.c在目录 STM32F4xx_DSP_StdPeriph_Lib_V1.4.0ProjectSTM32F4xx_StdPeriph_Templates可以找到。这个里面有一个非常重要的SystemInit()函数申明,这个函数在我们系统启动的时候都会调用,用来设置系统的整个系统和总线时钟。,标准外设库体系结构,stm32f4xx.h是STM32F4片上外设访问层头文件。这个文件就相当重要了,只要你做STM32F4开发,你几乎时刻都要查看这个文件相关的定义。这个文件打开可以看到,里面非常多的结构体以及宏定义。

6、这个文件里面主要是系统寄存器定义申明以及包装内存操作。同时该文件还包含了一些时钟相关的定义,FPU和MPU单元开启定义,中断相关定义等等。 stm32f4xx_it.c,stm32f4xx_it.h以及stm32f4xx_conf.h等文件,我们可以从STM32F4xx_DSP_StdPeriph_Lib_V1.4.0ProjectSTM32F4xx_StdPeriph_Templates文件夹中找到。这几个文件我们后面新建工程也有用到。stm32f4xx_it.c和stm32f4xx_it.h里面是用来编写中断服务函数,中断服务函数也可以随意编写在工程里面的任意一个文件里面。 stm32f4

7、xx_conf.h是外设驱动配置文件。文件打开可以看到一堆的#include,这里你建立工程的时候,可以注释掉一些你不用的外设头文件。,标准外设库体系结构,misc.c,misc.h,stm32f4xx_ppp.c,stm32f4xx_ppp.h以及stm32f4xx_rcc.c和tm32f4xx_rcc.h文件,这些文件存放在目录LibrariesSTM32F4xx_StdPeriph_Driver。这些文件是STM32F4标准的外设库文件。其中misc.c和misc.h是定义中断优先级分组以及Systick定时器相关的函数。 stm32f3xx_rcc.c和stm32f4xx_rcc.h是

8、与RCC相关的一些操作函数,作用主要是一些时钟的配置和使能。在任何一个STM32工程RCC相关的源文件和头文件是必须添加的。 对于文件stm32f4xx_ppp.c和stm32f4xx_ppp.h,这就是stm32F4标准外设固件库对应的源文件和头文件。包括一些常用外设GPIO,ADC,USART等。 文件Application.c实际就是说是应用层代码。这个文件名称可以任意取了。我们工程中,直接取名为main.c。,CMSIS标准软件架构,CMSIS 是独立于供应商的Cortex-M 处理器系列硬件抽象层,为芯片厂商和中间件供应商提供了简单的处理器软件接口,简化了软件复用工作,降低了Cort

9、ex-M 上操作系统的移植难度,并减少了新入门的微控制器开发者的学习曲线和新产品的上市时间,CMSIS分为3个基本功能层: 1)核内外设访问层:ARM公司提供的访问,定义处理器内部寄存器地址以及功能函数。2)中间件访问层:定义访问中间件的通用API。由ARM提供,芯片厂商根据需要更新。3)外设访问层:定义硬件寄存器的地址以及外设的访问函数。,库文件介绍,MDK5,MDK源自德国的KEIL公司,是RealViewMDK的简称。在全球MDK被超过10万的嵌入式开发工程师使用。目前最新版本为:MDK5.10,该版本使用uVision5IDE集成开发环境,是目前针对ARM处理器,尤其是CortexM内

10、核处理器的最佳开发工具。 MDK5向后兼容MDK4和MDK3等,以前的项目同样可以在MDK5上进行开发(但是头文件方面得全部自己添加),MDK5同时加强了针对Cortex-M微控制器开发的支持,并且对传统的开发模式和界面进行升级,MDK5由两个部分组成:MDKCore和SoftwarePacks。其中,SoftwarePacks可以独立于工具链进行新芯片支持和中间库的升级。,MDKCore又分成四个部分:uVisionIDEwithEditor(编辑器),ARMC/C+Compiler(编译器),PackInstaller(包安装器),uVisionDebuggerwithTrace(调试跟踪

11、器)。uVisionIDE从MDK4.7版本开始就加入了代码提示功能和语法动态检测等实用功能,相对于以往的IDE改进很大。 SoftwarePacks(包安装器)又分为:Device(芯片支持),CMSIS(ARMCortex微控制器软件接口标准)和Mdidleware(中间库)三个小部分,通过包安装器,我们可以安装最新的组件,从而支持新的器件、提供新的设备驱动库以及最新例程等,加速产品开发进度。,新建基于固件库的工程模板,1)在建立工程之前,我们建议用户在电脑的某个目录下面建立一个文件夹,后面所建立的工 程都可以放在这个文件夹下面,这里我们建立一个文件夹为Template。这是工程的根目录文

12、件夹。然后为了方便我们存放工程需要的一些其他文件,这里我们还新建下面子文件夹USER。至于这些文件夹名字,实际上是可以任取的,我们这样取名只是为了方便识别。,2)打开Keil,点击Keil的菜单:ProjectNewUvisionProject,然后将目录定位到刚才建立的文件夹Template之下的USER子目录,同时,工程取名为Template之后点击保存,我们的工程文件就都保存到USER文件夹下面。,3)接下来会出现一个选择Device的界面,就是选择我们的芯片型号,这里我们定位到 STMicroelectronics下面的STM32F103ZE。这里我们选择STMicroelectron

13、icsSTM32F4SeriesSTM32F103STM32F103ZE(如果使用的是其他系列的芯片,选择相应的型号就可以了。特别注意:一定要安装对应的器件pack才会显示这些内容)。,点击OK,MDK会弹出ManageRun-TimeEnvironment对话框 这是MDK5新增的一个功能,在这个界面,我们可以添加自己需要的组件,从而方便构建开发环境,不过这里我们不做介绍。我们直接点击Cancel,即可,4) 到这里,我们只是建了一个框架,还需要添加启动代码以及.c文件等。现在我们可以看到USER目录下面包含2个文件夹和2个文件 Template.uvprojx是工程文件,非常关键,不能轻易

14、删除 Listings和Objects文件夹是MDK自动生成的文件夹,用于存放编译过程中产生的中间文件。删除这两个文件夹(我们会在下一步骤中新建一个OBJ文件夹用来存放编译中间文件;当然不删除这两个文件夹也没有关系) 5) 接下来,在Template工程目录下新建3个文件夹CORE、OBJ以及STM32F10 x_FWLib。 CORE用来存放核心文件和启动文件 OBJ用来存放编译过程文件以及hex文件 STM32F10 x_FWLib用来存放ST官方提供的库函数源码文件 已有的USER除了用来存放工程文件以外还用来存放主函数文件main.c和system_stm32f10 x.c等,6) 下

15、面我们要将官方的固件库包里的源码文件复制到我们的工程目录文件夹下面。打开官方固件库包,定位到我们之前准备好的固件库包的目录: STM32F10 x_StdPeriph_Lib_V3.5.0LibrariesSTM32F10 x_StdPeriph_Driver下面,将目录下面的src,inc文件夹copy到我们刚才建立的STM32F10 x_FWLib文件夹下面。src中存放的是固件库的.c文件,inc存放的是固件库的.h文件 7) 下面我们要将固件库包里面相关的启动文件复制到我们的工程目录CORE之下。打开官方固件库包,定位到目录 STM32F10 x_StdPeriph_Lib_V3.5.

16、0LibrariesCMSISCM3DeviceSupportSTSTM32F10 xstartuparm下面,将文件startup_stm32f10 x_hd.s复制到CORE目录下面。然后定位到目录STM32F10 x_StdPeriph_Lib_V3.5.0LibrariesCMSISCM3CoreSupport,将里面的头文件core_cm3.h和core_cm3.h同样复制到CORE目录下面。 现在CORE文件夹下包含: startup_stm32f10 x_hd.s, core_cm3.c, core_cm3.h,8) 定位到STM32F10 x_StdPeriph_Lib_V3.

17、5.0LibrariesCMSISCM3DeviceSupportSTSTM32F10 x下,将里面的3个文件stm32f10 x.h, system_stm32f10 x.c, system_stm32f10 x.h复制到USER目录下;然后将STM32F10 x_StdPeriph_Lib_V3.5.0ProjectStm32f10 x_StdPreiph_Template下面的四个文件main.c, stm32f10 x_conf.h, stm32f10 x_it.c, stm32f10 x_it.h复制到USER目录下 前面步骤,我们将需要的固件库相关文件复制到了我们的工程目录下面,下

18、面我们将这些文件加入我们的工程中去。,9) 右键点击Target1,选择ManageComponents,如下图:,10) 在弹出的Manage Project Items对话框中,在 ProjectTargets一栏,将Target名字修改为Template,然后在Groups一栏删掉一个Source Group1,建立三个Groups:USER,CORE,FWLIB。然后点击OK,可以看到我们的Target名字以及Groups情况如图:,11) 下面我们往Group里面添加我们需要的文件。我们按照步骤9的方法,右键点击点击 Tempate,选择选择ManageComponents.然后选择

19、需要添加文件的Group,这里第一步我们选择FWLIB,然后点击右边的AddFiles,定位到我们刚才建立的目录FWLIBsrc下面,将里面所有的文件选中(Ctrl+A),然后点击Add,然后Close.可以看到Files列表下面包含我们添加的文件,如下图。 这里需要说明一下,对于我们写代码,如果我们只用到了其中的某个外设,我们就可以不用添加没有用到的外设的库文件。例如我只用GPIO,我可以只用添加stm32f4xx_gpio.c而其他的可以不用添加。这里我们全部添加进来是为了后面方便,不用每次添加,当然这样的坏处是工程太大,编译起来速度慢,用户可以自行选择。,12) 用同样的方法,将Grou

20、ps定位到CORE和USER下面,添加需要的文件。这里 我们的CORE下面需要添加的文件为core_cm3.c, startup_stm32f10 x_hd.s(注意,默认添加的时候文件类型为.c,也就是添加startup_stm32f10 x_hd.s启动文件的时候,你需要选择文件类型为Allfiles才能看得到这个文件),USER目录下面需要添加的文件为main.c,stm32f10 x_it.c,system_stm32f10 x.c。这样我们需要添加的文件已经添加到我们的工程中去了,最后点击OK,回到工程主界面。 13) 接下来我们要在MDK里面设置头文件存放路径。也就是告诉MDK到那

21、些目录下面去寻 找包含了的头文件。这一步骤非常重要。如果没有设置头文件路径,那么工程会出现报错头文件路径找不到。具体操作如下图,5步之后添加相应的头文件路径。,这里我们需要添加的头文件路径包括:CORE,USER以及FWLIBinc。这里大家务必要仔细,固件库存放的头文件子目录是FWLIBinc,不是FWLIBsrc。很多朋友都是这里弄错导致报很多奇怪的错误,14) 接下来对于STM32F10系列的工程,还需要添加一个全局宏定义标识符。添加方法是点击魔术棒之后,进入C/C+选项卡,然后在Define输入框连输入: STM32F10X_HD,USE_STDPERIPH_DRIVER。注意这里是两

22、个标识符们之间是用逗号隔开的,请大家注意。 HD表示高容量,MD中容量,LD小容量 15) 接下来我们要编译工程,在编译之前我们首先要选择编译中间文件编译后存放目录。 方法是点击魔术棒,然后选择“Output”选项下面的“Selectfolderforobjects”, 然后选择目录为我们上面新建的OBJ目录。同时将下方的三个选项框都勾上,这里说明一下步骤4的意义。CreateHEXFile选项选上是要求编译之后生成HEX文件。BrowseInformation选项选上是方便我们查看工程中的一些函数变量定义。,16) 打开工程USER下面的main.c,复制 17) 编译,下载,测试,常用头文

23、件说明,1. core_cm3.c/core_cm3.h 该文件是内核访问层的源文件和头文件,查看其中的代码多半是使用汇编语言编写的。 2. stm32f10 x.h 该文件是外设访问层的头文件,该文件是最重要的头文件之一。定义了 CPU是哪种容量的 CPU,中断向量等等。除了这些该头文件还定义了和外设寄存器相关的结构体 3. system_stm32f10 x.c/h 该头文件也可以称为外设访问层的头文件和源文件。在该文件中可以定义系统的时钟频率,定义低速时钟 总线和高速时钟总线的频率,其中最关键的函数就是SystemInit()了。总之这两个文件是新固件库的重点,有了它也大大简化了使用st

24、m32的初始化工作。 4. stm32f10 x_conf.h 这个文件和V2版本的库的内容是一样的,需要使用哪些外设就取消哪些外设的注释。例如需要使用GPIO功能,但不使用SPI功能,就可以这样操作。 5. stm32f10 x_it.c/h 这两个文件包含了stm32中断函数,在源文件和头文件中并没有把所有的中断入口函数都写出来,而 只写了ARM内核的几个异常中断,其他的中断函数需要用户自己编写。,STM32的GPIO,想要控制LED灯,当然是通过控制STM32芯片的I/O引脚电平的高低来实现。在STM32芯片上,I/O引脚可以被软件设置成各种不同的功能,如输入或输出,所以被称为GPIO(

25、General-purposeI/O)。而GPIO引脚又被分为GPIOA、GPIOBGPIOG不同的组,每组端口分为015,共16个不同的引脚,对于不同型号的芯片,端口的组和引脚的数量不同,具体请参考相应芯片型号的datasheet。 于是,控制LED的步骤就自然整理出来了: 1.GPIO端口引脚多-就要选定需要控制的特定引脚 2.GPIO功能如此丰富-配置需要的特定功能 3.控制LED的亮和灭-设置GPIO输出电压的高低,要控制GPIO端口,就要涉及到控制相关的寄存器。这时我们就要查一查与GPIO相关的寄存器了,可以通过STM32参考手册来查看 图中的7个寄存器,相应的功能在文档上有详细的说

26、明。可以分为以下4类,其功能简要概括如下: 1.配置寄存器:选定GPIO的特定功能,最基本的如:选择作为输入还是 输出端口。 2.数据寄存器:保存了GPIO的输入电平或将要输出的电平。 3.位控制寄存器:设置某引脚的数据为1或0,控制输出的电平。4.锁定寄存器:设置某锁定引脚后,就不能修改其配置。,关于寄存器名称上标号x的意义,如:GPIOx_CRL、GPIOx_CRH,这个x的取值可以为图中括号内的值(AE),表示这些寄存器也跟GPIO一样,也是分组的。也就是说,对于端口GPIOA和GPIOB,它们都有互不相干的一组寄 存器,如控制GPIOA的寄存器名为GPIOA_CRL、GPIOA_CRH

27、等,而控制GPIOB的则是不同的、被命名为GPIOB_CRL、GPIOB_CRH等寄存器。,STM32的GPIO操作流程,端口配置寄存器,对于GPIO端口,每个端口有16个引脚,每个引脚的模式由寄存器的4个位控制,每四位又分为两位控制引脚配置(CNFy1:0),两位控制引脚的模式及最高速度(MODEy1:0),其中y表示第y个引脚。这个图是GPIOx_CRH寄存器的说明,配置GPIO引脚模式的一共有两个寄存器,CRH是高寄存器,用来配置高8位引脚:pin8pin15。还有一个称为CRL寄存器,如果我们要配置pin0pin7引脚,则要在寄存器CRL中进行配置。 举例说明对CRH的寄存器的配置:当

28、给GPIOx_CRH寄存器的第28至29 位设置为参数“11”,并在第30至31位设置为参数“00”,则把x端口第15个引脚的模式配置成了“输出的最大速度为50MHz的通用推挽输出模式、”,其它引脚可通过其GPIOx_CRH或GPIOx_CRL的其它寄存器位来配置。至于x端口的x是指端口GPIOA还是GPIOB还要具体到不同的寄存器基址,要控制引脚电平高低,需要对寄存器进行对应的操作,端口位设置/清除寄存器,由寄存器说明图可知,一个引脚y的输出数据由GPIOx_BSRR寄存器位的2个位来控制分别为BRy(BitResety)和BSy(BitSety),BRy位用于写1清零,使引脚输出低电平,B

29、Sy位用来写1置1,使引脚输出高电平。而对这两个位进行写零都是无效的。(还可以通过设置寄存器ODR来控制引脚的输出。) 例如:对x端口的寄存器GPIOx_BSRR的第0位(BS0)进行写1,则x端口的第0引脚被设置为1,输出高电平,若要令第0引脚再输出低电平,则需要向GPIOx_BSRR的第16位(BR0)写1。,地址映射,所谓地址映射,就是将芯片上的存储器甚至I/O等资源与地址建立一一对应的关系。如果某地址对应着某寄存器,我们就可以运用c语言的指针来寻址并修改这个地址上的内容,从而实现修改该寄存器的内容。 Cortex-M3有32根地址线,所以它的寻址空间大小为232bit=4GB。ARM公

30、司设计时,预先把这4GB的寻址空间大致地分配好了。它把地址从0 x40000000至0 x5FFFFFFF(512MB)的地址分配给片上外设。通过把片上外设的寄存器映射到这个地址区,就可以简单地以访问内存的方式,访问这些外设的寄存器,从而控制外设的工作。结果,片上外设可以使用C语言来操作。,M3存储器映射,为什么需要使用固件库,stm32f10 x.h这个文件中重要的内容就是把STM32的所有寄存器进行地址映射。 stm32f10 x.h像一个大表格,我们在使用的时候就是通过宏定义进行类似查表的操作,大家想像一下没有这个文件的话,我们要怎样访问STM32的寄存器?有什么缺点? 不进行这些宏定义

31、的缺点有: 1、地址容易写错 2、我们需要查大量的手册来确定哪个地址对应哪个寄存器 3、看起来还不好看,且容易造成编程的错误,效率低,影响开发进度 当然,这些工作都是由ST的固件工程师来完成的,只有设计M3的人才是最了解M3的,才能写出完美的库。 在这里我们以外接了LED灯的外设GPIOC为例,在这个文件中有这样的一系列宏定义:#defineGPIOC_BASE(APB2PERIPH_BASE+0 x1000) #defineAPB2PERIPH_BASE(PERIPH_BASE+0 x10000) #definePERIPH_BASE(uint32_t)0 x40000000) 这几个宏定义

32、是从文件中的几个部分抽离出来的,具体的可参考stm32f10 x.h源码。,外设基地址 首先看到PERIPH_BASE这个宏,宏展开为0 x40000000,并把它强制转换为uint32_t的32位类型数据,这是因为地STM32的地址是32位的,是不是觉得0 x40000000这个地址很熟?是的,这个是Cortex-M3核分配给片上外设的从0 x40000000至0 x5FFFFFFF的512MB寻址空间中的第一个地址,我们把0 x40000000称为外设基地址。 总线基地址 接下来是宏APB2PERIPH_BASE,宏展开为PERIPH_BASE(外设基地 址)加上偏移地址0 x10000,

33、即指向的地址为0 x40010000。这个 APB2PERIPH_BASE宏是什么地址呢?STM32不同的外设是挂载在不同的总线上的,见图。有AHB总线、APB2总线、APB1总线,挂载在这些总线上的外设有特定的地址范围。,STM32总线结构,其中像GPIO、串口1、ADC及部分定时器是挂载这个被称为APB2的总线上,挂载到APB2总线上的外设地址空间是从0 x40010000至地址0 x40013FFF。这里的第一个地址,也就是0 x40010000,被称为APB2PERIPH_BASE(APB2总线外设的基地址)。 而APB2总线基地址相对于外设基地址的偏移量为0 x10000个地址,即为

34、APB2相对外设基地址的偏移地址。,STM32总线地址,由这个表我们可以知道,stm32f10 x.h这个文件中必然还有以下的宏: #defineAPB1PERIPH_BASEPERIPH_BASE 因为偏移量为零,所以APB1的地址直接就等于外设基地址,寄存器组基地址 最后到了宏GPIOC_BASE,宏展开为APB2PERIPH_BASE(APB2总线外设的基地址)加上相对APB2总线基地址的偏移量0 x1000得到了GPIOC端口的寄存器组的基地址。这个所谓的寄存器组又是什么呢?它包括什么寄存器? 细看stm32f10 x.h文件,我们还可以发现以下类似的宏: 1.#defineGPIOA

35、_BASE(APB2PERIPH_BASE+0 x0800) 2.#defineGPIOB_BASE(APB2PERIPH_BASE+0 x0C00) 3.#defineGPIOC_BASE(APB2PERIPH_BASE+0 x1000) 4.#defineGPIOD_BASE(APB2PERIPH_BASE+0 x1400) 除了GPIOC寄存器组的地址,还有GPIOA、GPIOB、GPIOD的地址,并且这些地址是不一样的。,注意到前面端口配置寄存器说明中有一个偏移地址:0 x04,这里的偏移地址的是相对哪个地址的偏移呢?下面进行举例说明。 对于GPIOC组的寄存器,GPIOC含有的端口配

36、置高寄存器(GPIOC_CRH)寄存器地址为:GPIOC_BASE+0 x04。 假如是GPIOA组的寄存器,则GPIOA含有的端口配置高寄存器 (GPIOA_CRH)寄存器地址为:GPIOA_BASE+0 x04。 也就是说,这个偏移地址,就是该寄存器相对所在寄存器组基地址的偏移量。 于是,我们可能会想,大概这个文件含有一个类似如下的宏(当初野火也是这么想的): 1.#defineGPIOC_CRH(GPIOC_BASE+0 x04) 这个宏,定义了GPIOC_CRH寄存器的具体地址,然而,在stm32f10 x.h文件中并没有这样的宏。ST公司的工程师采用了更巧妙的方式来确定这些地址,ST

37、M32库对寄存器的封装,ST的工程师用结构体的形式,封装了寄存器组。在stm32f10 x.h文件中,有以下代码:#defineGPIOA(GPIO_TypeDef*)GPIOA_BASE) #defineGPIOB(GPIO_TypeDef*)GPIOB_BASE) #defineGPIOC(GPIO_TypeDef*)GPIOC_BASE) 有了这些宏,我们就可以定位到具体的寄存器地址,在这里发现了一个陌生的类型GPIO_TypeDef,追踪它的定义,可以在stm32f10 x.h文件中找到如下代码: typedefstruct _IOuint32_tCRL; _IOuint32_tCRH

38、; _IOuint32_tIDR; _IOuint32_tODR; _IOuint32_tBSRR; _IOuint32_tBRR; _IOuint32_tLCKR; GPIO_TypeDef; 其中 _IO 也是一个ST库定义的宏,宏定义如下: #define _O volatile /*! defines write only permissions */ #define _IO volatile /*! defines read / write permissions */,回到GPIO_TypeDef这段代码,这个代码用typedef关键字声明了名为GPIO_TypeDef的结构体类型

39、,结构体内又定义了7个_IOuint32_t类型的变量。这些变量每个都为32位,也就是每个变量占内存空间4个字节。在c语言中,结构体内变量的存储空间是连续的,也就是说假如我们定义了一个GPIO_TypeDef,这个结构体的首地址(变量CRL的地址)若为0 x4001 1000,那么结构体中第二个变量(CRH)的地址即为0 x40011000+0 x04,加上的这个0 x04,正是代表4个字节地址的偏移量。 这个0 x04偏移量,正是GPIOx_CRH寄存器相对于所在寄存器组的偏移地址,见图5-9。同理,GPIO_TypeDef结构体内其它变量的偏移量,也和相应的寄存器偏移地址相符。于是,只要我

40、们匹配了结构体的首地址,就可以确定各寄存器的具体地址了。,有了这些准备,就可以分析本小节的第一段代码了:#defineGPIOA(GPIO_TypeDef*)GPIOA_BASE) #defineGPIOB(GPIO_TypeDef*)GPIOB_BASE) #defineGPIOC(GPIO_TypeDef*)GPIOC_BASE) GPIOA_BASE在前面已解析,是一个代表GPIOA组寄存器的基地址。(GPIO_TypeDef*)在这里的作用则是把GPIOA_BASE地址转换为 GPIO_TypeDef结构体指针类型。 有了这样的宏,以后我们写代码的时候,如果要修改GPIO的寄存器,就可

41、以用以下的方式来实现。代码分析见注释。GPIO_TypeDef*GPIOx;/定义一个GPIO_TypeDef型结构体指针GPIOx GPIOx=GPIOA;/把指针地址设置为宏GPIOA地址 GPIOx-CRL=0 xffffffff;/通过指针访问并修改GPIOA_CRL寄存器,STM32的时钟系统,STM32芯片为了实现低功耗,设计了一个功能完善但却非常复杂的时钟系统。普通的MCU,一般只要配置好GPIO的寄存器,就可以使用了,但STM32还有一个步骤,就是开启外设时钟. 从时钟频率来说,又分为高速时钟和低速时钟,高速时钟是提供给芯片主体的主时钟,而低速时钟只是提供给芯片中的RTC(实时

42、时钟)及独立看门狗使用。 从芯片角度来说,时钟源分为内部时钟与外部时钟源,内部时钟是在芯片内部RC振荡器产生的,起振较快,所以时钟在芯片刚上电的时候,默认使用内部高速时钟。而外部时钟信号是由外部的晶振输入的,在精度和稳定性上都有很大优势,所以上电之后我们再通过软件配置,转而采用外部时钟信号。,STM32的时钟系统,STM32有以下4个时钟源: 高速外部时钟(HSE):以外部晶振作时钟源,晶振频率可取范围为416MHz,我们一般采用8MHz的晶振。 高速内部时钟(HSI):由内部RC振荡器产生,频率为8MHz,但不稳定。 低速外部时钟(LSE):以外部晶振作时钟源,主要提供给实时时钟模块,所以一

43、般采用32.768KHz。一般M3实验板上用的是32.768KHz,6p负载规格的晶振。 低速内部时钟(LSI):由内部RC振荡器产生,也主要提供给实时时钟模块,频率大约为40KHz。,高速外部时钟(HSE),1、 从左端的OSC_OUT和OSC_IN开始,这两个引脚分别接到外部晶振的两端。 2、 8MHz的时钟遇到了第一个分频器PLLXTPRE(HSEdividerforPLLentry),在这个分频器中,可以通过寄存器配置,选择它的输出。它的输出时钟可以是对输入时钟的二分频或不分频。本例子中,我们选择不分频,所以经过PLLXTPRE后,还是8MHz的时钟。 3、 8MHz的时钟遇到开关PL

44、LSRC(PLLentryclocksource),我们可以选择其输出,输出为外部高速时钟(HSE)或是内部高速时钟(HSI)。这里选择输出为HSE,接着遇到锁相环PLL,具有倍频作用,在这里我们可以输入倍频因子PLLMUL(PLLmultiplication factor)。经过PLL的时钟称为PLLCLK。倍频因子我们设定为9倍频,也就是说,经过PLL之后,我们的时钟从原来8MHz的HSE变为72MHz的PLLCLK。,4、 紧接着又遇到了一个开关SW,经过这个开关之后就是STM32的系统时钟(SYSCLK)了。通过这个开关,可以切换SYSCLK的时钟源,可以选择为HSI、PLLCLK、H

45、SE。我们选择为PLLCLK时钟,所以SYSCLK就为72MHz了。 5、 PLLCLK在输入到SW前,还流向了USB预分频器,这个分频器输出为USB外设的时钟(USBCLK)。 6、 回到SYSCLK,SYSCLK经过AHB预分频器,分频后再输入到其它外设。如输出到称为HCLK、FCLK的时钟,还直接输出到SDIO外设的SDIOCLK时钟、存储器控制器FSMC的FSMCCLK时钟,和作为APB1、APB2的预分频器的输入端。 7、 GPIO外设是挂载在APB2总线上的,APB2的时钟是APB2预分频器的输出,而APB2预分频器的时钟来源是AHB预分频器。因此,把APB2预分频器设置为不分频,

46、那么我们就可以得到GPIO外设的时钟也等于HCLK,为72MHz了。,HCLK、FCLK、PCLK1、PCLK2,经过一系列的倍频、分频后得到了几个与我们开发密切相关的时钟。 SYSCLK:系统时钟,STM32大部分器件的时钟来源。主要由AHB预分频器分配到各个部件。 HCLK:由AHB预分频器直接输出得到,它是高速总线AHB的时钟信号,提供给存储器,DMA及cortex内核,是cortex内核运行的时钟,cpu主频就是这个信号,它的大小与STM32运算速度,数据存取速度密切相关。 FCLK:同样由AHB预分频器输出得到,是内核的“自由运行时钟”。“自由”表现在它不来自时钟HCLK,因此在HC

47、LK时钟停止时FCLK也继续运行。它的存在,可以保证在处理器休眠时,也能够采样和到中断和跟踪休眠事件,它与HCLK互相同步。 PCLK1:外设时钟,由APB1预分频器输出得到,最大频率为36MHz,提供给挂载在APB1总线上的外设。 PCLK2:外设时钟,由APB2预分频器输出得到,最大频率可为 72MHz,提供给挂载在APB2总线上的外设。,代码解释:初始化结构体GPIO_InitTypeDef类型,GPIO_InitTypeDefGPIO_InitStructure;这是利用库,定义了一个名为GPIO_InitStructure的结构体,结构体类型为GPIO_InitTypeDef。追踪其

48、定义原型如下,位于stm32f10 x_gpio.h文件中 typedef struct uint16_tGPIO_Pin;/*指定将要进行配置的GPIO引脚*/ GPIOSpeed_TypeDefGPIO_Speed; /*指定GPIO引脚可输出的最高频率*/ GPIOMode_TypeDefGPIO_Mode;/*指定GPIO引脚将要配置成的工作状态*/ GPIO_InitTypeDef;,uint16_t类型的GPIO_Pin为我们将要选择配置的引脚,在stm32f10 x_gpio.h文件中有如下宏定义: #define GPIO_Pin_0 (uint16_t)0 x0001) /*

49、!Pin0selected*/ #define GPIO_Pin_1 (uint16_t)0 x0002) /*!Pin1selected*/ #define GPIO_Pin_2 (uint16_t)0 x0004) /*!Pin2selected*/ #define GPIO_Pin_3 (uint16_t)0 x0008) /*!Pin3selected*/ 这些宏的值,就是允许我们给结构体成员GPIO_Pin赋的值,如我们给GPIO_Pin赋值为宏GPIO_Pin_0,表示我们选择了GPIO端口的第0个引脚,在后面会通过一个函数把这些宏的值进行处理,设置相应的寄存器,实现我们对GPIO端口的配置。,GPIOSpeed_TypeDef 和GPIOMode_TypeDef又是两个库定义的新类型,GPIOSpeed_TypeDef原型如下: typedef enum GPIO_Speed_10MHz=1,/枚举常量,值为1,代表输出速率最高为10MHz GPIO_Speed_2MHz,/对不赋值的枚举变量,自动加1,此常量值为2 GPIO_Speed_50MHz/常量值为3 GPIOSpeed_TypeDe

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论