收藏 分享(赏)

第7章 CMSIS架构与STM32库开发方式6H.ppt

上传人:精品资料 文档编号:9883481 上传时间:2019-09-14 格式:PPT 页数:61 大小:2.35MB
下载 相关 举报
第7章 CMSIS架构与STM32库开发方式6H.ppt_第1页
第1页 / 共61页
第7章 CMSIS架构与STM32库开发方式6H.ppt_第2页
第2页 / 共61页
第7章 CMSIS架构与STM32库开发方式6H.ppt_第3页
第3页 / 共61页
第7章 CMSIS架构与STM32库开发方式6H.ppt_第4页
第4页 / 共61页
第7章 CMSIS架构与STM32库开发方式6H.ppt_第5页
第5页 / 共61页
点击查看更多>>
资源描述

1、Embedded System Development,聊城大学 理工学院 曹银杰 ,嵌入式系统与应用,第7章 CMSIS架构与STM32库开发方式,7.1 STM32库简介 7.2 STM32结构及库层次关系 7.3 库文件及使用简介 7.4 GPIO 7.5 stm32f10x.h中GPIO代码剖析 7.6 GPIO控制LED灯实验 7.7 时钟设置与开启外设时钟,7.1 STM32库简介,STM32外设资源丰富,寄存器的数量多、设置复杂度高,直接配置寄存器方式开发程序效率低。 STM32库是由ST公司针对STM32提供的函数接口,即API (Application Program Int

2、erface), 库是架设在寄存器与用户驱动层之间的代码,向下处理与寄存器直接相关的配置,向上为用户提供配置寄存器的接口。,STM32库简介,开发者可调用这些函数接口来配置STM32的寄存器,开发快速,易于阅读,维护成本低等优点。 事实上,库函数的底层实现恰恰是直接配置寄存器方式的最佳例子,想深入了解芯片是如何工作的话,只要追踪到库的最底层实现就能理解。 想修炼C语言,就从ST的库开始。,7.2 STM32结构及库层次关系,解决不同的芯片厂商生产的Cortex微控制器软件的兼容性问题,ARM与芯片厂商建立了一个软件抽象层。CMSIS标准:Cortex MicroController Softw

3、are Interface Standard。,CMSIS架构,STM32结构及库层次关系,CMSIS标准中最主要的为CMSIS核心层,它包括了: 内核函数层:其中包含用于访问内核寄存器的名称、地址定义,主要由ARM公司提供。 设备外设访问层:提供了片上的核外外设的地址和中断定义,主要由芯片生产商提供可见CMSIS层位于硬件层与操作系统或用户层之间,提供了与芯片生产商无关的硬件抽象层,可以为接口外设、实时操作系统提供简单的处理器软件接口,屏蔽了硬件差异,这对软件的移植是有极大的好处的。 STM32的库,就是按照CMSIS标准建立的。,7.3 库文件及使用简介,新建工程-选择芯片后 选择运行环境

4、、用的库、驱动文件、RTX等编译时自动添加其他用的库文件,库文件及使用简介,ARM公司提供的:如core_cm3.h、及core_前缀的头文件,核内设备函数层,进入M3内核的接口。stdin.h 头文件,这是一个ANSI C 文件,是独立于处理器之外的,就像我们熟知的C语言头文件 stdio.h 文件一样。misc.h和misc.c是和CM3内核有关的NVIC和SysTick的驱动代码。自行添加到工程。ST公司提供的:stm32f10x.h 重要文件,定义寄存器地址、寄存器数据结构、中断向量表。stm32f10x_adc.c、stm32f10x_adc.h,针对模数转换(ADC)外设,还有很多

5、其他设备外设的驱动程序。每个外设对应一个 .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文件提供了两个函数和一个全局变量,库文

6、件及使用简介,stm32f10x.h头文件中重要的内容就是把STM32的所有寄存器进行地址映射。 如同51单片机的头文件一样,stm32f10x.h像一个大表格,我们在使用的时候就是通过宏定义进行类似查表的操作。 没有这个文件的话,怎样访问STM32的寄存器,有什么缺点? 1、需要查手册来确定哪个地址对应哪个寄存器。 2、地址易写错、可读性差、易出错、开发效率低。,库文件及使用简介,库函数,就是STM32的库文件中为我们编写好的函数接口,调用这些库函数,就可以对STM32进行配置。我们可以不知道库函数是如何实现的,但必须要知道函数的功能、可传入的参数及其意义、和函数的返回值。 库函数很多,学会

7、查阅库帮助文档就行! 库帮助文档:stm32f10x_stdperiph_lib_um.chm 层层打开文档的目录标签即可。 在用库函数的地方,直接从库帮助文档复制即可。,思考题:,1、没有stm32f10x.h头文件的话,怎样访问STM32的寄存器,有什么缺点? 2、从STM32库的实现原理上解答 库到底是什么?为什么要用库?用库函数与直接配置寄存器的区别等问题。,7.4 GPIO,GPIO(General Purpose I/O)通用型输入/输出,主要用于需要用到数字量输入/输出的场合。 如: 继电器、 LED、蜂鸣器等的控制; 传感器状态、高低电平等信息的输入等。,1、GPIO简介,大部

8、分GPIO为推挽输出,具有完整I2C功能的是开漏结构; 正常拉出灌入电流为4mA,短时间极限值40mA; 管脚可承受最大5V的输入电压。 GPIO寄存器位于AHB总线上,可以进行高性能的 CPU快速访问,支持Cortex-M3位带操作。 GPIO允许进行DMA数据操作。,GPIO简介,GPIO引脚又被分为GPIOA、GPIOBGPIOG不同的组,每组端口分为015,共16个不同的引脚,不同芯片的端口组数不同。GPIO结构图:,端口配置寄存器,GPIO简介,I/O引脚可通过端口配置寄存器设置成不同的功能。 四种输入模式(结构图上半部分): 上拉输入与下拉输入:与VDD相连的为上拉电阻,与VSS相

9、连的为下拉电阻。再经施密特触发器就把信号转化为0、1存储在输入数据寄存器。 浮空输入:不接上拉与下拉电阻,直接由触发器输入,由于其输入阻抗较大,一般把这种模式用于标准的通讯协议如I2C、USART的接收端。 模拟输入:把电压信号直接传送到片上外设模块,如ADC。,GPIO简介,结构图下半部分为输出模式结构:推挽输出模式:在输出高电平时,P-MOS导通,低电平时,N-MOS管导通。 开漏输出模式:输出0时为低电平,1为高阻状态。 在使用任何一种开漏模式,都需要接上拉电阻。,GPIO简介,GPIO都可配置为中断功能,并可设置为上升沿、下降沿或边沿触发。,GPIO中断还具 有掉电唤醒功能,2、GPI

10、O端口配置寄存器,端口配置低寄存器GPIOx_CRL (配置07引脚),端口配置高寄存器GPIOx_CRH (配置815引脚) (x=AG)。 可将I/O口配置为输入、输出或模拟模式;PIOx_CRL复位值:4444 4444h,偏移地址:00h。 每个引脚的模式由寄存器的4个位控制,又分引脚配置(CNFy1:0),引脚的模式(MODEy1:0),其中y表示第y个引脚。,GPIOx_CRL,GPIO端口配置寄存器,例:CRH高寄存器的配置,PIOx_CRH 复位值:4444 4444h,偏移地址:04h。例:GPIOx_CRH寄存器的第28至29位设置为11,并在第30至31位设置为00 答:

11、则把x端口第15个引脚的模式配置成了:输出的最大速度为50MHz的 通用推挽输出模式。,3、端口输入数据寄存器GPIOx_IDR,端口输入数据寄存器(GPIOx_IDR) (x=AE) 复位值: 4444 4444h ,地址偏移:08h高位31:16保留,始终读为0。 IDRx15:0:端口输入数据(x = 015) 这些位为只读并只能以字的形式读出。读出的值为对应I/O口的状态。,4、端口输出数据寄存器GPIOx_ODR,端口输出数据寄存器(GPIOx_ODR) (x=AE)设置I/O口的方向输入还是输出。 复位值: 4444 4444h ,地址偏移:0Ch高位31:16保留,始终为0。 O

12、DRx15:0:端口输出数据方向(x = 015) 这些位可读可写并只能以字的形式操作。 通过GPIOx_BSRR(x = AE),可以分别地对各个ODR位进行独立的置位/清零。,5、端口置位/清零寄存器GPIOx_BSRR,端口置位/清零寄存器(GPIOx_BSRR) (x=AE) 复位值: 4444 4444h ,地址偏移:10h,6、端口位复位寄存器(GPIOx_BRR),端口位复位寄存器(GPIOx_BRR) (x=AE) 复位值: 4444 4444h ,地址偏移:14h,7、端口配置锁定寄存器GPIOx_LCKR,端口配置锁定寄存器(GPIOx_LCKR) (x=AE) 复位值:

13、4444 4444h ,地址偏移:14h 当执行正确的写序列设置了位16(LCKK)时,该寄存器用来锁定端口位的配置。 位15:0用于锁定GPIO端口的配置。在规定的写入操作期间,不能改变LCKP15:0。 当对相应的端口位执行了LOCK序列后,在下次系统复位之前将不能再更改端口位的配置。 每个锁定位锁定控制寄存器(CRL, CRH)中相应的4个位。,例:,要控制引脚电平高低,需要对寄存器进行什么操作? 一个引脚y的输出数据由GPIOx_BSRR寄存器位的2个位来控制分别为BRy (Bit Reset y)和BSy (Bit Set y),BRy位用于写1清零,使引脚输出低电平;BSy位用来写

14、1置1,使引脚输出高电平。,8、GPIO输入输出演示,GPIOx_IDR,GPIO输入,GPIO输出,1,高电平,1,输出操作流程,输入操作流程,1,GPIOx_BSRR,7.5 stm32f10x.h库中GPIO代码剖析,以外设GPIOC为例,文件中包含如下宏定义: #define GPIOC_BASE (APB2PERIPH_BASE + 0x1000) #define APB2PERIPH_BASE (PERIPH_BASE + 0x10000) #define PERIPH_BASE (uint32_t)0x40000000) 首先看外设基地址 PERIPH_BASE这个宏,宏展开为0

15、x4000 0000,并把它强制转换为uint32_t类型数据; 总线基地址宏APB2PERIPH_BASE指向地址0x4001 0000; 最后到了宏GPIOC_BASE为APB2PERIPH_BASE加上偏移量0x1000得到了GPIOC端口的寄存器组的基地址。,stm32f10x.h中GPIO代码剖析,stm32f10x.h文件,还可以发现以下类似的宏:#define GPIOA_BASE (APB2PERIPH_BASE + 0x0800) #define GPIOB_BASE (APB2PERIPH_BASE + 0x0C00) #define GPIOC_BASE (APB2PER

16、IPH_BASE + 0x1000) #define GPIOD_BASE (APB2PERIPH_BASE + 0x1400)GPIOA、GPIOB、GPIOC、GPIOD寄存器组的起始地址,都对应着独立的一组寄存器。,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 GPIOA (GPIO_TypeDef *) G

17、PIOA_BASE) #define GPIOB (GPIO_TypeDef *) GPIOB_BASE) (GPIO_TypeDef *) 把GPIOA_BASE 地址转换为GPIO_TypeDef 结构体指针类型。,对每个GPIOx是用结构封装了寄存器组,stm32f10x.h中代码:,GPIO_TypeDef ,这个结构体的首地址(变量CRL的地址)若为0x4001 1000, 那么结构体中第二个变量(CRH)地址为0x4001 1000 +0x04 ,加上的这个0x04 ,正是4字节地址偏移量。,stm32f10x.h中GPIO代码剖析,有了这样的宏,就可用以下方式来修改GPIO寄存器

18、: GPIO_TypeDef * GPIOx; /定义一个GPIO_TypeDef型结构体指针GPIOx GPIOx = GPIOA;/把指针地址设置为宏GPIOA地址 GPIOx-CRL = 0xffffffff; /通过指针访问并修改GPIOA_CRL寄存器 通过类似的方式,我们就可以给具体的寄存器写上适当的参数,控制STM32了。 这只是库开发的皮毛,库提供了更简单的开发方式。,GPIO,1. 配置寄存器:选定GPIO的特定功能,最基本的如:选择作为输入还是输出端口。 2. 数据寄存器:保存了GPIO的输入电平 或 将要输出的电平。 3. 位控制寄存器:设置某引脚的数据 为1或0,控制输

19、出的电平。 4. 锁定寄存器:设置某锁定引脚后,就不能修改其配置。,C语言程序举例:TESTc.C,#define uint32 unsigned int #define N 10 uint32 sum; /使用加法运算来计算1+2+3+.+(N-1)+N的值。(N0) int main(void) uint32 i; sum = 0;for(i=0; i=N; i+) sum += i; ,GPIO库函数,7.6 LED流水灯实验,想要控制LED灯,当然是通过控制STM32芯片的I/O引脚电平的高低来实现。,LED流水灯实验,LED流水灯实验,1. GPIO端口引脚多 就要选定需要控制的特定

20、引脚 2. GPIO功能如此丰富 配置需要的特定功能 3. 控制LED的亮和灭 设置GPIO输出电压的高低 与GPIO相关的寄存器了,可以通过STM32参考手册来查看,LED流水灯实验,LED实验中用到了RCC跟GPIO这两个外设。环境配置如图: main.c led.c led.h,Led流水灯主程序:main.c,#include “led.h“ void Delay(_IO uint32_t nCount) /简单延时函数 for(; nCount != 0; nCount-); int main(void) LED_GPIO_Config(); while (1) LED1( ON )

21、; Delay(0x0FFFFF);LED1( OFF ); LED2( ON );Delay(0x0FFFFF);LED2( OFF ); LED3( ON ); Delay(0x0FFFFF);LED3( OFF ); ,初始化LED函数 led.c,#include “led.h“ #include “stm32f10x_gpio.h“ #include “stm32f10x_rcc.h“ void LED_GPIO_Config(void) /*利用库定义一个GPIO_InitTypeDef类型的结构体*/ GPIO_InitTypeDef GPIO_InitStructure;/*开

22、启GPIOC的外设时钟*/ RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOC, ENABLE); /*选择要控制的GPIOC引脚GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3| GPIO_Pin_4 | GPIO_Pin_5; /*设置引脚模式为通用推挽输出*/ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;,初始化LED函数 led.c,/*设置引脚速率为50MHz */ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

23、 /*调用库函数,初始化GPIOC*/ GPIO_Init(GPIOC, 个函数LED_GPIO_Config()实现了所有为点亮led的配置,led.h,#ifndef _LED_H #define _LED_H #include “stm32f10x.h“ /* the macro definition to trigger the led on or off * 1 - off* 0 - on*/ #define ON 0 #define OFF 1 /* 带参宏,可像内联函数一样使用*/ #define LED1(a) if (a) GPIO_SetBits(GPIOC,GPIO_Pi

24、n_3); else GPIO_ResetBits(GPIOC,GPIO_Pin_3),led.h续,#define LED2(a) if (a) GPIO_SetBits(GPIOC,GPIO_Pin_4); else GPIO_ResetBits(GPIOC,GPIO_Pin_4) #define LED3(a) if (a) GPIO_SetBits(GPIOC,GPIO_Pin_5); else GPIO_ResetBits(GPIOC,GPIO_Pin_5) void LED_GPIO_Config(void); #endif /* _LED_H */ 在编译过程,编译器会把带参宏展

25、开,在相应的位置替换为宏展开代码。 其中的反斜杠符号“ ”叫做续行符,后面不能有空格、注释等,led用到stm32f10x_gpio.h库的结构、宏定义,1、GPIO_InitTypeDef结构,引脚初始化的结构,2、GPIO_Pin_x 引脚为uint16_t类型,宏定义:,1. #define GPIO_Pin_0 (uint16_t)0x0001) /*!Pin 0 selected */ 2. #define GPIO_Pin_1 (uint16_t)0x0002) /*!Pin 1 selected */ 3. #define GPIO_Pin_2 (uint16_t)0x0004)

26、 /*!Pin 2 selected */ 4. #define GPIO_Pin_3 (uint16_t)0x0008) /*!Pin 3 selected */,例:GPIO_Pin_0 (0000 0000 0000 0001)BGPIO_Pin_1 (0000 0000 0000 0010)B,led用到stm32f10x_gpio.h库的结构、宏定义,3、GPIOSpeed_TypeDef定义GPIO的输出速率:typedef enum GPIO_Speed_10MHz = 1,/枚举常量值1,对应10MHz GPIO_Speed_2MHz, /常量值为2,对应2MHz GPIO_S

27、peed_50MHz /常量值为3,对应50MHzGPIOSpeed_TypeDef;,GPIO_Speed_10MHz 对应(0001)B GPIO_Speed_2MHz 对应(0010)B GPIO_Speed_50MHz 对应(0011)B Speed控制参数,它的宏展开低2位的值,正好符合寄存器MODEy中2位的控制值。 直接把这个参数写入CRL、CRH配置寄存器的MODEy位,其中y由GPIO_Pin参数确定第几引脚。,led用到stm32f10x_gpio.h库的结构、宏定义,4、GPIOMode_TypeDef结构定义GPIO引脚的功能:typedef enum GPIO_Mod

28、e_AIN = 0x0, /模拟输入模式 GPIO_Mode_IN_FLOATING = 0x04, /浮空输入模式 GPIO_Mode_IPD = 0x28, /下拉输入模式 GPIO_Mode_IPU = 0x48, /上拉输入模式GPIO_Mode_Out_OD = 0x14, /开漏输出模式 GPIO_Mode_Out_PP = 0x10, /通用推挽输出模式 GPIO_Mode_AF_OD = 0x1C, /复用功能开漏输出 GPIO_Mode_AF_PP = 0x18 /复用功能推挽输出 GPIOMode_TypeDef;,用于初始化的库函数GPIO_Init(),通过查找库帮助文

29、档获得,Error: L6218E:,Error: L6218E: Undefined symbol assert_param (referred from stm32f10x_gpio.o). 断言机制函数assert_param,STM32的函数:assert_param(IS_GPIO_ALL_PERIPH(GPIOx); 刚开始学习的时候都遇到编译不过去的问题, 通过在文件中添加USE_STDPERIPH_DRIVER来解决的:,error 65:,创建一个STM32F103VE核的项目 error 65: access violation at 0x40021000 : no rea

30、d permission 是Debug里面的设置有缺陷,不会自动匹配: Dialog DLL:DCM3.DLL Parameter:-pCM3 应手动改为: Dialog DLL:DARMSTM.DLL Parameter:-pSTM32F103VE,逻辑分析窗口使用,再点击Setup,输入LED灯对应的三个信号PORTB.0、PORTF.7、PORTF.8;,Display Type选择bit,然后单击Close关闭该对话框;,逻辑分析窗口使用,点击运行按钮。运行一段时间之后,点击停止按钮,暂停仿真回到逻辑分析窗口, 可通过Zoom里面的In按钮来放大波形,通过Out按钮来缩小波形,或者按A

31、ll显示全部波形。,7.7 时钟设置与开启外设时钟,外设初始化后,必须要开启外设时钟。 开启外设时钟之前,首先要配置好系统时钟SYSCLK 。 在startup_stm32f10x_hd.s启动文件中,调用main函数之前就先调用了SystemInit()函数,就是设置系统时钟SYSCLK:时钟来源、倍频、分频等控制参数。,这个函数的定义在system_stm32f10x.c文件之中。,时钟设置与开启外设时钟,void SystemInit (void)函数的执行流程是先将与配置时钟相关的寄存器都复位为默认值,复位寄存器后,调用了另外一个函数SetSysClock(),其代码:,在system

32、_stm32f10x.c文件的开头,有条件编译定义。选择相应的时钟。,时钟设置与开启外设时钟,GPIO所用的时钟PCLK2我们采用默认值,也为72MHz。 开启和关闭外设时钟也有封装好的库函数 RCC_APB2PeriphClockCmd()。在led.c文件中调用了这个函数。 /*开启GPIOC外设时钟,参数DISABLE为关闭*/ RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOC, ENABLE); 如用到I/O引脚复用功能,还要开启其复用功能时钟。 如GPIOC的Pin4还可作为ADC1的输入引脚,把它作为ADC1来用,除开启GPIOC时钟,还要开

33、启ADC1时钟:RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOC, ENABLE); RCC_APB2PeriphClockCmd( RCC_APB2Periph_ADC1, ENABLE);,挂载在APB2上的外设,查手册可知挂载在APB2上的外设;通过库函数控制相应的外设时钟状态。,几个规范的位操作方法,将char型变量a的第七位(bit6)清0,其它位不变。 a ,再论开发方式,用直接配置寄存器的方法,只需要一个语句: GPIOC-CRL = 0x44333444; 内核执行效率最高的方式,确定这样的一个值,却是一件麻烦事。 配置寄存器还可以用前面提到的三种位操作方式: 1. GPIOC-CRL /配置Pin5的4个控制位 修改起来比较容易,执行效率低些 本章介绍的库开发方式,调用库函数耗时,但易快速编程;CPU高速了,一般不必担心耗时。,课下任务,作业: 1、试述STM32的系统时钟,并说明是如何设置的? 2、举例说明STM32的外设时钟是如何开启与关闭的。 3、LED流水灯模拟实验,实验报告(包括每个语句的解释意义)。 思考简答: 在stm32f10x_conf.h这个头文件中定义的函数声明还是宏定义,怎么在其它文件中应用呢? 自学: GPIO_Init()函数的定义代码分析,见野火PDF资料P105-106.,

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 企业管理 > 管理学资料

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报