嵌入式技术应用项目式教程(STM32版)高职PPT完整全套教学课件_第1页
嵌入式技术应用项目式教程(STM32版)高职PPT完整全套教学课件_第2页
嵌入式技术应用项目式教程(STM32版)高职PPT完整全套教学课件_第3页
嵌入式技术应用项目式教程(STM32版)高职PPT完整全套教学课件_第4页
嵌入式技术应用项目式教程(STM32版)高职PPT完整全套教学课件_第5页
已阅读5页,还剩349页未读, 继续免费阅读

下载本文档

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

文档简介

嵌入式技术应用课程介绍全套可编辑PPT课件什么是嵌入式系统什么是嵌入式系统IEEE(InstituteofElectricalandElectronicsEngineers,美国电气和电子工程师协会)对嵌入式系统的定义:“用于控制、监视或者辅助操作机器和设备的装置”。原文为:DevicesUsedtoControl,MonitororAssisttheOperationofEquipment,MachineryorPlants)。嵌入式系统是一种专用的计算机系统,作为装置或设备的一部分。什么是嵌入式系统硬件嵌入式系统应用与发展嵌入式系统应用与发展如何学好嵌入式如何学好嵌入式如何学好嵌入式如何学好嵌入式培养兴趣多动手、多问为什么注重观察,勤总结多使用搜索引擎查找资料、没事逛逛论坛项目一流水灯项目内容知识STM32概述STM32最小系统电路分析(重点)GPIO概述GPIO的输出功能使用(重点、难点)流水灯程序设计逻辑分析技能STM32开发环境搭建创建STM32工程固件库文档的使用(重点)GPIO的输出功能使用(重点、难点)流水灯电路设计实践搭建STM32开发环境点亮一个LED灯实现流水灯考核实现流水灯项目计划计划总课时:8课时计划讲授课时:4课时计划实践课时:4课时目录STM32概述预计时间15分钟STM32开发环境搭建预计时间15分钟创建STM32工程预计时间10分钟固件库文档的使用预计时间10分钟层次化原理图的阅读预计时间10分钟STM32最小系统分析预计时间20分钟GPIO的概述预计时间30分钟GPIO的输出功能使用预计时间20分钟流水灯电路设计预计时间10分钟流水灯程序设计逻辑分析预计时间20分钟STM32概述STM32是什么?意法半导体集团(STMicroelectronics,简称ST)于2007年开始陆续推出的一系列基于ARMCortex-M构架的32位低成本、高性能的微控制器(microcontroller)。代表产品STM32F103,内核构架ARMCortex-M3。STM32是什么?图片来源:/ybhuangfugui/article/details/89369069STM32家族图片来源:/en/microcontrollers-microprocessors/stm32-32-bit-arm-cortex-mcus.htmlSTM32F103家族图片来源:/content/st_com/en/products/microcontrollers-microprocessors/stm32-32-bit-arm-cortex-mcus/stm32-mainstream-mcus/stm32f1-series/stm32f103.htmlSTM32F103VET6引脚图STM32性能AT89S51STM32F103VET6主频使用24MHz晶振时,机械频率2MHz通常使用8MHz晶振,主频72MHzFlash/RAM4KB/128Byte128KB/20KBIO数量32(P0、P1、P2、P3)80(PA、PB、PC、PD、PE、PF……)定时器数量2个16位4个16位UART/SPI/I2C/USB/CAN1/0/0/0/03/2/2/1/1ADC012位2*16通道供电电压4.5~5.5V2.0~3.6V封装DIP-40;LQFP-44LQFP-100;LFBGA-100价格STM32F103与AT89S51对比为什么学STM32?开发生态相对完整,上手难度较小最早推出固件库,显著缩短开发周期(其他厂商同时期几乎都是直接操作寄存器)STM32CubeMX进一步简化底层设计为什么学STM32?推出时间早,开发资源丰富为什么学STM32?能够对使用ARMCortex-M系列微控制器打基础。以下微控制器均采用ARMCortex-M内核MSP432E401Y(TI)MKE14F256VLH16(NXP/Freescale)R7FS124773A01CNF(Renesas)ATSAMD09C13(MicroChip)XMC1401-Q048F0064(Infineon)GD32F103(兆易创新)STM32难在哪?同样是将8位IO设置为01010101,对比一下AT89S51和STM32的代码:STM32代码涉及到的寄存器P1=0X55;RCC->APB2ENR|=(1<<2);GPIOA->CRL=0X444444CC;GPIOA->ODR=0X00000055;STM32难在哪?功能强大导致需要配置的寄存器多32位结构导致每个特殊功能寄存器复杂对C语言有更高的要求(结构体、指针)配置多、程序长,显得很复杂STM32程序示例STM32程序示例程序不是越长越难,可以举个例子。代码1:#include"stdio.h"voidmain(){inta,b,c;a=b+c;c=a;a=b+c;c=c/2;c=c+a;printf("%d\n",c);}代码2:#include"stdio.h"voidmain(){int*p,a,b;&p=&a+b+*(&&b);printf("%d\n",*p);}代码1比代码2长,但是代码1非常容易看懂,代码2虽然只有1行,但是看起来非常的复杂。程序的长短与程序的复杂程度没有必然联系。对于实现同样功能的两端代码,可能长的代码更清晰易懂。STM32开发环境搭建什么是开发环境?在做开发时需要用到的指定软、硬件,以及对应的系统以及应用程序工具等,这个整体就是开发环境。简单的说:就是用什么写程序,用什么编译程序,用什么通过什么方式将编译好的程序烧录到微控制器。随着开发软件的不断发展,将多种开发工具集成到一个软件中的集成开发环境(IntegratedDevelopmentEnvironment,IDE)逐渐成为开发人员的首选。开发环境选择STM32F103支持多种IDEKeilMDK优点:编程界面友好、操作方便、实用简单、资料多等缺点:商用软件需付费STM32CubeIDE优点:官方软件、界面友好、代码补全、操作简单等缺点:基于eclipse,对电脑硬件要求较高MicrosoftVisualCode

&gcc-arm-none-eabi优点:开源免费缺点:搭建困难,需要一定的基础……开发环境选择本着易用的思路,选择keilMDK作为首选开发工具。烧录工具选择ST官方推出的ST-Link(如下右图)。关于固件库由于STM32功能强,片上资源丰富,因此必然导致配置寄存器数量多,配置难度大。从而希望寻求一种简单的配置寄存器的方法。ST是最早推出固件库配置寄存器方案的公司之一,在其他厂商还在使用传统的纯手工写代码配置寄存器的时候,ST的标准固件库(StandardFirmwareLibrary)横空出世。直接使用函数对器件进行配置的方式一经上市就广受开发人员好评。这也是STM32能够迅速发展壮大的一个重要原因。关于固件库标准固件库更新到3.5版本后,ST停止了对其更新。继而推出了HAL库(HardwareAbstractionLayer),并以STM32CubeMX图形化界面作为支持,使得STM32底层配置代码只需要点鼠标即可完成。但是STM32CubeMX图形化配置对于不熟悉微控制器内部资源的初学者并不友好,在初学阶段,使用标准固件库更为合适。关于固件库除了官方的固件库以外,还有很多第三方库,它们大多使用C++编写,例如libstm32pp。每一种第三方库都会专注于某几个问题而有自己的优缺点。在学习STM32初期,建议选择标准固件库。KeilMDK的安装创建STM32工程固件库文档的使用固件库文档的使用传统的微控制器配置方式:1.查看数据手册相关内容2.分析寄存器配置方式3.对照寄存器位功能定义配置寄存器传统配置方式的优点:配置灵活代码执行效率高缺点:开发效率低难度大固件库文档的使用固件库的出现就是为了解决传统配置方式存在的问题,直接操作寄存器的代码被封装成函数,使得开发人员只需要关注所需要配置的功能及其对应的参数,调用函数,并带上合适的参数即可对硬件进行配置。问题:用哪个函数?用什么参数?固件库文档的使用ST官方在推出固件库时,有一份详细的固件库文档,仅依靠固件库文档即可完成绝大部分片上资源的配置和使用,一些高级功能还需要查看数据手册,才能完成配置和使用。固件库文档的使用固件库文档的使用固件库文档的使用当前最关注的目录:ModulesSTM32F10x_StdPeriph_Driver固件库文档的使用首字母缩写对应的片上资源固件库文档的使用模数转换器外部中断控制器直接内存访问控制器通用功能输入输出端口中断向量控制器复位和时钟控制器定时器异步发送接收器固件库文档的使用以GPIO相关函数为例,依次选择“STM32F10x_StdPeriph_Driver”、“GPIO”、“GPIO_Private_Function”、“Function”、“GPIO_Init”,即可看到GPIO初始化GPIO_Init函数的使用说明。固件库文档的使用层次化原理图的阅读层次化原理图的阅读传统的原理图传统的原理图通常将所有模块的原理图直接绘制在同一张图纸里,当模块较多时,也有用多张原理图。但是随着原理图中的模块越来越多,原理图变得越来越复杂。为了更好的查看原理图,层次化原理图(也称模块化原理图)成为一种比较好的解决方案。层次化原理图的阅读层次化原理图通常需要用目录作为辅助查看工具。先从目录中找到顶层文件。树状目录能够帮助我们轻易辨别顶层文件。顶层文件中看到的是模块之间的连接方式,但不能看到模块内部的电路。层次化原理图的阅读以查看LED与STM32F103引脚连接情况为例说明层次化原理图的使用方法层次化原理图的阅读在顶层原理图中,可以看到LED模块,对应的原理图为LED.SchDoc,与STM32的连接方式为STM32F103Vx.SchDoc中的LED0标号与LED.SchDoc中的LED0标号相连。层次化原理图的阅读从目录中打开LED.SchDoc文件后,能够看到LED部分的电路连接。LED0标号连接到D1的阴极,并经过330Ω的电阻后到3.3V电源。层次化原理图的阅读STM32F103Vx.SchDoc文件中,LED0标号连接在PA0端口。由此可以得出结论:LEDD1与STM32F103的PA0口相连,当PA0口输出高电平时,D1熄灭,PA0口输出低电平时,D1亮。STM32最小系统分析STM32最小系统分析STM32F1系列的最小系统主要包括以下几个部分:电源复位时钟启动电路STM32最小系统分析电源STM32F103的电源为2.0~3.6V,推荐电源为3.3V。3.3V电源推荐使用线性稳压电源(LDO)输出,并在LDO输出后接多个退耦电容。STM32最小系统分析电源3.3V电源由线性稳压器LM1117-3.3提供,再接C8、C9两个0.1μF瓷片电容滤波。注意:线性稳压器的输入与输出电压如果过大,极易引起稳压器发热烧毁。STM32最小系统分析复位STM32F103为低电平复位,复位引脚NRST。上电瞬间,3.3V电源提供给了电源引脚,但是由于C24的存在,使得NRST将维持低电平。根据数据手册,NRST引脚的低电平最高电压为0.8V,不到供电电源的三分之一。按RC电路充放电时间计算,0.1s可以将C24两端电压充到约1.1V,而低电平时间只要持续20μs即可触发复位,因此该电路能够满足上电复位的要求。STM32最小系统分析复位当需要手动复位时,可以通过按按钮S5完成。当S5被按下后,C24短路,NRST直接与GND相连。而人手动的按键时间几乎不可能小于20μs。STM32最小系统分析时钟对于数字电路来说,时钟是其工作的节拍。多数封装的STM32F103可以同时外接两种不同频率的晶振。其中一个是低速外部时钟,通常供给实时时钟使用的32.768KHz晶振。另一个是高速外部时钟,该时钟可以使用1~25MHz晶振。为了倍频方便,常用8MHz。STM32最小系统分析时钟左图所示时钟电路图选用的是8MHz无源晶振,两个22pF的起振电容,以及1MΩ的反馈电阻。STM32最小系统分析启动STM32F1系列微控制器为不同的需求提供3种启动方式:从主Flash存储器启动:正常启动,从Flash存储器加载程序从系统存储器启动:一般用于串口烧录程序从SRAM启动:一般用于特殊场景调试,例如Flash被锁的场景STM32最小系统分析启动方式通过BOOT0和BOOT1引脚设置。

对于LQFP100封装的STM32F103Vx来说,BOOT0位于94脚,BOOT1与PB2共用37脚。BOOT1BOOT0X0从主Flash存储器启动01从系统存储器启动11从SRAM启动STM32最小系统分析BOOT0经过一个10K的电阻后,连接到一个由3位排针,可通过短路帽选择连接高电平或低电平。正常使用时连接低电平,需要使用串口烧录程序时,可连接高电平。GPIO概述GPIO概述GPIO全称General-purposeandalternate-functionI/Os,包含GPIOs和AFIOs两个部分。GPIO是基础,也就是一般功能输入输出端口;AFIO一般称之为复用IO。通过查看数据手册可以看出,STM32F1系列微控制器几乎没有哪个IO口是只有IO功能,通常还会有第三功能甚至是第四功能,而这部分功能将由AFIO管理。GPIO概述数据手册中的GPIO部分结构图对理解GPIO具有重要意义。GPIO概述增加6个节点编号以分析输入路径。当I/Opin位置有一个输入信号时,在节点1处为保护二极管,2个串联的二极管可以使得输入信号的电压不高于VDD且不低于VSS。节点2为输入输出的路径选择,由于下方为两个MOS管输出,信号无法通过,因此只能往上走。123456GPIO概述节点3位置有2个电阻,分别接VDD、VSS。当连接VDD的开关闭合时,该电阻为上拉电阻,此时的输入方式为“上拉输入”;仅闭合与VSS连接的开关时,该电阻为下拉电阻,此时的输入方式为“下拉输入”;上下两个开关同时断开时,输入方式为“浮空输入”,不允许两个开关同时闭合。123456GPIO概述节点4位置有两条支路,一条连接到模拟输入,另一条经过一个施密特触发器整形到达节点5。节点5同样有两条支路,一条连接到复用功能输入,第二条支路连接到输入数据寄存器,即节点6。可以通过编写程序,使得CPU读输入数据寄存器,从而完成对一个输入信号的读入。123456GPIO概述对于输出路径,同样可以采取该方法分析。节点1处,通过编写程序,CPU对置位/复位寄存器进行操作,则会修改节点2处的输出数据寄存器。节点3处有数据选择器,选择通过的数据来源于输出数据寄存器还是复用功能输出。32451GPIO概述节点4将由输出控制器控制两个MOS管的状态。可以两个MOS管同时工作,这种输出模式称为“推挽输出”;也可配置为P-MOS不工作,仅N-MOS工作,此输出模式称为“开漏输出”。MOS管的输出经过节点5的保护二极管之后,最终到达I/O引脚。32451GPIO概述根据对GPIO结构图的分析,可以得出以下结论:GPIO工作在输出模式时:需要配置输出模式(推挽输出、开漏输出)GPIO工作在输入模式时:需要配置输入模式(上拉输入、下拉输入、浮空输入)GPIO输出功能使用GPIO输出功能使用使用GPIO时(无论是输出功能还是输入功能),都需要完成以下几个步骤:使能对应GPIO组时钟配置GPIO使用GPIOGPIO输出功能使用借助标准外设固件库对GPIO进行操作。功能固件库中对应函数使能GPIO时钟RCC_APB2PeriphClockCmd配置GPIOGPIO_Init控制GPIO输出电平GPIO_ResetBits、GPIO_SetBits、GPIO_Write、GPIO_WriteBitGPIO输出功能使用函数使用说明voidRCC_APB2PeriphClockCmd(uint32_tRCC_APB2Periph,FunctionalStateNewState)函数作用:使能或失能指定时钟参数RCC_APB2Periph。指明需要控制的时钟,固件库文档中有该参数的说明。如需要失能GPIOA时钟,即可使用参数RCC_APB2Periph_GPIOA,该参数为一个已定义的宏。参数NewState。指明是需要使能还是失能指定时钟。使能使用ENABLE,反之使用DISABLE。GPIO输出功能使用voidGPIO_Init(GPIO_TypeDef*GPIOx,GPIO_InitTypeDef*GPIO_InitStruct)函数功能:对GPIO进行初始化配置参数GPIOx。该参数用于指定需要配置的GPIO组。例如需要对PA0进行配置,则该参数可使用GPIOA。参数GPIO_InitStruct。该参数为一个结构体指针,用于指定IO口具体如何配置。固件库文档中有大量超链接,可以灵活的跳转到各个类型、函数、结构体的定义。右图为GPIO_InitTypeDef结构体的定义。从定义可以看出,结构体包含3个数据域,从变量名基本可以判断其意义。GPIO_Mode域用来指定GPIO的工作模式;GPIO_Pin域用来指定具体的IO位,GPIO_Speed域用于指定GPIO工作速度。其中,GPIO_Mode为GPIOMode_TypeDef类型,GPIOMode_TypeDef为枚举类型。因此,GPIO_Mode域的取值只能为枚举类型定义的值。通过超链接同样可以查看其定义。该枚举类型共有8个值,分别代表着GPIO的8种工作模式,从上到下依次为:模拟量输入、浮空输入、下拉输入、上拉输入、开漏输出、推挽输出、复用功能开漏输出、复用功能推挽输出。GPIO_Pin为16位无符号整型(uint16_t),使用时可直接使用固件库提供的宏,通过超链接跳转,可以看到从GPIO_Pin_0到GPIO_Pin_15的定义,在使用时,根据需要使用对应的宏即可。对于GPIO工作速度,在分析GPIO结构图时,并没有提及速度相关的因素。工作速度存在的意义主要是提供更好的低功耗支持,一般认为工作频率越低,功耗越小。因此STM32提供可选的GPIO工作速度,并通过枚举类型变量GPIO_Speed域设置,取值范围如下:GPIO输出功能使用voidGPIO_SetBits(GPIO_TypeDef*GPIOx,uint16_tGPIO_Pin)函数功能:将指定GPIO口位设置成高电平。参数GPIOx。指定需要设置为高电平的GPIO口位处于哪一个GPIO组,如GPIOA、GPIOB等。参数GPIO_Pin。指定需要设置为高电平的GPIO口具体是哪一位,如GPIO_Pin_1、GPIO_Pin_2等。GPIO_ResetBits与该函数参数一致,不同之处在于将指定GPIO口位设置为低电平。GPIO输出功能使用当需要PA0输出高电平时,需编写代码如下:第3行,定义GPIO_InitTypeDef类型变量gpio,用于初始化GPIO。第5行,使能GPIOA时钟。第7~9行,对gpio变量的3个域赋值。第11行,使用gpio变量地址作为GPIO_Init函数参数对GPIO进行初始化。第13行,通过SetBits将PA0设置为高电平。流水灯电路设计流水灯电路设计所谓流水灯就是发光二极管依次亮灭,从视觉上来说,就像水在流动。因此,设计实现流水灯电路需要能够使用STM32F103对LED的亮灭状态进行控制。在讨论LED电路设计时,先回顾一个知识点,需要满足什么条件,LED才能发光?一般来说,0805封装的贴片红色LED,2V电压,8mA电流(电流大小将影响LED亮度),即可点亮。LED的连接方式主要有两种,一种是将LED的阳极连接到3.3V电源,阴极接STM32F103的GPIO,此时电流从电源流出,最终流入GPIO;另一种是将LED的阳极接STM32F103的GPIO,阴极接地(两种连接方式都未考虑限流电阻),此时电流从GPIO流出,最终到地。流水灯电路设计两种连接方式,一种是需要GPIO输出电流驱动LED,另一种是电流流入GPIO。这两种电流分别称为拉电流和灌电流。简单来说,拉电流就是IO口输出电流的能力;灌电流则是IO口承受外部电流流入的能力。对于多数微控制器而言,首选的连接方式是第一种,该种方式电流直接从电源输出,不需要IO口有足够的拉电流驱动能力,只需要有灌电流驱动能力即可(多数微控制器灌电流都能达到10mA级别)。STM32F103的GPIO驱动能力强,其拉电流、灌电流均达到25mA,对于驱动LED,可以在两种连接方式中任选一种。流水灯电路设计由于电路要求不严格,在一定范围内,电流的大小仅与LED的亮度有关,在设计时,可以采取估算参数的方式。STM32F103的输出电压为3.3V,按10mA计算,可以使用330Ω的限流电阻,因此可设计驱动电路如下图所示。流水灯程序逻辑分析流水灯程序逻辑分析在动手写代码之前,需要进行逻辑分析,简单点说就是画流程图。通过画流程图,确认程序每一步应该干什么,然后对照流程图,按流程图中的步骤完成代码的编写即可。在学习C语言时,老师通常会建议同学们在写程序前先画流程图,在初学阶段,甚至建议在动手写每一个程序之前都先画流程图。在本门课程同样建议大家在写代码之前画流程图,因为画流程图的过程不需要关心使用编程语言如何实现,而只需要将注意力集中到怎样实现功能上。流程图绘制完成后,对照流程图写代码,则是将设计思路转变成代码的过程。流水灯程序逻辑分析使用合适的工具绘制流程图可以使得事半功倍。有不少同学直接使用word中的绘图画流程图,这样一来,注意力会被分散,不利于流程图的绘制。推荐工具1:MicrosoftOfficeVisio。和Word、Excel等软件一样,都属于office,但是Visio是一个专门用来绘制各种框图、流程图、甘特图等的绘图软件。使用Visio绘制好的图也能和Word无缝对接,使用方便。推荐工具2:/。在线绘制流程图工具,最大的好处就是不需要安装软件。不登录不影响基本功能使用使用迅捷的网络工具绘制了一个流水灯的流程图如左图所示。该流程图只绘制了4位LED的流水灯,但是和8位流水灯的逻辑基本是一致的。那么,按照这个流程图编写程序,能实现流水灯的效果吗?直观来看,流程图并没有问题,程序也完全是对照着流程图编写,但是却没有得到预想的效果。导致这种情况的原因,是因为人为的在流程图中加了“戏”。从微控制器的角度,也就是从程序代码的角度,依次点亮熄灭每一个LED并没有问题,但是有一个非常重要的因素,就是速度。微控制器执行代码的速度非常快,有一种误差很大的估算代码运行时间的方法:每一个时钟周期,执行一条程序代码。这个方法对于汇编语言的程序来说,是成立的,但是对于C语言编写的程序来说不成立。因此只能用于估计时间。STM32F103的主频72MHz,时钟周期0.01389us,直接按0.02us计算。点亮第一个LED、熄灭第一个LED等一些列功能执行完,也不会超过0.1us。这样的依次亮灭的速度,在人眼看来就是全亮了。解决这个问题的方法就是增加延时函数。延时函数延时函数的功能是让微控制器在程序的某一行停留一段比较长的时间(ms级居多),能达到这一目的的方法很多,因此延时函数的写法也非常多。最常用的延时函数写法是纯软件的形式,利用循环语句,使得微控制器在某一时段内一直在执行循环,从而达到延时的目的。按照时钟周期0.02us计算,如果需要微控制器在停留500ms,则需要执行25000000条代码,这用循环是很容易实现的。delay_500ms函数大概就是完成了500ms的延时,实际时间会大于500ms。这个延时函数的通用性比较差,如果在一个地方需要延时100ms,则这个函数又需要重新写。应该怎样写延时函数才能使得通用性好呢?项目二篮球计分器项目内容知识数码管显示原理端口的重定向(重点、难点)技能GPIO的输入功能使用(重点、难点)篮球计分器的设计实践按键控制LED灯数码管显示“1234”篮球计分器流程图绘制篮球计分器的实现考核篮球计分器的实现项目计划计划总课时:12课时计划讲授课时:6课时计划实践课时:6课时目录项目描述GPIO的输入功能使用数码管显示原理端口的重定向C语言函数回顾数码管显示函数的编写篮球计分器逻辑设计项目描述开发板上有4位数码管,4个按键。利用这些资源可以设计出各种各样的计分器,篮球、乒乓球、足球等等。本项目将完成一个篮球计分器的设计。在开始动手之前,应该对篮球计分器所需要的功能进行一个详细的分析。这个过程在项目开发中,称之为需求分析。篮球计分器需要的功能:1.能显示比分。2.能调整比分。篮球比赛中,有1分、2分、3分,应该能给对应方增加得分。3.能调换显示。在篮球比赛中,通常中场休息时会交换场地,此时可以将比分显示也同样交换。4.比分能清零。根据需求分析,已经确定了篮球计分器需要一些什么功能。接下来根据手上的开发板已有的资源,做一个可行性分析。显示比分。4位数码管可以用来显示比分,最直接的方式是每方使用2位数码管,最高比分99:99。调整比分。一共有4个按键S1~S4。可设置为按下S1,数码管左边2位加1,按下S2,数码管右边2位加1。2分的情形对应按键按2次,3分的情形对应按键按3次。调换显示。设定按键S3,当按下S3时,左右两边比分交换。根据以上分析,以开发板上的资源完全可以设计一个简易的篮球计分器。实现篮球计分器的方式并不唯一,课后可自行用其他方式实现。GPIO的输入功能使用前序课程中学习过如何使用GPIO的输出功能,在学习使用GPIO输入功能时,可以采用与输出功能对比学习的方法。如果需要将PC0的电平状态读入,可以写如下代码:与学习输出功能时一样,对每一行程序的功能进行解析。第3行定义一个8位无符号整型变量,最后用来保存读取的PC0电平信息。第5行定义了一个GPIO初始化结构体变量。第7行通过调用固件库函数使能GPIOC的时钟。第9行在GPIO初始化结构体变量中设置GPIO的模式为上拉输入。第10行在GPIO初始化结构体变量中指定GPIO位为PIN0。与学习输出功能时一样,对每一行程序的功能进行解析。第12行调用固件库GPIO初始化函数,并将GPIOC和初始化结构体变量的地址作为参数传递给初始化函数。第13行调用固件库函数读取PC0的电平状态并赋值给level变量。疑问1:为什么代码中不设置GPIO工作速度?因为GPIO工作速度设置只在输出模式有效,在输入模式无效。疑问2:为什么是上拉输入模式,而不是其他输入模式?为了解决第二个疑问,需要再看微控制器的GPIO结构图。左图为GPIO工作在输入模式时的结构图。

为了解决第二个疑问,需要再看微控制器的GPIO结构图。回顾一下3种输入模式:当配置为上拉输入时,1位置连接电源的开关闭合;配置为下拉输入时,1位置连接地的开关闭合;配置为浮空输入时,两个开关均断开。3种输入模式的在电路结构上的差异是显而易见的,但是这3种模式在实际使用过程中有什么差异呢?1为了在实际电路中看到3种输入电路的区别,需要使用一种输入器件,再将该器件与微控制器连接,从而对比3种模式的差异。按键是最常见的输入器件之一,在数字电子电路中,已经学习过按键的相关知识。通过按键及其必要的电路,可以改变电路中某一个点的电平。例如,在数字电子电路中,555的单稳态触发器电路,就是使用的按键作为触发信号,使得电路进入暂稳态。那么按键应该怎样与微控制器相连?又该使用怎样的输入模式呢?如左图所示:按钮S1的左边链接KEY1标号,且该标号直接连接到微控制器的PC0口;S1的右边接地。按照输入电路结构,最简单的是浮空输入模式,既不接上拉电阻,也不接下拉电阻。假设在初始化PC0口时,将输入模式设置为浮空输入。当按下S1时,由于PC0通过S1直接连接到地,所以PC0为低电平。但是,当S1未按下时,PC0没有连接到地,同时也没有连接到电源,那么,此时的PC0应该是高电平还是低电平呢?无法确定。如果配置为上拉输入时,为了电路描述方便,可以将在微控制器内部的上拉电阻画在电路图上,如左图所示。此时,当S1闭合时,PC0同样是通过S1连接到地,PC0上为低电平。当S1断开时,PC0经过一个电阻,连接到3.3V电源,因此PC0为高电平。这就是上拉输入模式的作用。提问:配置为下拉输入模式时,按键S1能否引起PC0上的电平变化?为什么?3.3V现在已经可以通过编写代码获得指定GPIO位的电平,因此,可以通过编写代码使用按键来控制LED灯。在项目1中,LED灯的亮与灭是程序直接确定的,并不受外界的影响。在本项目中,数码管显示的比分则需要通过按键调整,按键值需要对程序的执行产生影响。为了掌握使用按键值的方法,设计3个阶段的任务:1.按下按键时,LED亮;松开时,LED灭。2.按一次按键(按下再松开),LED亮;再按一次,LED灭。3.按一次按键,流水灯开始;再按一次,流水灯停止。第6行,表明该循环为一死循环,其循环体将一直执行。第8行,调用固件库中的读取GPIO电平函数,并用if语句判断该函数的返回值。当返回值不为0时,则执行第10行,否则执行第14行。返回值为0时,表示按键按下,反之则为未按下。第10行,将PA0置为高电平,即LED灭。第14行,将PA0置为低电平,即LED亮。第6、7行,各定义一个8位无符号整型变量。第11行,将按键电平读取到level变量。第13行,判断level变量是否为0,为0则表明按键已按下。第15行,判断flag变量的值,由于需要将亮的LED熄灭,灭的LED点亮,因此程序必须知道当前LED的状态,该状态有flag变量记录。第17、18行和第22、23行修改flag值和PA0状态。实际使用时,会发现该程序体验不好,有时候能点亮LED,有时候不能;有时候能熄灭LED,有时候不能。分析其原因,还是和微控制器执行速度太快有关。当按键按下时,第一次执行时,会把PA0置为高电平,第二次执行会置为低电平,第三次……。但是人按一次按键的时间,够微控制器执行多少次呢?这个数量总之很多,但具体是多少,无法判断。当执行次数为奇数时,LED会灭,为偶数时,LED会亮。因此LED亮灭状态并不确定。解决这个问题的思路非常简单,如果每按一次按键,程序只执行一次,问题就迎刃而解。那么如何实现呢?灵活运用循环语句,总是能有出其不意的效果。按一次键程序只执行一次,可以换一种理解,当按键没有释放时,程序始终停留在一个位置,无法继续向下执行。该功能同样可以用循环实现。while语句的循环条件是当括号里的条件为真时,则执行循环体(当前循环体为空)。根据代码分析则是当PC0为低电平,程序则停留在本行代码。当按键按下时,PC0为低电平。当按键释放时,PC0口为高电平,循环条件为假,循环结束。程序则能继续向下执行。这个功能称之为“松手检测”。这一条代码,添加在什么位置呢?经过了一次修改之后,用户体验好了很多,但是感觉还是有些不灵敏,或者说太灵敏。引起这种体验的原因在数字电子电路中有提到过,叫做机械按键的抖动。图片来源:/html/2015/1107/28772606.shtm理想的按键波形是按下按键后,电平稳定的变为低电平,松手后,稳定的变为高电平。实际情况是在按下后,在一段时间内电压会有抖动,而抖动的电压可能是高电平,也可能是低电平。一旦出现低电平,程序则会执行一次。从而出现体验不好的问题。为了解决按键抖动的问题,数字电子电路里给出了一种硬件解决方案,但是增加硬件一方面会增加电路成本,同时也会使得电路变得复杂,因此,硬件解决方案使用率不高。观察按键的实际波形,抖动只会存在一段时间,这一段时间以后电平是稳定的。因此可以采用软件的方式完成去抖动。当检测到PC0为低电平时,为了避免抖动的影响,可以用软件延时10ms(经验值),然后再次确认PC0是否仍为低电平,是则确认为按键按下,反之则不认为按键按下。此流程图使用typora(Markdown)绘制,可自行了解根据流程图,可写出代码如右图。只要逻辑清晰,if语句嵌套并不是复杂的问题。第3阶段的任务是需要使用按键控制流水灯。写代码之前先观察流水灯的流程图。先不用考虑怎样让流水灯停下来,先思考按键检测的功能在流程图的什么位置进行?似乎放在任何位置,都不能有良好的操作体验。因为放在循环内的任意一个框的前后,都将需要经过4个500ms的延时,才能执行一次按键检测,是故必然影响按键的响应速度。那么,怎么样才能让按键的操作体验如之前一样呢?随着学习内容的深入,当学习了外部中断之后,这个问题是非常容易解决的。但是在此之前,解决这个问题就需要一些技巧。根据之前的内容分析,打开LED和关闭LED所需要的时间是非常短的,大概只需要0.04us。那么这一个时间对按键的操作不会有任何影响,造成影响的根源是延时函数。而微控制器在执行延时函数时,实际上没有做任何有意义的工作。有没有可能把延时函数和按键检测结合呢?延续这个思路,读取GPIO电平,设置GPIO状态等操作基本能在0.02us内完成,为简化分析,将这些代码的执行时间忽略。也就是说,在当前任务,除了延时函数,其他代码都不需要考虑其执行时间。在完成500ms的延时函数中,可增加按键检测代码(读取PC0电平)。由于延时是由微控制器执行空循环实现,因此,按键检测代码可以直接放在循环中。当没有按键按下时,延时函数的功能几乎感觉不到任何区别。如果不需要做防抖、松手检测,那么可以把延时函数写成如左图所示,则延时函数与按键检测合二为一了。但是,软件延时防抖、松手检测又该如何处理呢?在上一页的代码中,微控制器一直在读取GPIO的状态。但是,在实际使用过程中,需要一直读取GPIO状态吗?(注意,已忽略除延时函数外的任何代码的执行时间)一个用户使用按键,每秒钟能按多少次?10次?还是100次?不妨以100次来分析。每秒钟能按100次,也就是按键产生了一个100Hz的矩形波形,也就是周期10ms。将这个矩形波理想化分析,高电平5ms,低电平5ms,一共10ms。既然低电平持续的时间至少得有5ms,那么每隔6ms读取一次GPIO的状态是不会丢失任何一个按键操作的。当然,用户按键的速度是达不到每秒100次的,之前的代码中,我们还添加过10ms的防抖延时,而这个10ms的延时,并没有让我们感觉到有操作滞后的感觉。既然如此,我们可以考虑10ms读取一次GPIO状态。每10ms读取一次GPIO状态,也就是把500ms的延时,拆分成50个10ms的延时。当没有键按下的时候,直接延时10ms,当有按键按下时,去抖动的10ms则能充当此次循环内的10ms延时。文字描述比较抽象,所以才需要流程图。先判断50次循环是不是完成了,如果是,则表明500ms延时已经到了,直接结束即可。否则,判断按键是否按下,无论是还是否,10ms的延时都必须有。无按键按下时,10ms延时后,则当次循环结束。有键按下时,10ms延时后,需继续判断按键是否按下,若按下则执行按键功能,否则结束当次循环。怎样停止流水灯呢?用标志位即可。数码管显示原理数码管显示在数字电子电路课程中,已经使用过数码管。当时使用的数码管的外观如图所示。图片来源/supplyself/80335170383.html数码管的种类非常多,下图所示的还只是数码管种类中非常小的一个子集。图片来源:/i/B0D9C9ABCAFDC2EBB9DCB3A7BCD2.html日常生活中,数码管也随处可见。例如电梯的楼层显示等。首先回顾数码管的内部结构。数码管分共阴极和共阳极两种,在实际使用过程中,选用共阴还是共阳取决于电路的设计。图片来源:/question/2010990761534455948.html对于多位一体的数码管,其内部结构与1位数码管也有很大相似之处。以四位一体共阳极数码管为例,其内部结构如右图所示。每一位有一个公共阳极,每一位的相同段连接在一起,例如每一位中的A段连接在一起,并引出管脚。公共阳极决定哪一位数码管亮,称之为“位选信号”,简称“位选”,阴极决定哪一段亮,称之为“段选信号”,简称“段选”。图片来源:/shop/_nic_200568_196847980.html在电路设计中,选择共阴极数码管,还是共阳极数码管,则完全由电路设计本身决定。数字电子电路课程中使用的是共阴极数码管,这是由CD4511的特性决定的。那么,STM32F103在驱动数码管时,应该用共阴还是共阳呢?要完成电路的设计,需要一些必要的电气参数。在数码管的数据手册中,可以找到如下信息:尺寸规格:0.36英寸四位工作电流:每字节小于20mA工作电压:红:1.8-2.0v黄绿/黄/橙:2.0-2.2v蓝/翠绿3.0-3.2v从理论上分析,由于STM32F103的GPIO拉电流可以到25mA,可以直接由一个GPIO对公共阳极进行控制,对于8个段信号,则连接到另外8个GPIO即可(忽略限流电阻)。但在实际电路设计中,会尽量减小从GPIO引脚的电流输出,这样有利于减小微控制器的发热量。因此,微控制器连接数码管时,通常有必要的驱动电路。以驱动共阳极数码管为例。第1位数码管的公共端12脚,连接到NPN型三极管的发射极,三极管的集电极连接3.3V电源,三极管的基极通过限流电阻后连接到GPIO。由此完成位选信号的控制。点亮数码管的电流直接由3.3V电源输出。对于段选信号,则通过限流电阻连接到GPIO。根据电路分析,得出结论:需要A位数码管的B段亮,则A位选GPIO给高电平,B段选GPIO给低电平即可。根据显示的需要,可以得出如表格所示的段选码。数字共阳极七段码00xc010xf920xa430xb040x9950x9260x8270xf880x8090x90数码管显示数码管的显示的3个阶段的任务阶段1不同位显示相同内容(静态显示)阶段2不同位显示不同内容(动态显示)阶段3在阶段2的基础上可以指定位闪烁静态显示最简单,当需要第1位显示数字“1”时,代码如图所示。GPIO_Write函数的功能是直接将第2个参数的值,直接作为第一个参数所指定的GPIO组的输出,未配置为输出模式的GPIO无效。当需要2位数码管显示“1”也非常简单,代码如图所示。但是,如果要让4位数码管分别显示“1”“2”“3”“4”呢?按照常规的思路,由于4位数码管都需要点亮,所以4个位选都必须有效。但是,此时段选信号应该如何确定呢?由于4位数码管的段选信号是连接在一起的,当微控制器给任意段选信号时,对于4位数码管而言段选信号是一致的,也就是说4位数码管一定是显示的相同的内容。因此,这一种思路是行不通的。考虑另外一种情形。如果让4位数码管在不同的时间,分别显示“1”“2”“3”“4”,这不是多复杂的工作。流程图如右图所示。根据流程图可以写出代码。第8行是为了在一次循环执行完后,需要先关闭第4位数码管,再打开第1位数码管。第9行给出第1位数码管的段选。第10行给出第1位数码管的位选。后续对应位置代码功能类似。如果交换第9行和第10行代码位置,效果会有变化吗?如果先给位选信号,那么上一次的段选信号就对该位数码管产生了影响,虽然时间很短,但是还是能够看到阴影。所以在使用数码管时,一定是先保证段选信号对了之后,再打开位选信号。这一种操作方式称为“消隐”。现在实现的功能是在不同时刻,不同的数码管显示的不同内容。那么,如果把500ms的延时时间减短呢?先减到100ms,看到的是什么效果?再减少到50ms呢?10ms呢?当延时时间减少到10ms时,看到的就是动态扫描的效果了。只是一种利用“人眼余辉”效应使得数码管在人眼看来是在同一时刻所有的数码管显示不同内容。在日常生活中看到的电子显示屏等显示设备,同样也是利用了这一原理。端口的重定向根据右图,数码管的本质就是发光二极管按照一定的排列顺序封装在一个塑料壳内。那么点亮数码管的过程和点亮发光二极管没有区别。按照分析,编写程序点亮一位数码管的全部段。图片来源:/question/2010990761534455948.html可以写出如左图所示代码。GPIO配置成输出功能部分代码省略。第6行,使1位数码管的位选三极管导通,电源连接到数码管的公共阳极上。第8行,使数码管的段选全部置为低电平。第10行,死循环,程序停留在此行。按照程序一步步执行,理应点亮1位数码管的所有段,但是实际情况似乎不太一样,为什么?从开发板运行程序的实际效果来看,有2段没有按照预想的被点亮。但是对于所有的段选GPIO,操作都是一致的,为什么其他段显示都正常,唯独这两段没有按照程序的写法被点亮呢?为了解决这个问题,就需要引入一个新的概念——端口重定向或端口重映射。英文单词是Remap。先给一个结论,PB3和PB4所对应的段之所以不亮,是因为它俩复位后默认功能不是GPIO。只有是GPIO的端口,才能按照GPIO的方式进行编程,设置其高低电平。如果不是GPIO,那么按照GPIO进行编程,效果不言而喻。这两个端口不是GPIO,那是什么?要回答这个问题,就必须要查阅其官方数据手册(DataSheet)。从数据手册看,PB3和PB4,也就是LQFP-100封装的第89、90脚,它俩的主要功能分别是JTDO、JNTRST。所谓的主要功能,括号里头有说明,就是复位之后的功能。也就是说这两个引脚,复位之后肯定不是GPIO的功能。为此,找出PB0的信息与之对比。从表格可以看出,PB0的主要功能就是PB0。因此,仅需要对PB0进行GPIO设置后,就可以按照GPIO的操作流程使用。那么,怎么样将PB3和PB4的功能设置为“PB3”和“PB4”呢?设置的这个过程就是所谓的端口重定义。要完成端口重定义,仅依靠数据手册是不够的,还需要官方的另一个文档——参考手册(Referencemanual)。参考手册是官方提供的编写程序的指导性文档,由于使用了固件库进行开发,大多数时候都不需要查询参考手册,但是,如果要更深入的学习任何一种MCU,阅读其参考手册是非常必要的。从参考手册的目录中,依次打开General-purposeandalternate-functionI/Os(GPIOsandAFIOs),Alternate-functionI/Oanddebugconfiguration(AFIO),JTAG/SWDalternatefunctionremapping。则会看到右侧显示内容。PB3和PB4复位之后默认的功能是调试接口JTAG的相关引脚,从表格36可以看到PB3和PB4。如果说表格36只是列出了所有与JTAG相关的引脚,那么表格37,可以更加直接的指导如何进行端口重定向。第一列SWJ_CFG[2:0]是指的STM32F103的特殊功能寄存器SWJ_CFG的第0~2位,其设置不同的值,对应不同的端口映射方式。从表格看,配置成100是最彻底的,所有被SWJ占用的IO口全会释放,但是开发板使用的是SWD下载方式,如果配置成100后,则不能再下载。因此只能配置成010——JTAG-DPDisabledandSW-DPEnabled模式。不需要直接操作SWJ_CFG寄存器,还是可以借助固件库中提供的函数接口。查询参考手册是为了明确重定向的过程。固件库中提供了如右图所示函数,由红框标注的参数,其配置方式与参考手册中描述一致。因此第一个参数填写GPIO_Remap_SWJ_JTAGDisable,第二个参数填写ENABLE即可。由于端口重映射属于AFIO部分功能,在配置GPIOB端口前,需先调用RCC_APB2PeriphClockCmd函数,使能AFIO时钟,再调用GPIO_PinRemapConfig函数,对端口进行重映射。最后按照传统的方式配置GPIOB,即可正常使用PB3和PB4。C语言函数回顾函数是程序代码的一个自包含单元,用于完成某一特定的任务。有的函数完成某一操作;有的函数计算出一个值。也可以同时完成某一操作,同时得出一个数值。延时函数完成延时功能为什么要用函数?避免重复的编程使程序更加模块化,便于阅读、修改根据定义函数或调用时是否要给出参数,又可将函数分为:无参函数和有参函数。有参函数:delay_ms(500);无参函数:delay500ms();无参函数主调函数并不将数据传给被调函数无参函数主要用于完成某一操作主函数调用print_star()函数调用print_message()函数调用print_star()函数函数无返回值函数名函数无参数函数体有参函数主调函数和被调函数之间有数据传递。主调函数可以将参数传递给被调函数,被调函数中的结果也可以带回主调函数。调用max函数调用printf函数max函数的参数返回值为int类型两个参数均为int类型使用return关键字确定返回值数码管显示函数的编写显示“1234”的程序如右图所示。根据回顾C语言的函数,可以非常轻松地将数码管显示的代码拿出来,封装成一个seg_display()函数。有了seg_display函数后,主函数只需要在while(1)中调用该函数即可。接下来的任务是如何完善seg_display函数,使得程序能够实现指定的功能。在C语言中,有常量和变量两个概念。常量意味着在程序运行过程中,数值不会发生改变;变量则可以改变。在如右图所示的数码管显示函数中,显示的值都是形如0xf9、0xa4的常量。为了能让显示的值能发生改变,第一步则是将这些常量替换成变量。形如0xf9的4个常量替换成了a,b,c,d四个变量。从代码的内容来看,a,b,c,d的值将直接决定显示的内容。这4个变量的定义方式有两种。一种是使用全局变量,直接在主函数中定义;第二种是采用函数参数的形式。推荐使用第二种。第二种方式也符合“高内聚,低耦合”的编程思想。函数增加了4个参数后,第4、10、16、22行的段选码不再是常量,而是由4个参数决定其值的4个变量。在调用set_display函数时,4个参数是什么,对应4位数码管的段选码就是什么。但是,如果要显示“1”的时候,参数不能直接填“1”,而要填“0xf9”,因为“1”的段选码是“0xf9”。有什么办法可以让参数中填“1”,就直接将“翻译”成对应的段选码呢?解决这个问题,最简单的方法是利用数组。将参数作为数组的下标,而数组的值,则是与下标对应的数字的段选码。如右图。当参数a为“1”时,第6行给的段选码为duan[1],即为0xf9。到目前为止,完成了一个粗糙的显示函数的编写。之所以称这个显示函数粗糙,是因为在实际使用过程中还会遇到显示效果不理想的问题。对于原因的分析给出以下2个思考方向:消隐方式每个数码管点亮的时间最后给出一个显示函数供参考。篮球计分器逻辑设计先回顾一下篮球计分器的需求:1.能显示比分。2.能调整比分。篮球比赛中,有1分、2分、3分,应该能给对应方增加得分。3.能调换显示。在篮球比赛中,通常中场休息时会交换场地,此时可以将比分显示也同样交换。4.比分能清零。项目三数字时钟项目内容知识定时器的基本结构定时器的原理(重点、难点)中断的原理(重点、难点)技能定时器的使用(重点、难点)中断的使用(重点、难点)实践1Hz闪烁LED简易秒表考核数字时钟的实现项目计划计划总课时:12课时计划讲授课时:6课时计划实践课时:6课时目录项目描述定时器概述STM32定时器的使用中断、中断控制器NVIC及定时器中断外部中断EXTI数字时钟逻辑设计项目描述数字时钟是日常生活中常见的物品。使用开发板可以自制一个数字时钟,而使时钟运行准确的保证则是微控制器中的一个重要资源——定时器。STM32F103VET6拥有8个定时器,其中一般功能定时器4个,高级功能定时器2个,基础定时器2个。在本项目中,主要讲解一般功能定时器的使用。任务描述项目3的任务是使用STM32开发板完成一个数字时钟。要求数码管显示小时和分钟信息。使用1个按键,用于修改小时;使用1个按键,用于修改分钟;为了显示秒的变化,要求设计8位流水灯,要求每秒完成一次流水。为了便于演示进位,设置1个按钮,按下后,时钟速度提高6倍。也就是每10s分钟数字应该加1。扩展要求:设置一个按键,按下时显示秒,松开时显示小时和分钟。要求按下时,正常走时。定时器概述什么是定时器(timer)?定时器是一种在微控制器中能够实现准确计时的功能模块,是微控制器非常重要的一种硬件资源。所有电子产品中的计时功能,都直接或间接与定时器相关。STM32F103通用功能定时器主要性能16位,向上,向下,向上向下,自动重装计数器16位可编程分频器更新中断:定时器上溢出、下溢出等等等定时器的本质是计数器。在数字电子计数中,我们学习过计数器,例如,74LS161。每当一个脉冲上升沿产生在计数器的CP引脚上时,计数器的输出将加1(以向上计数为例)。假设,有一已知且固定的频率的信号加在CP引脚上,那么计数器的输出Q则表明时间经过了Q个已知信号的周期。左图是STM32F103通用功能定时器的框图,相比较于GPIO的框图,这个框图显得要复杂很多。由于本项目中仅需要使用到定时器中最基本的功能。因此,只需要关注框图的一部分。左图是定时器框图的上半部分。而我们需要使用到的,仅仅是这部分框图的三分之一。从框图可以得知,定时器的时钟来源于RCC,经过分频器后到达计数器。当74LS161计数到0xf时,RCO会产生一个脉冲,用于表示当前计数满。类似的,STM32F103的定时器计数溢出时会有一个标志位置位。对前几页PPT做一个小结。使用定时器的关键是:如何配置分频器如何配置计数器如何利用溢出标志位分频器和计数器的配置将决定定时器所记录的时间,而到达这一设定时间的标志就是溢出标志位置位。正如使用闹钟一样,我们不但需要设定时间,还需要在设定时间到达时,有一个提醒。STM32F103定时器的使用在使用STM32F103的GPIO时,基本步骤是:使能GPIO时钟;GPIO配置;使用GPIO。这一步骤,推广到所有的片上资源都是类似的。因此,在使用定时器时,基本步骤仍然时:是能定时器时钟;配置定时器;使用定时器。STM32F103VET6的片上有8个定时器,其中通用功能定时器(General-purposetimer)为TIM2~TIM5,选用TIM2即可。使能TIM2时钟,使用RCC_APB1PeriphClockCmd函数。GPIO使用的APB2时钟,TIM2使用的是APB1时钟,那么如何判断一个资源使用哪个时钟呢?最直接的方法就是查看固件库文档中RCC_APB1PeriphClockCmd和RCC_APB2PeriphClockCmd两个函数的参数。例如,启动ADC1的时钟,可以从RCC_APB2PeriphClockCmd函数的参数中找到RCC_APB2Periph_ADC1,则可确认ADC1属于APB2时钟。使用该方法查找,比在数据手册的时钟树图中寻找ADC时钟要方便,且不易出错。使能TIM2时钟的代码如下:RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);时钟使能之后,就可以对TIM2进行配置。从固件库文档中,找到TIM2_TimeBaseInit函数。为什么TIM2的初始化函数名不是TIM_Init?因为定时器的功能非常多,在分析定时器部分的框图时,就已经知道我们使用的仅仅只是定时器中非常少的一部分功能。正因为功能多,那么使用TIM_Init作为函数名就很难确定是对哪部分功能进行初始化。因此,通过查看定时器部分的固件库文档,会发现不但有TIM_TimeBaseInit,还有TIM_OC1Init等多个以Init结尾的初始化函数。而TIM_TimeBaseInit,从函数名就能看出,是定时器基础功能初始化,定时器的其他功能也是在此基础上工作的。定时器初始化函数与GPIO的初始化在形式上是一致的,对于其他片上资源的初始化,也是大同小异。voidTIM_TimeBaseInit(TIM_TypeDef*TIMx,TIM_TimeBaseInitTypeDef*TIM_TimeBaseInitStruct)从TIM_TimeBaseInit的函数原型来看,包含两个参数,第一个参数用于指定TIMx,也就是指定实际使用的定时器。例如,TIM2。第二个参数则用于指定定时器基本功能的配置。该参数为一TIM_TimeBaseInitTypeDef类型的结构体指针。typedefstruct{

uint16_tTIM_Prescaler;/*!<SpecifiestheprescalervalueusedtodividetheTIMclock.Thisparametercanbeanumberbetween0x0000and0xFFFF*/

uint16_tTIM_CounterMode;/*!<Specifiesthecountermode.Thisparametercanbeavalueof@refTIM_Counter_Mode*/

uint16_tTIM_Period;/*!<SpecifiestheperiodvaluetobeloadedintotheactiveAuto-ReloadRegisteratthenextupdateevent.Thisparametermustbeanumberbetween0x0000and0xFFFF.*/

uint16_tTIM_ClockDivision;/*!<Specifiestheclockdivision.Thisparametercanbeavalueof@refTIM_Clock_Division_CKD*/

uint8_tTIM_RepetitionCounter;/*!<Specifiestherepetitioncountervalue.EachtimetheRCRdowncounterreacheszero,anupdateeventisgeneratedandcountingrestartsfromtheRCRvalue(N).ThismeansinPWMmodethat(N+1)correspondsto:-thenumberofPWMperiodsinedge-alignedmode-thenumberofhalfPWMperiodincenter-alignedmodeThisparametermustbeanumberbetween0x00and0xFF.@noteThisparameterisvalidonlyforTIM1andTIM8.*/}TIM_TimeBaseInitTypeDef;TIM_TimeBaseInitTypeDef类型定义如左所示。通过typedef将一个结构体类型定义而来。TIM_Prescaler为分频系数;TIM_Period为计数周期;其他参数暂时不需要设置。分频系数、计数周期参数的设置是使用定时器的基础。其取值范围均为0~65535。当APB1时钟工作在72MHz时,TIM2的输入时钟则为72MHz。为了完成特定时间的计时,则需要对以上2个参数进行设置。APB1时钟经过TIM2的分频器后,到达TIM2的计数器。当计数器中的值增加到计数周期参数设定的值时,则会使得TIM2的状态寄存器SR中的更新标志位UIF置位。该标志位置位后,需要通过软件清除。否则无法判断下一次计数器值等于计数器周期的时间。注:分频系数、计数周期两个参数的实际值为其设置值加1。当需要进行100分频时,TIM_Prescaler应设置为99。计数1000个脉冲时,TIM_Period应设置为999。如果需要完成1s定时,则可以设置好定时器,然后不断查询UIF标志位,当标志位产生时,说明1s时间到。那么应该如何设置TIM_Prescaler、TIM_Period两个参数呢?一般来说有两种方式。一种时以频率计算;另一种时以周期计算。以频率计算方式为例。需要定时器定时1s,换算成频率也就是1Hz。定时器的输入频率为72MHz,也就是72000000Hz。可以在取值范围内选择TIM_Prescaler和TIM_Period的值使得72000000/(TIM_Prescaler+1)/(TIM_Period+1)=1成立,则此时的TIM_Prescaler、TIM_Period即为所需参数值。由于72000000/(7199+1)/(9999+1)=1,所以可以将TIM_Prescaler设置为7199,TIM_Period设置为9999。配置代码如下:TIM_TimeBaseInitTypeDeftim;tim.TIM_Presc

温馨提示

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

评论

0/150

提交评论