• STM32F4 系统定时器


    概述


      系统定时器(SysTick)也叫做叫做系统滴答时钟,属于Cortex-M4内核中的一个外设(系统外设),内嵌在NVIC中,并且是24bit向下递减的计数器,当计数器的值为0时就申请中断请求,告诉CPU紧急处理该事件。当计数器为0时,可设置自动重装计数器的值便可以实现周期性的调用中断函数,可以利用这种特性实现一个调度器,基于时间片轮转会根据时间片切换任务,用于任务管理和上下文切换,这使得处理器能够在不同的时隙中处理不同的任务。
      上图是从《stm32f4xx中文参考手册》时钟树中截取的部分截图,可以看出RCC向Cortex系统定时器 (SysTick) 提供了8分频的AHB时钟(HCLK),SysTick可使用此时钟作为时钟源,也可使用HCLK作为时钟源,具体可在SysTick控制和状态寄存器中配置。

    库函数

    /**该函数初始化系统计时器及其中断,并启动系统计时计时器,其时钟源被设置为了AHB时钟,
    计数器处于自由运行模式,以产生周期性中断。
    */
    uint32_t SysTick_Config(uint32_t ticks) 
    

      参数ticks就是计数值,为了方便计算直接使用全局变量SystemCoreClock,AHB时钟的值与其相等,将SysTick_Config的参数设置为SystemCoreClock时,也就是一秒钟的时间到达,每过1秒就会产生一个中断。当需要设置一秒钟到达1000次时,只需要将SystemCoreClock/1000,也就是可以将分母看成程序systick中断产生的频率,如下所示:

    SysTick_Config(SystemCoreClock/1000);//假设SystemCoreClock为168MHz,系统定时器进行168000次计数,就是1ms时间的到达。
    

    延时函数

      在许多情况下,可能不需要使用SysTick_Config函数,因为可能使用别的参考时钟,或者不希望启用SysTick中断。在这些情况下,需要直接对SysTick寄存器进行编程,推荐如下顺序:
        1.按SysTick->CTRL写入0,关闭SysTick定时器;
        2.将新的重载值写入SysTick->LOAD;
        3.向SysTick当前值寄存器SysTick->VAL写入0;
        4.写入SysTick控制和状态寄存器SysTick->CTRL,选择时钟源,启动SysTick定时器;
        5.循环检测计数是否完毕,计数完毕便退出;
        6.关闭系统定时器。
      可通过上述方法便可以实现延迟函数,创建sys_tick.c,sys_tick.h文件,保存到Hardware文件夹下,在添加到目录树的Hardware组合Inc组中。

    int32_t delay_us(uint32_t nus)
    {
    	uint32_t temp;
    
    	SysTick->CTRL = 0; 					
    	SysTick->LOAD = (nus*21)-1; 		
    	SysTick->VAL = 0; 					
    	SysTick->CTRL = 1;//使能定时器,并使用AHB的八分频时钟作为时钟源,不使能systick中断				
    	
    	while(1)
    	{
    		temp=SysTick->CTRL;
    		//检测count flag
    		if(temp & 0x00010000)
    			break;
    		
    		//检测系统定时器是否意外关闭	
    		if((temp & 0x1)==0)
    			return -1;		
    	}
    	
    	SysTick->CTRL = 0; 					
    	return 0;
    }
    
    int32_t  delay_ms(uint32_t nms)
    {
    	uint32_t t = nms;
    	uint32_t temp;
    
    	while(t--)
    	{
    		SysTick->CTRL = 0; 			
    		SysTick->LOAD = 21000-1; 	
    		SysTick->VAL = 0; 			
    		SysTick->CTRL = 1; 			
    		while(1)
    		{
    			temp=SysTick->CTRL;
    			
    			//检测count flag
    			if(temp & 0x00010000)
    				break;
    			
    			//检测系统定时器是否意外关闭	
    			if((temp & 0x1)==0)
    				return -1;		
    		}
    	}	
    	SysTick->CTRL = 0; 	
    	return 0;
    }
    

      与官方的代码不同,上述代码考虑到了系统定时器意外关闭的情况,当使用官方代码的延时函数进行反复调用的时候(如轮询检测矩阵键盘需要大量调用延时函数),程序终将会跳转到延时函数中无法退出。

    总结

      1.系统定时器不够精准,需要高精度计时时可以使用TIM(外设定时器)实现;
      2.不过就我编写过的程序来看,与外设通信时使用上面的延迟函数时,没有出现什么大问题;
      3.系统定时器也可以实现高精度计时,不过目前还没有去研究,后续有机会再补充。

  • 相关阅读:
    Spring AOP前置通知实例说明AOP相关概念
    什么是面向切面编程AOP
    关于IOC容器的一些个人理解
    在.Net Core WebAPI下给Swagger增加导出离线文档功能
    .Net Core ORM选择之路,哪个才适合你
    真香.小程序云开发(时光邮局小程序)
    Cordova的安装与配置
    JS三座大山再学习(三、异步和单线程)
    JS三座大山再学习(二、作用域和闭包)
    JS三座大山再学习(一、原型和原型链)
  • 原文地址:https://www.cnblogs.com/ding-ding-light/p/14423934.html
Copyright © 2020-2023  润新知