stm32初学之Systick
来源:互联网 发布:网络综艺节目排行榜 编辑:程序博客网 时间:2024/06/05 11:36
一、介绍
Systick中,Sys指系统,tick是滴答声,所以Systick就是一个系统滴答定时器。它被捆绑在 NVIC 中,用于产生 SysTick 异常(异常号:15)。SysTick的最大使命,就是定期地产生异常请求,作为系统的时基。操作系统都需要这种“滴答”来推动任务和时间的管理。
Cortex-M3 在内核部分 包含了一个简单的定时器——SysTick timer。在 STM32 中 SysTick 以 HCLK(AHB 时钟)或 HCLK/8 作为运行时钟。另外,SysTick 定时器除了能服务于操作系统之外,还能用于其它目的:如作为一个闹铃,用于测量时间等。
二、SysTick timer工作分析
Systick的介绍在STM32参考手册中没有找到,费了些时间才在权威指南和固件库手册中找到。Systick有四个寄存器:
CTRL Systick控制和状态寄存器
LOAD Systick重装载值寄存器
VAL Systick当前值寄存器
CALIB Systick标准值寄存器
在权威指南中有图说明:
图1
SysTick 是一个 24 位的定时器,即一次最多可以计数 2^24 个时钟脉冲,这个脉冲计数值被保存到 当前计数值寄存器 STK_VAL (SysTick current value register) 中,只能向下计数,每接收到一个时钟脉冲 STK_VAL 的值就向下减1,直至 0,当 STK_VAL 的值被减至 0 时,由硬件自动把重载寄存器STK_LOAD(SysTick reload value register)中保存的数据加载到 STK_VAL,重新向下计数。当 STK_VAL 的值被计数至 0 时,触发异常,就可以在中断服务函数中处理定时事件了。
SysTick只有三个控制位和一个标志位,都位于寄存器 STK_CTRL(SysTick control and status register )中,如下图:
图2
Bit0: ENABLE 为 SysTick timer 的使能位,此位为 1 的时候使能 SysTick timer,此位为 0的时候关闭 SysTick timer。
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编程
首先看了一下固件库函数,发现有六个,但我只找到了SysTick_CLKSourceConfig这个时钟源配置函数,在misc.c中,其他的库函数没有找到(库版本问题?),之后查资料发现大家都不怎么用这些函数,都是使用SysTick_Config函数来配置,这个函数位于core_cm3.h中,其具体代码如下:
static __INLINE uint32_t SysTick_Config(uint32_t ticks){ if (ticks > SysTick_LOAD_RELOAD_Msk) return (1); /* Reload value impossible */ SysTick->LOAD = (ticks & SysTick_LOAD_RELOAD_Msk) - 1; /* set reload register */ NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1); /* set Priority for Cortex-M0 System Interrupts */ SysTick->VAL = 0; /* 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 (0); /* Function successful */}
函数的功能是启动了 SysTick timer;并把它配置为计数至 0 时引起中断;输入的参数 ticks 为两个中断之间的脉冲数,即相隔 ticks 个时钟周期会引起一次中断;配置 SysTick 成功时返回 0,出错进返回 1。
首先,检查输入参数ticks,这里用了一个宏SysTick_LOAD_RELOAD_Msk,在同一文件中可以找到其定义和代码下面所用到宏的定义,代码如下:
#define SysTick_CTRL_CLKSOURCE_Pos 2 /*!< SysTick CTRL: CLKSOURCE Position */#define SysTick_CTRL_CLKSOURCE_Msk (1ul << SysTick_CTRL_CLKSOURCE_Pos) /*!< SysTick CTRL: CLKSOURCE Mask */#define SysTick_CTRL_TICKINT_Pos 1 /*!< SysTick CTRL: TICKINT Position */#define SysTick_CTRL_TICKINT_Msk (1ul << SysTick_CTRL_TICKINT_Pos) /*!< SysTick CTRL: TICKINT Mask */#define SysTick_CTRL_ENABLE_Pos 0 /*!< SysTick CTRL: ENABLE Position */#define SysTick_CTRL_ENABLE_Msk (1ul << SysTick_CTRL_ENABLE_Pos) /*!< SysTick CTRL: ENABLE Mask *//* SysTick Reload Register Definitions */#define SysTick_LOAD_RELOAD_Pos 0 /*!< SysTick LOAD: RELOAD Position */#define SysTick_LOAD_RELOAD_Msk (0xFFFFFFul << SysTick_LOAD_RELOAD_Pos) /*!< SysTick LOAD: RELOAD Mask */由图1 可知,STK_LOAD 和 STK_VAL 都是 24 位的,ticks 是脉冲计数值,要被保存到重载寄存器 STK_LOAD 寄存器中,再由硬件把 STK_LOAD 值加载到当前计数值寄存器 STK_VAL 使用,所以ticks不能超过其最大存储值。另外这里的SysTick_xxx_Pos就是相应寄存器中的位置,SysTick_xxx_Msk是相应寄存器的位全部置1后,左移SysTick_xxx_Pos 位,利用&、|运算可以方便地修改寄存器的某些位。
接下来将值赋给STK_LOAD寄存器,这里用到了一个指针SysTick ,找到其定义为:
#define SysTick ((SysTick_Type *) SysTick_BASE) /*!< SysTick configuration struct */说明SysTick是一个SysTick_Type类型的指针,继续跳转,可以看到SysTick_Type的定义:
typedef struct{ __IO uint32_t CTRL; /*!< Offset: 0x00 SysTick Control and Status Register */ __IO uint32_t LOAD; /*!< Offset: 0x04 SysTick Reload Value Register */ __IO uint32_t VAL; /*!< Offset: 0x08 SysTick Current Value Register */ __I uint32_t CALIB; /*!< Offset: 0x0C SysTick Calibration Register */} SysTick_Type;原来寄存器的定义就包含在这个结构体中。
然后调用了NVIC_SetPriority函数来配置SysTick中断,同样可以在同一文件中找到它的具体代码:
static __INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority){ if(IRQn < 0) { SCB->SHP[((uint32_t)(IRQn) & 0xF)-4] = ((priority << (8 - __NVIC_PRIO_BITS)) & 0xff); } /* set Priority for Cortex-M3 System Interrupts */ else { NVIC->IP[(uint32_t)(IRQn)] = ((priority << (8 - __NVIC_PRIO_BITS)) & 0xff); } /* set Priority for device specific Interrupts */}这个是用来配置中断的优先级的,第一个参数是中断类型,第二个是优先级,比较复杂。
配置好中断后,将 STK_VAL 寄存器重新赋值为 0,当使能SysTick时,硬件会把存储在 STK_LOAD 寄存器中的 ticks 值加载给它。
在这段代码的最后,向 STK_CTRL 寄存器写入了 SysTick timer 的控制参数,由以上宏分析知是将CTRL寄存器的[2:0]都设为了1。又由图1及图2可知,设为1时,分别是使用内核时钟(FCLK)、计数至 0 时引起中断和使能 SysTick。当然你也可以自己修改成自己需要的参数。
在执行完这段代码后,SysTick 就开始运行,进行脉冲计数了。不过运行完这个函数后,SysTick就开启了,但我们一般是在需要的时候才用它,所以在运行完这个函数后最好先将它关闭。可以使用如下方法:
// 使能滴答定时器 SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;// 失能滴答定时器 SysTick->CTRL &= ~ SysTick_CTRL_ENABLE_Msk;
例如:
void SysTick_Init(){if (SysTick_Config(SystemCoreClock / 100000)) //SystemCoreClock 为定义了系统时钟(SYSCLK)频率的宏,即等于 AHB 的时钟频率,被设置成72MHz{while (1);}SysTick->CTRL &= ~ SysTick_CTRL_ENABLE_Msk;}至于时间的计算,公式为: T=ticks*(1/f) , T为总时间,1/ f 即为 SysTick timer 使用的时钟源的时钟周期,f 为该时钟源的时钟频率,当时钟源确定后为常数。
通过计算可得出此函数延时为10us。只要在主函数中将SysTick使能开启,就能使用10us的精确延时了。
int main(void){ SystemInit();SysTick_Init();SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;......}
- stm32初学之Systick
- STM32之SysTick
- STM32之SysTick
- stm32之systick
- STM32之SysTick学习
- stm32之SysTick定时器
- stm32之systick应用
- STM32之SysTick定时器
- stm32之systick
- STM32之SysTick嘀嗒定时器
- stm32之SysTick的理解
- STM32之SysTick(系统定时器)
- stm32 systick
- STM32 Systick
- stm32 systick
- STM32 SysTick
- STM32之用SysTick做准确定时
- STM32之用SysTick做准确定时
- WinMain函数学习笔记
- Java设计模式之从[剪刀石头布AI策略]分析策略(Strategy)模式
- 1
- UVA 1267 - Network
- java多线程基础概要
- stm32初学之Systick
- 设计模式六大原则之--开闭原则(OCP)
- 关于C#/WPF的SerialPort类串口接受数据异常的问题
- Java Web中的过滤器Filter
- 数据库加锁小结
- 如何批量修改文件名
- C语言中getchar()函数的理解
- 黑马程序员-Java多线程和定时器
- 简析正则中的环视