-第2页-0、友情提示《零死角玩转STM32》系列教程由初级篇、中级篇、高级篇、系统篇、四个部分组成,根据野火STM32开发板旧版教程升级而来,且经过重新深入编写,重新排版,更适合初学者,步步为营,从入门到精通,从裸奔到系统,让您零死角玩转STM32。M3的世界,与野火同行,乐意惬无边。另外,野火团队历时一年精心打造的《STM32库开发实战指南》将于今年10月份由机械工业出版社出版,该书的排版更适于纸质书本阅读以及更有利于查阅资料。内容上会给你带来更多的惊喜。是一本学习STM32必备的工具书。敬请期待!-第3页-6、Sysstick(系统滴答定时器)6.1SysTick——操作系统的心跳SysTick定时器被捆绑在NVIC中,用于产生SysTick异常(异常号:15)。在以前,操作系统和有所有使用了时基的系统,都必须要一个硬件定时器来产生需要的“滴答”中断,作为整个系统的时基。滴答中断对操作系统尤其重要。例如,操作系统可以为多个任务许以不同数目的时间片,确保没有一个任务能霸占系统;或者把每个定时器周期的某个时间范围赐予特定的任务等,还有操作系统提供的各种定时功能,都与这个滴答定时器有关。因此,需要一个定时器来产生周期性的中断,而且最好还让用户程序不能随意访问它的寄存器,以维持操作系统“心跳”的节律。Cortex-M3在内核部分包含了一个简单的定时器——SysTicktimer。因为所有的CM3芯片都带有这个定时器,软件在不同芯片生产厂商的CM3器件间的移植工作就得以化简。该定时器的时钟源可以是内部时钟(FCLK,CM3上的自由运行时钟),或者是外部时钟(CM3处理器上的STCLK信号)。不过,STCLK的具体来源则由芯片设计者决定,因此不同产品之间的时钟频率可能会大不相同。因此,需要阅读芯片的使用手册来确定选择什么作为时钟源。在STM32中SysTick以HCLK(AHB时钟)或HCLK/8作为运行时钟。见图6-1。-第4页-图6-1时钟树(部分)-SysTicktimer时钟来源SysTick定时器能产生中断,CM3为它专门开出一个异常类型,并且在向量表中有它的一席之地。它使操作系统和其它系统软件在CM3器件间的移植变得简单多了,因为在所有CM3产品间,SysTick的处理方式都是相同的。SysTick定时器除了能服务于操作系统之外,还能用于其它目的:如作为一个闹铃,用于测量时间等。Systick定时器属于cortex内核部件,可以参考《CortexM3权威指南》或《STM32xxx-Cortex编程手册》来了解6.2SysTicktimer工作分析SysTick是一个24位的定时器,即一次最多可以计数224个时钟脉冲,这个脉冲计数值被保存到当前计数值寄存器STK_VAL(SysTickcurrentvalue-第5页-register)中,只能向下计数,每接收到一个时钟脉冲STK_VAL的值就向下减1,直至0,当STK_VAL的值被减至0时,由硬件自动把重载寄存器STK_LOAD(SysTickreloadvalueregister)中保存的数据加载到STK_VAL,重新向下计数。当STK_VAL的值被计数至0时,触发异常,就可以在中断服务函数中处理定时事件了。当然,要使SysTick进行以上工作必须要进行SysTick进行配置。它的控制配置很简单,只有三个控制位和一个标志位,都位于寄存器STK_CTRL(SysTickcontrolandstatusregister)中,见图6-。图6-2SystickCTRL寄存器Bit0:ENABLE为SysTicktimer的使能位,此位为1的时候使能SysTicktimer,此位为0的时候关闭SysTicktimer。Bit1:TICKINT为异常触发使能位,此位为1的时候并且STK_VAL计数至0时会触发SysTick异常,此位被配置为0的时候不触发异常Bit2:CLKSOURCE为SysTick的时钟选择位,此位为1的时候SysTick的时钟为AHB时钟,此位为0的时候SysTick时钟为AHB/8(AHB的八分频)。Bit16:COUNTFLAG为计数为0标志位,若STK_VAL计数至0,此标志位会被置1。与SysTick控制相关的所有寄存器如图0-2,其中上面没有介绍的STK_CALIB寄存器是用于校准的,不常用。-第6页-图0-2SysTick寄存器映像6.3SysTick精确延时实例精讲前面的的实验例程中,当有延时需要的时候,我们都是利用内核循环执行变量自减的代码来实现,延时的时间无法精确测量,有很大的局限性,当我们需要精确延时时,就可以利用SysTicktimer实现,理论上它的最小计时单位为AHB的时钟周期,即1/72000000秒,72分之一的微秒,足以满足大部分极端应用需求。本小节以实例讲解如何利用SysTick进行精确延时。6.3.1实验描述及工程文件清单实验描述3个LED在SysTick的控制下,以500ms的频率闪烁。硬件连接PC3–LED1、PC4–LED2、PC5–LED3用到的库文件startup/start_stm32f10x_hd.cCMSIS/core_cm3.cCMSIS/system_stm32f10x.cFWlib/stm32f10x_gpio.cFWlib/stm32f10x_rcc.c用户编写的文件USER/main.cUSER/stm32f10x_it.cUSER/led.cUSER/led.hUSER/SysTick.c-第7页-6.3.2配置工程环境本SysTicktimer精确延时实验中我们用到了GPIO、RCC外设,所以我们先要把以下库文件添加到工程stm32f10x_gpio.c、stm32f10x_rcc.c。由于本实验中,SysTick的中断是在文件core_cm3.h的函数配置的,没有使用NVIC来配置中断,所以可不添加misc.c文件。而core_cm3.h在包含stm32f10x.h头文件时已被添加进工程了。接下来添加旧工程中的外设用户文件led.c,新建SysTick.c及SysTick.h文件,并在stm32f10x_conf.h中把使用到的ST库的头文件注释去掉。1./**2.*****************************************************3.*@fileProject/STM32F10x_StdPeriph_Template/stm32f10x_conf.h4.*@authorMCDApplicationTeam5.*@versionV3.5.06.*@date08-April-20117.*@briefLibraryconfigurationfile.8.**************************************/9.10.#includestm32f10x_gpio.h11.#includestm32f10x_rcc.h6.3.3main文件我们从看main函数看起:1./*2.*函数名:main3.*描述:主函数4.*输入:无5.*输出:无6.*/7.intmain(void)8.{9./*LED端口初始化*/10.LED_GPIO_Config();11.12./*配置SysTick为10us中断一次*/13.SysTick_Init();14.15.for(;;)16.{17.18.LED1(0);19.Delay_us(50000);//50000*10us=500ms20.LED1(1);21.22.LED2(0);23.Delay_us(50000);//50000*10us=500ms24.LED2(1);-第8页-25.26.LED3(0);27.Delay_us(50000);//50000*10us=500ms28.LED3(1);29.30.}31.32.}在main函数中,我们只见到SysTick_Init()和Delay_us()这两个函数比较陌生,它们的功能分别是配置好SysTick定时器和进行精确延时。整个main函数的流程就是先初始化好LED及SysTick定时器之后,就进入死循环,轮流点亮LED1、LED2、LED3,点亮的时间为精确的500ms。6.3.4配置并启动SysTicktimer接下来我们看一下SysTick_Init()这个函数,它是由用户在SysTick.c这个文件中实现的,其功能是启动系统滴答定时器SysTick,并将SysTick配置为10us中断一次:1./*2.*函数名:SysTick_Init3.*描述:启动系统滴答定时器SysTick4.*输入:无5.*输出:无6.*调用:外部调用7.*/8.voidSysTick_Init(void)9.{10./*SystemFrequency/10001ms中断一次11.*SystemFrequency/10000010us中断一次12.*SystemFrequency/10000001us中断一次13.*/14.//if(SysTick_Config(SystemFrequency/100000))//ST3.0.0库版本15.if(SysTick_Config(SystemCoreClock/100000))//ST3.5.0库版本16.{17./*Captureerror*/18.while(1);19.}20.//关闭滴答定时器21.SysTick-CTRL&=~SysTick_CTRL_ENABLE_Msk;22.}本函数实际上只是调用了SysTick_Config()函数,它是属于内核层的Cortex-M3通用函数,位于core_cm3.h文件中,若调用SysTick_Config()配置-第9页-SysTick不成功,则进入死循环,初始化SysTick成功后,先关闭定时器,在需要的时候再开启。SysTick_Config()函数无法在《STM32外设固件库帮助手册.chm》文件中找到其使用方法。所以我们在keil环境下直接跟踪这个函数到core_cm3.h文件,查看函数的定义:1./**2.*@briefInitializeandstarttheSysTickcounteranditsinterrupt.3.*4.*@paramticksnumberofticksbetweentwointerrupts5.*@return1=failed,0=successful6.*7.*Initialisethesystemticktimeranditsinterruptandstartthe8.*systemticktimer/counterinfreerunningmodetogenerate9.*periodicalinterrupts.10.*/11.static__INLINEuint32_tSysTick_Config(uint32_tticks)12.{13./*Reloadvalueimpossible*/14.if(ticksSysTick_LOAD_RELOAD_Msk)return(1);15.16./*setreloadregister*/17.SysTick-LOAD=(ticks&SysTick_LOAD_RELOAD_Msk)-1;18.19./*setPriorityforCortex-M0SystemInterrupts*/20.NVIC_SetPriority(SysTick_IRQn,(1__NVIC_PRIO_BITS)-1);21.22./*LoadtheSysTickCounterValue*/23.SysTick-VAL=0;24.25.SysTick-CTRL=SysTick_CTRL_CLKSOURCE_Msk|26.SysTick_CTRL_TICKINT_Msk|27.SysTick_CTRL_ENABLE_Msk;/*EnableSysTickIRQa