FOC控制原理7-源码解析2-系统滴答定时器中断
1、基础框图
中断执行逻辑
19. ST FOC MC SDK5.x电机控制软件框架 — [野火]电机应用开发实战指南—基于STM32 文档 (embedfire.com)
中断频率由低到高分别为:霍尔传感器中断->SysTick中断->ADC采样中断
速度捕获->状态机->采样FOC控制
2、中断代码讲解
(1)滴答定时器中断---(2kHz)电机控制任务(1kHz)时基信号用于HAL库
/*** 函数功能: 系统滴答定时器中断* 输入参数: 无* 返 回 值: 无* 说 明: 2Khz,执行电机控制任务,同时生成1Khz的时基用于HAL库*/
void SysTick_Handler(void)
{static uint8_t SystickDividerCounter = SYSTICK_DIVIDER;if (SystickDividerCounter == SYSTICK_DIVIDER){HAL_IncTick();HAL_SYSTICK_IRQHandler(); // 1Khz(1ms)的时基SystickDividerCounter = 0;}SystickDividerCounter ++; MC_RunMotorControlTasks(); //2kHz 状态机:电机调度 中频任务
}
这段代码是一个用于处理系统滴答定时器(SysTick)中断的函数 SysTick_Handler
。SysTick 是一个24位倒计时定时器,通常用于提供系统的基准时钟信号,广泛应用于嵌入式系统中。这段代码的目的是在每秒2000次(2kHz)的频率下执行电机控制任务,同时生成一个每秒1000次(1kHz)的时基信号用于HAL库。
代码细节解释:
-
函数声明:
void SysTick_Handler(void)
SysTick_Handler
是 SysTick 定时器中断的服务程序(ISR)。当 SysTick 定时器倒计时到0时,系统会自动调用这个函数。
-
静态变量
SystickDividerCounter
:static uint8_t SystickDividerCounter = SYSTICK_DIVIDER;
SystickDividerCounter
是一个静态变量,用于分频计数。SYSTICK_DIVIDER
是一个预定义的常量,通常是2,用于将2kHz的时钟信号分频为1kHz。
-
分频逻辑:
if (SystickDividerCounter == SYSTICK_DIVIDER) {HAL_IncTick();HAL_SYSTICK_IRQHandler(); // 1Khz(1ms)的时基SystickDividerCounter = 0; } SystickDividerCounter ++;
- 每次进入
SysTick_Handler
函数时,都会检查SystickDividerCounter
是否等于SYSTICK_DIVIDER
。 - 如果相等,说明已经经过了足够的时钟周期(2个2kHz周期,即1ms),此时会调用
HAL_IncTick()
和HAL_SYSTICK_IRQHandler()
来更新 HAL 库的时基,并将SystickDividerCounter
重置为0。 - 如果
SystickDividerCounter
不等于SYSTICK_DIVIDER
,则只是简单地将SystickDividerCounter
加1。
- 每次进入
-
电机控制任务:
MC_RunMotorControlTasks(); //2kHz 状态机:电机调度 中频任务
- 在每次进入
SysTick_Handler
函数时,都会调用MC_RunMotorControlTasks()
函数,执行电机控制任务。这个任务是以2kHz的频率运行的,即每秒2000次。
- 在每次进入
总结:
- SysTick_Handler 函数以2kHz的频率被调用。
- 通过
SystickDividerCounter
变量,每2个2kHz周期(即1ms)生成一个1kHz的时基信号,用于 HAL 库的计时。 - 每次调用
SysTick_Handler
时,都会执行一次电机控制任务MC_RunMotorControlTasks()
,确保电机控制任务以2kHz的频率运行。
这段代码的核心思想是利用 SysTick 定时器的高频率中断来同时处理高频的电机控制任务和生成低频的时基信号。
HAL 库(Hardware Abstraction Layer,硬件抽象层)是 STM32 微控制器系列中提供的一个软件包,旨在简化对硬件的访问和控制,提供了一种与处理器内核和具体硬件相对独立的编程接口。在 HAL 库中,定时器功能是其重要的一部分,而 HAL_IncTick
和 HAL_SYSTICK_IRQHandler
函数则与系统的时基管理密切相关。
----------------------------------------------------------------------------------------------------------------------------
HAL 库计时的作用
-
时间测量:
- 通过 SysTick 定时器生成一个定期中断,每次中断时调用
HAL_IncTick
函数递增一个全局时间变量(通常是uwTick
),从而实现对时间的测量。这可以用于延时函数、时间戳记录等场景。
- 通过 SysTick 定时器生成一个定期中断,每次中断时调用
-
延时功能:
- HAL 库提供了一些基于时基的延时函数,如
HAL_Delay
,它通过查询uwTick
变量来实现毫秒级的延时。
- HAL 库提供了一些基于时基的延时函数,如
-
定时功能:
- 在许多应用中,需要定期执行某些任务,如传感器数据采集、状态监控等。通过 SysTick 定时器的中断,可以实现这些定时任务的调度。
-
系统功能:
- HAL 库中的一些功能,如 USB、CAN 等通信协议的实现,可能依赖于精确的时基来确保协议的正确执行。
-
RTOS 支持:
- 如果系统中运行了实时操作系统(如 ARM 的 CMSIS-RTX),SysTick 定时器常被用作操作系统的时间基准,用于任务调度、信号量处理等。
工作原理
-
SysTick 定时器配置:
- SysTick 定时器通常被配置为每1毫秒(1kHz)产生一次中断,这一中断频率是通过系统时钟分频得到的。例如,如果系统时钟为16MHz,可以通过设置 SysTick 定时器的重载值为16000来实现1ms的中断周期。
-
中断服务程序:
- 在 SysTick 定时器中断服务程序中,调用
HAL_IncTick
函数递增uwTick
变量,该变量通常是一个32位的无符号整数,表示自系统启动以来经过的毫秒数。
- 在 SysTick 定时器中断服务程序中,调用
-
时间相关的函数:
HAL_Delay
函数通过查询uwTick
变量,在达到指定延时时间时返回。HAL_GetTick
函数返回当前的uwTick
值,用于获取时间戳或计算时间差。
示例代码
以下是一个简单的 SysTick_Handler
函数示例,展示了如何使用 SysTick 定时器来生成1kHz的时基:
void SysTick_Handler(void)
{HAL_IncTick();HAL_SYSTICK_IRQHandler();
}uint32_t HAL_GetTick(void)
{return uwTick;
}void HAL_Delay(uint32_t Delay)
{uint32_t tickstart = HAL_GetTick();uint32_t wait = Delay;if ((tickstart + wait) < tickstart) {while ((HAL_GetTick() < (uint32_t)(MAX_DELAY - wait)) || ((HAL_GetTick() >= tickstart) && (HAL_GetTick() < (tickstart + wait))));} else {while ((HAL_GetTick() < (tickstart + wait)));}
}
在这段代码中:
HAL_IncTick
用于递增uwTick
变量。HAL_GetTick
返回当前的uwTick
值。HAL_Delay
通过循环等待,直到uwTick
达到预期的延时时间。
总之,HAL 库的计时功能为开发者提供了方便的时间管理工具,使得在嵌入式系统中实现定时和延时操作更加简单和可靠。
(2)电机控制调度
/*** 函数功能: 电机控制调度* 输入参数: 无* 返 回 值: 无* 说 明: 执行中等频率任务,调用该函数频率是2KHz*/
void MC_Scheduler(void)
{if (bMCBootCompleted == 1){ if(hMFTaskCounterM1 > 0u){hMFTaskCounterM1--; // 中频计数器}else{TSK_MediumFrequencyTaskM1();// 执行中等频率的任务hMFTaskCounterM1 = MF_TASK_OCCURENCE_TICKS;// 计数器复位}if(hBootCapDelayCounterM1 > 0u){hBootCapDelayCounterM1--; // 自举电容充电时间}if(hStopPermanencyCounterM1 > 0u){hStopPermanencyCounterM1--;// 状态机STOP的持续时间}}
}
这段代码是一个电机控制调度函数 MC_Scheduler
,用于在中等频率下执行电机控制相关的任务。调用该函数的频率是2kHz(每秒2000次)。下面是对这段代码的详细解释:
代码功能概述
- 函数功能:电机控制调度,执行中等频率的任务。
- 调用频率:2kHz,即每秒调用2000次。
- 主要任务:触发中等频率的任务(
TSK_MediumFrequencyTaskM1
),并管理一些计数器,用于延时或状态控制。
代码详细解释
-
函数声明:
void MC_Scheduler(void)
MC_Scheduler
函数是一个无参数、无返回值的函数,主要负责电机控制的调度任务。
-
启动完成标志检查:
if (bMCBootCompleted == 1)
bMCBootCompleted
是一个布尔类型的标志变量,表示电机控制的启动阶段是否已经完成。- 如果
bMCBootCompleted
为1(启动完成),则执行电机控制相关的任务。否则,不执行任何操作。
-
中等频率任务调度:
if(hMFTaskCounterM1 > 0u) {hMFTaskCounterM1--; // 中频计数器 } else {TSK_MediumFrequencyTaskM1(); // 执行中等频率的任务hMFTaskCounterM1 = MF_TASK_OCCURENCE_TICKS; // 计数器复位 }
hMFTaskCounterM1
是一个计数器变量,用于控制中等频率任务的执行间隔。- 如果
hMFTaskCounterM1
大于0,说明还未到达执行任务的时间,因此将其减1。 - 如果
hMFTaskCounterM1
减到0,则调用TSK_MediumFrequencyTaskM1()
函数,执行中等频率的电机控制任务。 - 执行完任务后,将
hMFTaskCounterM1
重新设置为MF_TASK_OCCURENCE_TICKS
,即复位计数器,等待下一个周期。
-
自举电容充电时间管理:
if(hBootCapDelayCounterM1 > 0u) {hBootCapDelayCounterM1--; // 自举电容充电时间 }
hBootCapDelayCounterM1
是一个计数器,用于控制自举电容充电的时间。- 如果
hBootCapDelayCounterM1
大于0,说明自举电容还在充电过程中,因此将其减1。 - 如果减到0,说明充电完成,后续可能会进入其他状态(例如启动电机等)。
-
状态机STOP的持续时间管理:
if(hStopPermanencyCounterM1 > 0u) {hStopPermanencyCounterM1--; // 状态机STOP的持续时间 }
hStopPermanencyCounterM1
是一个计数器,用于控制状态机在STOP状态的持续时间。- 如果
hStopPermanencyCounterM1
大于0,说明状态机还需要保持在STOP状态,因此将其减1。 - 如果减到0,说明STOP状态的持续时间已结束,后续可能会进入其他状态(例如启动电机等)。
总结
- 中等频率任务调度:
- 通过
hMFTaskCounterM1
计数器控制中等频率任务的执行时间,任务的执行频率由MF_TASK_OCCURENCE_TICKS
决定。
- 通过
- 自举电容充电时间管理:
- 通过
hBootCapDelayCounterM1
计数器管理自举电容的充电时间,确保在充电完成后再进行下一步操作。
- 通过
- 状态机STOP的持续时间管理:
- 通过
hStopPermanencyCounterM1
计数器管理状态机在STOP状态的持续时间,确保在规定时间内保持STOP状态。
- 通过
这段代码的核心是通过计数器来实现时间控制,确保电机控制任务在合适的时间点执行,并且能够管理一些延时任务(如自举电容充电和状态机持续时间)。