Systick精确延时实验
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
本函数实际上只是调用了 SysTick_Config()函数,它是属于内核层的 Cortex-M3 通用 函数,位于 core_cm3.h 文件中,若调用 SysTick_Config() 配置 SysTick 不成功,则进入 死循环。
代码分析 2: SysTick_Config()函数详解
这个函数配置 24 位的倒计数 Systick 定时器,当计到 0 时引起中断,并从 STK_LOAD 寄存器中自动重装载定时初值。只要不把它在 SysTick 控制及状态寄存器中的使能位清除, 就永不停息。输入的参数 ticks 经过处理送 STK_LOAD 寄存器,为两个中断之间的脉冲数(定 时初值),即相隔 ticks 个时钟周期会引起一次中断;配置 SysTick 成功时返回 0,出错进 返回 1。
第二行代码“SysTick->LOAD = (ticks & SysTick_LOAD_RELOAD_Msk) - 1” 稍稍处 理一下把 ticks-1 赋值给 STK_LOAD 寄存器,要注意的是减 1,若 STK_VAL 从 ticks-1 向下 计数至 0,实际上就经过了 ticks 个脉冲。
最后一行代码设置了 Systick 的 CTRL 寄存器,配置 SysTick 定时器时钟频率为 AHB (72MHz)。同时使能 Systick 定时器和 Systick 定时器中断。
代码分析 3:中断服务函数详解 void SysTick_Handler(void) {
TimingDelay_Decrement(); } 调用 TimingDelay_Decrement()函数 void TimingDelay_Decrement(void) {
第三行代码 “NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1)”配 置中断向量及重置 STK_VAL 寄存器。配置了 SysTick 中断,这就是为什么我们在外部没有再 使用 NVIC 配置 SysTick 中断的原因。
第四行代码“SysTick->VAL = 0”把 STK_VAL 寄存器重新赋值为 0(在使能 SysTick 时,硬件会把存储在 STK_LOAD 寄存器中的 ticks 值加载给它)。
装载定时初值。只要不把它在SysTick控制及状态寄存器中的使能位清除,就永不停息。
SysTick相关的几个寄存器的寄存器不算多,相关的说明《STM32F10
● SysTick相关的4个寄存器名称和地址如下:
SysTick_CTRL
0xE000E010 -- 控制寄存器
SysTick_LOAD
0xE000E014 -- 重载寄存器
SysTick_VAL
0xE000E018 -- 当前值寄存器
SysTick_CALIB
0xE000E01C -- 校准值寄存器
SysTick_CTRL SysTick控制与状态寄存器
可以看到实际使用只用到了其中的4位,如下表所示:
位CLKSOURCE用于选择Systick定时器时钟。当为1时,Systick定时器时钟为AHB。当为0 时,Systick定时器时钟为AHB/8。 SysTick_LOAD 重装值寄存器
需要振荡的次数 * 每次的振荡时间 = 72M/10000000 * 1/72M = 1/1000000 = 0.000001 秒 = 1微秒=1us。
也就是说,systick 定时器每隔 1us 时钟就会产生一次 systick 的中断。 7.1.3 代码分析
我们从主函数开始.
调用函数 LED_Init()初始化板载 LED 灯,调用函数 SZ_STM32_SysTickInit()配置 Systick,进入 while 循环,点亮 4 个 LED 灯,延时 1 秒时间,熄灭 LED 灯,再延时 1 秒时 间。如此循环。我们这里主要分析的是 SZ_STM32_SysTickInit( )函数。 代码分析 1:函数 SZ_STM32_SysTickInit()分析。
第一行代码“if (ticks > SysTick_LOAD_RELOAD_Msk) return (1)”检查输入参数 ticks,因为 ticks 是定时初值,要被保存到重载寄存器 STK_LOAD 寄存器中,再由硬件把 STK_LOAD 值加载到 当前计数值寄存器 STK_VAL 使用的,STK_LOAD 和 STK_VAL 都是 24 位的, 所以当输入参数 ticks 大于其可存储的最大值时,将由这行代码检查出错误返回。
本实验,通过 Systick 定时器,进行精确的 1 秒延时。将代码下载到开发板,按下复位 按键使用逻辑分析仪测量管脚电平变化的时间,从而得初延时的时间。如下图:
这句赋值代码中使用到了宏 SysTick_LOAD_RELOAD_Msk,与其它库函数类似,这样子的 宏是用来指示寄存器的特定位置 或进行位屏蔽用的。类似的宏定义如下:
这里0xFFFFFFul,ul表示无符号长整型数值。0xFFFFFF6位的16进制刚好是24位的2进制。 0xFFFFFFul左移SysTick_LOAD_RELOAD_Pos位,SysTick_LOAD_RELOAD_Pos等于0。即 SysTick_LOAD_RELOAD_Msk 等于0xFFFFFFul左移0位。像这样子的操作,在控制寄存器的代 码(大部分库函数)中用得十分广泛。
通过对参数 nTime 的设定,确定延时时间。延时函数和 Systick 定时器中断的关联如下
图:
调用 Delay_us()函数,对一个 LED 灯的 GPIO 管脚的进行拉高 10us 在拉低 10us。通过 仪器测量得出波形如下:
实际高电平持续的时间是 10.5833 微秒,注意这个测得的时间是高电平持续的时候,而 不延时函数的延时时间。这个多出来的 0.5833 微秒是因为,延时函数中调用了赋值语句, 设置寄存器语句,同时调用库函数将 GPIO 管脚的电平拉低也消耗一定的时候。这样子的话, 延时函数的误差是非常的小的。微秒级的延时函数就有那么高的精确度,那么当我们调用 Delay_ms()函数,进行毫秒级的延时的时候,0.5833 微秒的差异几乎等于没有差异。 7.1.4 实验现象
for (; nCount != 0; nCount--); }
延时是通过给 nCount 设置值,CPU 循环执行变量 nCount 自减实现。对于 STM32 系列微
处理器来说,很难计算出延时的精确值。当我们需要精确延时是,可以利用 Systick 来设计。
SysTick其实就是一个24位的倒计数定时器,当计到0时,将从STK_LOAD寄存器中自动重
if (TimingDelay != 0x00) {
TimingDelay--; } } Systick 定时器每中断一次 TimingDelay 减 1,就表示时间过了 1 微秒。
代码分析 4:延时函数 Delay_us( )
延时函数有一个参数 nTime,函数中首先通过 nTime 对 TimingDelay 进行赋值。然后, 对 Systick 定时器 CTRL 寄存器的 ENABLE 位进行置 1,重载计数值,使能 Systick 定时器。 “while(TimingDelay != 0)”代码,等待 TimingDelay 变为 0。Systick 定时器每中断一次 TimingDelay 减 1,即时间过了 1 微秒。最后对 Systick 定时器 CTRL 寄存器的 ENABLE 位进 行置 0,关闭 Systick 定时器,完成一次延时。
SysTick一个递减的计数器,当计数器递减到“0”时,重装寄存器中的值就会被重 装。SysTick_LOAD重装值寄存器是一个24位宽的寄存器,如下图所示:
SysTick_VAL 当前值寄存器 使用SysTick当前值寄存器来查找寄存器中的当前值。具体寄存器的位分配如下所示:
SysTick_CALIB 校准寄存器 使用校准寄存器通过乘法或是除法运算可以将寄存器调节成任意所需的时钟速率,如下
7.1 SysTick系统滴答实验
我们学习 NVIC 向量中断控制器的时候,ST 官方提供的参考手册中几乎没有涉及 NVIC 的内容。我们要了解它里面的寄存器的话还要参考《STM32F10xxx 的 Cortex-M3 编程手 册.pdf》。Systick 定时器的情况和 NVIC 类似。
STM32 采用的是 Cortex-M3 的核,NVIC 和 Systick 在 Cortex-M3 的手册中都有详细的 介绍。要注意的是 STM32 中的 NVIC、Systick 和 Cortex-M3 中的 NVIC、Systick 是有一些 差异的。
● SysTick 定时器的作用
(1)产生操作系统的时钟节拍 SysTick 定时器被捆绑在 NVIC 中,用于产生 SYSTICK 异常(异常号:15)。在以前,大
多操作系统需要一个硬件定时器来产生操作系统需要的滴答中断,作为整个系统的时基。因 此,需要一个定时器来产生周期性的中断,而且最好还让用户程序不能随意访问它的寄存器, 以维持操作系统“心跳”的节律。SysTick 的最大使命,就是定期地产生异常请求,作为系 统的时基。OS 都需要这种“滴答”来推动任务和时间的管理。
(2)便于不同处理器之间程序移植。 Cortex‐M3 处理器内部包含了一个简单的定时器。因为所有的 CM3 芯片都带有这个定
时器,软件在不同 CM3 器件间的移植工作得以化简。该定时器的时钟源可以是内部时钟 (FCLK,CM3 上的自由运行时钟),或者是外部时钟(CM3 处理器上的 STCLK 信号)。不过, STCLK 的具体来源则由芯片设计者决定,因此不同产品之间的时钟频率可能会大不相同,你 需要检视芯片的器件手册来决定选择什么作为时钟源。SysTick 定时器能产生中断,CM3 为 它专门开出一个异常类型,并且在向量表中有它的一席之地。它使操作系统和其它系统软件 在 CM3 器件间的移植变得简单多了,因为在所有 CM3 产品间对其处理都是相同的。
(3)作为一个闹铃测量时间。 SysTick 定时器还可以用作闹钟,作为启动一个特定任务的时间依据。它作为一个闹铃,
用于测量时间。要注意的是,当处理器在调试期间被喊停(halt)时,则 SysTick 定时器亦 将暂停运作。
● SysTick 定时器的时钟源
如下图:
Systick 定时器的时钟源可以是内部时钟(FCLK,CM3 上的自由运行时钟),或者是外部 时钟( CM3 处理器上的 STCLK 信号)。不过,STCLK 的具体来源则由芯片设计者决定,因此 不同产品之间的时钟频率可能会大不相同。因此,需要阅读芯片的使用手册来确定选择什么 作为时钟源。
STM32 中,我们可以通过代码配置 Systick 定时器的时钟等于 AHB 时钟或者是 AHB 时钟 /8。
7.1.2 实验原理 本实验我们通过 Systick,进行精确的延时。 在前面的学习中,我们使用的延时函数 delay():
void delay(__IO uint32_t nCount) {
7.1.1 Systick简介
● 什么是 SysTick 定时器 SysTick,系统滴答声 。系统滴答滴答很形象地表示了它是一个系统节拍器。SysTick 是
一个 24 位的倒计数定时器,当计到 0 时,将从 RELOAD 寄存器中自动重装载定时初值。只 要不把它在 SysTick 控制及状态寄存器中的使能位清除,就永不停息。
所示:
● Systick定时器定时时间的计算
本实验中,我们给Systick定时器,配置的时钟频率是72MHz。1Hz表示1秒震荡1次,72MHz 表示1秒震荡72M次,那么每次振荡时间是1/72MHZ。现在需要振荡72M/1000000次,总共所花 的时间用以下公式来算(72M=72000000):
代码分析 2: SysTick_Config()函数详解
这个函数配置 24 位的倒计数 Systick 定时器,当计到 0 时引起中断,并从 STK_LOAD 寄存器中自动重装载定时初值。只要不把它在 SysTick 控制及状态寄存器中的使能位清除, 就永不停息。输入的参数 ticks 经过处理送 STK_LOAD 寄存器,为两个中断之间的脉冲数(定 时初值),即相隔 ticks 个时钟周期会引起一次中断;配置 SysTick 成功时返回 0,出错进 返回 1。
第二行代码“SysTick->LOAD = (ticks & SysTick_LOAD_RELOAD_Msk) - 1” 稍稍处 理一下把 ticks-1 赋值给 STK_LOAD 寄存器,要注意的是减 1,若 STK_VAL 从 ticks-1 向下 计数至 0,实际上就经过了 ticks 个脉冲。
最后一行代码设置了 Systick 的 CTRL 寄存器,配置 SysTick 定时器时钟频率为 AHB (72MHz)。同时使能 Systick 定时器和 Systick 定时器中断。
代码分析 3:中断服务函数详解 void SysTick_Handler(void) {
TimingDelay_Decrement(); } 调用 TimingDelay_Decrement()函数 void TimingDelay_Decrement(void) {
第三行代码 “NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1)”配 置中断向量及重置 STK_VAL 寄存器。配置了 SysTick 中断,这就是为什么我们在外部没有再 使用 NVIC 配置 SysTick 中断的原因。
第四行代码“SysTick->VAL = 0”把 STK_VAL 寄存器重新赋值为 0(在使能 SysTick 时,硬件会把存储在 STK_LOAD 寄存器中的 ticks 值加载给它)。
装载定时初值。只要不把它在SysTick控制及状态寄存器中的使能位清除,就永不停息。
SysTick相关的几个寄存器的寄存器不算多,相关的说明《STM32F10
● SysTick相关的4个寄存器名称和地址如下:
SysTick_CTRL
0xE000E010 -- 控制寄存器
SysTick_LOAD
0xE000E014 -- 重载寄存器
SysTick_VAL
0xE000E018 -- 当前值寄存器
SysTick_CALIB
0xE000E01C -- 校准值寄存器
SysTick_CTRL SysTick控制与状态寄存器
可以看到实际使用只用到了其中的4位,如下表所示:
位CLKSOURCE用于选择Systick定时器时钟。当为1时,Systick定时器时钟为AHB。当为0 时,Systick定时器时钟为AHB/8。 SysTick_LOAD 重装值寄存器
需要振荡的次数 * 每次的振荡时间 = 72M/10000000 * 1/72M = 1/1000000 = 0.000001 秒 = 1微秒=1us。
也就是说,systick 定时器每隔 1us 时钟就会产生一次 systick 的中断。 7.1.3 代码分析
我们从主函数开始.
调用函数 LED_Init()初始化板载 LED 灯,调用函数 SZ_STM32_SysTickInit()配置 Systick,进入 while 循环,点亮 4 个 LED 灯,延时 1 秒时间,熄灭 LED 灯,再延时 1 秒时 间。如此循环。我们这里主要分析的是 SZ_STM32_SysTickInit( )函数。 代码分析 1:函数 SZ_STM32_SysTickInit()分析。
第一行代码“if (ticks > SysTick_LOAD_RELOAD_Msk) return (1)”检查输入参数 ticks,因为 ticks 是定时初值,要被保存到重载寄存器 STK_LOAD 寄存器中,再由硬件把 STK_LOAD 值加载到 当前计数值寄存器 STK_VAL 使用的,STK_LOAD 和 STK_VAL 都是 24 位的, 所以当输入参数 ticks 大于其可存储的最大值时,将由这行代码检查出错误返回。
本实验,通过 Systick 定时器,进行精确的 1 秒延时。将代码下载到开发板,按下复位 按键使用逻辑分析仪测量管脚电平变化的时间,从而得初延时的时间。如下图:
这句赋值代码中使用到了宏 SysTick_LOAD_RELOAD_Msk,与其它库函数类似,这样子的 宏是用来指示寄存器的特定位置 或进行位屏蔽用的。类似的宏定义如下:
这里0xFFFFFFul,ul表示无符号长整型数值。0xFFFFFF6位的16进制刚好是24位的2进制。 0xFFFFFFul左移SysTick_LOAD_RELOAD_Pos位,SysTick_LOAD_RELOAD_Pos等于0。即 SysTick_LOAD_RELOAD_Msk 等于0xFFFFFFul左移0位。像这样子的操作,在控制寄存器的代 码(大部分库函数)中用得十分广泛。
通过对参数 nTime 的设定,确定延时时间。延时函数和 Systick 定时器中断的关联如下
图:
调用 Delay_us()函数,对一个 LED 灯的 GPIO 管脚的进行拉高 10us 在拉低 10us。通过 仪器测量得出波形如下:
实际高电平持续的时间是 10.5833 微秒,注意这个测得的时间是高电平持续的时候,而 不延时函数的延时时间。这个多出来的 0.5833 微秒是因为,延时函数中调用了赋值语句, 设置寄存器语句,同时调用库函数将 GPIO 管脚的电平拉低也消耗一定的时候。这样子的话, 延时函数的误差是非常的小的。微秒级的延时函数就有那么高的精确度,那么当我们调用 Delay_ms()函数,进行毫秒级的延时的时候,0.5833 微秒的差异几乎等于没有差异。 7.1.4 实验现象
for (; nCount != 0; nCount--); }
延时是通过给 nCount 设置值,CPU 循环执行变量 nCount 自减实现。对于 STM32 系列微
处理器来说,很难计算出延时的精确值。当我们需要精确延时是,可以利用 Systick 来设计。
SysTick其实就是一个24位的倒计数定时器,当计到0时,将从STK_LOAD寄存器中自动重
if (TimingDelay != 0x00) {
TimingDelay--; } } Systick 定时器每中断一次 TimingDelay 减 1,就表示时间过了 1 微秒。
代码分析 4:延时函数 Delay_us( )
延时函数有一个参数 nTime,函数中首先通过 nTime 对 TimingDelay 进行赋值。然后, 对 Systick 定时器 CTRL 寄存器的 ENABLE 位进行置 1,重载计数值,使能 Systick 定时器。 “while(TimingDelay != 0)”代码,等待 TimingDelay 变为 0。Systick 定时器每中断一次 TimingDelay 减 1,即时间过了 1 微秒。最后对 Systick 定时器 CTRL 寄存器的 ENABLE 位进 行置 0,关闭 Systick 定时器,完成一次延时。
SysTick一个递减的计数器,当计数器递减到“0”时,重装寄存器中的值就会被重 装。SysTick_LOAD重装值寄存器是一个24位宽的寄存器,如下图所示:
SysTick_VAL 当前值寄存器 使用SysTick当前值寄存器来查找寄存器中的当前值。具体寄存器的位分配如下所示:
SysTick_CALIB 校准寄存器 使用校准寄存器通过乘法或是除法运算可以将寄存器调节成任意所需的时钟速率,如下
7.1 SysTick系统滴答实验
我们学习 NVIC 向量中断控制器的时候,ST 官方提供的参考手册中几乎没有涉及 NVIC 的内容。我们要了解它里面的寄存器的话还要参考《STM32F10xxx 的 Cortex-M3 编程手 册.pdf》。Systick 定时器的情况和 NVIC 类似。
STM32 采用的是 Cortex-M3 的核,NVIC 和 Systick 在 Cortex-M3 的手册中都有详细的 介绍。要注意的是 STM32 中的 NVIC、Systick 和 Cortex-M3 中的 NVIC、Systick 是有一些 差异的。
● SysTick 定时器的作用
(1)产生操作系统的时钟节拍 SysTick 定时器被捆绑在 NVIC 中,用于产生 SYSTICK 异常(异常号:15)。在以前,大
多操作系统需要一个硬件定时器来产生操作系统需要的滴答中断,作为整个系统的时基。因 此,需要一个定时器来产生周期性的中断,而且最好还让用户程序不能随意访问它的寄存器, 以维持操作系统“心跳”的节律。SysTick 的最大使命,就是定期地产生异常请求,作为系 统的时基。OS 都需要这种“滴答”来推动任务和时间的管理。
(2)便于不同处理器之间程序移植。 Cortex‐M3 处理器内部包含了一个简单的定时器。因为所有的 CM3 芯片都带有这个定
时器,软件在不同 CM3 器件间的移植工作得以化简。该定时器的时钟源可以是内部时钟 (FCLK,CM3 上的自由运行时钟),或者是外部时钟(CM3 处理器上的 STCLK 信号)。不过, STCLK 的具体来源则由芯片设计者决定,因此不同产品之间的时钟频率可能会大不相同,你 需要检视芯片的器件手册来决定选择什么作为时钟源。SysTick 定时器能产生中断,CM3 为 它专门开出一个异常类型,并且在向量表中有它的一席之地。它使操作系统和其它系统软件 在 CM3 器件间的移植变得简单多了,因为在所有 CM3 产品间对其处理都是相同的。
(3)作为一个闹铃测量时间。 SysTick 定时器还可以用作闹钟,作为启动一个特定任务的时间依据。它作为一个闹铃,
用于测量时间。要注意的是,当处理器在调试期间被喊停(halt)时,则 SysTick 定时器亦 将暂停运作。
● SysTick 定时器的时钟源
如下图:
Systick 定时器的时钟源可以是内部时钟(FCLK,CM3 上的自由运行时钟),或者是外部 时钟( CM3 处理器上的 STCLK 信号)。不过,STCLK 的具体来源则由芯片设计者决定,因此 不同产品之间的时钟频率可能会大不相同。因此,需要阅读芯片的使用手册来确定选择什么 作为时钟源。
STM32 中,我们可以通过代码配置 Systick 定时器的时钟等于 AHB 时钟或者是 AHB 时钟 /8。
7.1.2 实验原理 本实验我们通过 Systick,进行精确的延时。 在前面的学习中,我们使用的延时函数 delay():
void delay(__IO uint32_t nCount) {
7.1.1 Systick简介
● 什么是 SysTick 定时器 SysTick,系统滴答声 。系统滴答滴答很形象地表示了它是一个系统节拍器。SysTick 是
一个 24 位的倒计数定时器,当计到 0 时,将从 RELOAD 寄存器中自动重装载定时初值。只 要不把它在 SysTick 控制及状态寄存器中的使能位清除,就永不停息。
所示:
● Systick定时器定时时间的计算
本实验中,我们给Systick定时器,配置的时钟频率是72MHz。1Hz表示1秒震荡1次,72MHz 表示1秒震荡72M次,那么每次振荡时间是1/72MHZ。现在需要振荡72M/1000000次,总共所花 的时间用以下公式来算(72M=72000000):