赞
踩
1。 首先,systick定时器(嘀嗒定时器)隶属于CM4内核的一个外设,内嵌在NVIC中,所以一些函数在core_cm4.c中,系统定时器是一个24bit向下递减的计数器,计数器每次计数时间为1/SYSCLK。 (SYSCLK->系统时钟,通常设定为100MHZ。公式:f=100MHZ,则T=1/f=1/SYSCLK)。
当重装载数值寄存器的值减到0时,系统定时器就产生一次中断(这个中断需要配置并使能),以此循环往复
频率与周期对照表:(f与T)。 1Hz:1s 1Khz=1ms 1Mhz:1us 100Mhz:10ns
对原理图:首先对SysTick->CTRL的第16位置1后,使能LODA(LODA->装载),对SysTick->VAL进行赋值,(VAL当前数值,对应递减的数值,随着数字递减,数值在变化),之后可以选择不分频或者8分频,重装载计数器每1/SYSCLK计数一次,也就是1/100Mhz,10ns计数一次,计数100次就是1us。
2。SysTick定时器寄存器
定时器配置时,只需要配置前三个,最后一个校准寄存器不用配置。
位段16:计数标志位,意思是:读了该位,他自己清0,如果读过一次,并且他还是0,则该位变成1
位段2:选择分频
位段1:置1后,计数器计到0就产生请求,为0没啥作用,
位段0:使能位
段位:把内存分为很多段,每一段有一个段基址,当然段基址也是一个20位的内存地址。不过段寄存器仍然是16位的,它的内容代表了段基址的高16位,这个16位的地址后面再加上4个0就构成20位的段基址。
这个简单,意思是计数到0自己会重新装载数值再倒计时
可读可写位。读的时候,就是把寄存器当前倒计的数值进行读取
写的时候,意思只是把它置位写状态,这个不是设定数值的寄存器,写不进去实际数值,置写位后,还会清除COUNTFLAG的标志位。
SysTick->VAL寄存器的值每一个时钟周期就会递减1,当他递减到0时候, SysTick->LOAD的值将会进入SysTick->VAL中,并且SysTick->CTRL的COUNTFLAG位将会置1,如果还使能了中断,将还会进入中断。
延时原理就是通过设定SysTick->LOAD的值以及时钟周期的数值(通常设定为100MHz)来实现的
定时器的配置代码如下:(在core_cm4.h中)
- __STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)
- {
- if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk) { return (1UL); } /* Reload value impossible */
-
- SysTick->LOAD = (uint32_t)(ticks - 1UL); /* set reload register */
- NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */
- SysTick->VAL = 0UL; /* Load the SysTick Counter Value */
- SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
- SysTick_CTRL_TICKINT_Msk |
- SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */
- return (0UL); /* Function successful */
- }
对于SysTick_Config(uint32_t ticks);这个函数,要知道他已经将定时器配置为AHB(100MHZ) 时钟为 SysTick 定时器的时钟频率,并且使能了计数中断。也就是说,计数ticks(变量参数)次,就会产生一次SysTick中断。
因此,我们就可以根据这个进行配置我们想要的ticks参数。例如:我们配置1ms的SysTick中断,我们可以调用SysTick_Config(uint32_t ticks);这个函数,首先,因为我们的计数周期为10ns(1/100MHZ),1ms/10ns=10*-3 / 10*-8=100000,也就是要递减10 0000次,也就是SysTick->VAL递减10 0000次,所以SysTick->LODA是10 0000,也可以说ticks参数必须是10 0000
SysTick_Config(SystemCoreClock/1000); //设置SysTick定时器1ms中断一次
参数ticks=SystemCoreClock/1000(SystemCoreClock为系统时钟100Mhz,100Mhz/1000=10 0000)。也可以直接填10 0000.
3。利用SysTick定时器设计程序,运行计时器
在此,我们定义一个全局变量volatile uint32_t sysTickUptime=0;在之后,每一次产生中断sysTickUptime++;(volatile修饰符表示sysTickUptime变量是一个易变的变量,它告诉编译器不要优化内容,直接读取变量内容)。
SysTick定时器中断在文件stm32f4xx_it.c,它中不仅有SysTick定时器中断,其他所有中断都在其中。
SysTick定时器中断代码如下:
- extern unit32_t sysTickUptime;
- void SysTick_Handler(void)
- {
- sysTickUptime++;
- }
通过这段简单的代码可知:每1ms产生中断后sysTickUptime会进行加1。就是说,如果我们想知道一段代码运行了多长时间,可以在代码前面,后面分别读一下sysTickUptime的值:StartTime=sysTickUptime; 代码运行时间;EndTime=sysTickUptime;最终代码运行的时间为EndTime-StartTime(ms)
但是,在32系统时钟中,都是以兆级别的,所以一个程序运行时间很短,一般以微妙级,所以毫秒对于一些代码,可能太大,不适合,不满足要求,所以也有微妙的计数器,以下是微妙级函数:
- //延时初始化
- void Delay_init(void)
- {
- RCC_ClocksTypeDef clocks;
- //选择系统时钟HCLK作为Systick定时器的时钟,开Systick中断1ms一次
- SysTick_Config(SystemCoreClock/1000);
- RCC_GetClocksFreq(&clocks);//获取当前时钟
- usTicks = clocks.SYSCLK_Frequency/1000000;//100M/1M=100次 也就是计数100次为1us
- }
-
- //微妙计数器
- uint32_t micros(void)
- {
- //register请求编译器尽可能的将变量存在CPU内部寄存器,而不是通过内存寻址访问。
- register uint32_t ms, cycle_cnt;
- do
- {
- ms = sysTickUptime;
- cycle_cnt = SysTick->VAL;//SysTick->VAL 的计数范围10 0000~0就是1ms,递减计数器
- }while (ms != sysTickUptime);
- return (ms*1000)+ (usTicks * 1000 - cycle_cnt)/usTicks;
-
- }
我们配置SysTick定时器的计数时钟为系统时钟,也就是100Mhz,也可以说SysTick->VAL每10ns递减1,1us也就是递减100次,1ms也就是10 0000次,其实我们也可以把上面的程序改为微妙级的中断,但是这样比较消耗资源,中断频率太高对程序运行也不太友好 。因此,我们可以进行毫秒中断微秒计时的方法。usTicks表示1微秒的计数次数,usTicks=100Mhz/1Mhz=100次,那么,在我们没进毫秒中断前进行循环读取sysTickUptime和SysTick->VAL的值(毫秒级别大嘛,没产生中断前可以读很多次),SysTick->VAL是从10 0000递减到0进行一次中断sysTickUptime才加1。
所以在函数micros(void);在调用的时候,do{},while()里面的函数先进行一次执行,把两个值分别赋给ms,cycle_cnt,因为刚赋完,ms肯定=sysTickUptime,所以条件不满足,立即返回微妙计数值。等待sysTickUptime更新后,就再进入函数。就是说:do{},while()里面的循环体只有在sysTickUptime更新时才执行两次,其他情况执行一次就返回了微妙计数。
4。利用SysTick定时器设置精准延时
上面我们写出了毫秒计数器millis();i和微妙计数器micros();也知道了怎么计算程序运行时间,其实延时函数就简单为:延时多长时间计多少次数。
- //毫秒延时
- void delay_ms(unit32_t nms)
- {
- uint32_t mStart = 0;
- mStart = mills();//毫秒开始值
- while(mills()-mStart<nms)
- {}
- }
-
- //微妙延时
- void delay_us(uint32_t nus)
- {
- uint32_t uStart =0;
- uStart = micros();
- while(micros()-uStart<nus)
- {}
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。