[英]STM32 - While loop blocking behaviour of timerUpdate callback in stepper motor application
我正在使用 STM32F103C8T6 和 HAL 库在 2 轴 CNC 机器上工作。 我已经为机器的每个轴设置了一个单独的计时器,并将它们配置为 PWM 模式。
我有一个名为 step_x(numberSteps, Direction) 的函数,它接受两个参数,分别是要执行的步数和要移动的方向。该函数将步数设置为全局变量中的目标步数,设置通过 GPIO 写入的方向,然后使用 HAL 库在中断模式下启动 PWM:
void step_x(uint32_t numberSteps, uint16_t direction){
RELEASE_X=0;
steps_x_target = numberSteps;
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, direction_x);
__HAL_TIM_ENABLE_IT(&htim1, TIM_IT_UPDATE);
HAL_TIM_PWM_Start_IT(&htim1, TIM_CHANNEL_1);
}
然后启动PWM,我通过定时器更新回调函数计算脉冲数:
void TIM1_UP_IRQHandler(void)
{
if (__HAL_TIM_GET_FLAG(&htim1, TIM_FLAG_UPDATE))
{
if (__HAL_TIM_GET_IT_SOURCE(&htim1, TIM_IT_UPDATE))
{
step_update('X');
__HAL_TIM_CLEAR_FLAG(&htim1, TIM_FLAG_UPDATE);
__HAL_TIM_CLEAR_FLAG(&htim1,TIM_FLAG_CC1 );
}
}
}
在这个回调中, step_update() 被调用,将我正在使用的轴作为参数。
step_update 函数将已发生的步数加 1,并在步数等于设置的目标步数时停止 PWM。 它还调用一个函数,该函数以毫米而不是步长跟踪位置。 (为简洁起见,删除了 Y 和 Z 轴案例)
void step_update(char axis){
switch(axis){
case 'X':
steps_x++;
updatePosition(axis);
if(steps_x==(2*steps_x_target)){ //check if 2* because the update event happens twice every pulse
HAL_TIM_PWM_Stop(&htim1, TIM_CHANNEL_1);
steps_x_target=0;
steps_x=0;
RELEASE_X=1;
if(limitSwitchX_Trigger==1){
positionX=0;
limitSwitchX_Trigger=0;
NVIC_EnableIRQ(EXTI0_IRQn);
}
}
break;
case 'Y':
break;
case 'Z':
break;
}
}
我确信这不是一种完全有效的方法,但是它工作得很好,除了我无法调用 step_x() 函数并在调用下一个函数之前等待它完成。 我添加了 volatile 变量 RELEASE_X,它在 step_x() 被调用时设置为 0,当 step_update() 函数在达到目标步骤时停止 PWM 时设置为 1。 我认为使用这个我可以做这样的事情,我希望在一个方向上步进 800 个脉冲,然后在另一个方向上步进 800 个脉冲:
step_x(800,0);
while(RELEASE_X!=1);
step_x(800,1);
然而,发生的情况是,while 循环最终阻止了 Timer1_Update 回调的发生,并且不会对脉冲进行计数。 我期望因为脉冲计数是在 ISR 回调中完成的,所以 MCU 会从这个 while 循环跳转到 ISR 并更新步骤直到 RELEASE_X 设置为 true 然后前进到 step_x() 的下一次调用? 为什么不是这样?
有人可以建议一种我可以编写代码的方法,它允许我调用一个函数,该函数在等待它们完成之前执行一定数量的步骤,然后再继续下一次调用吗? 我正在尝试接下来实现 Bresenhams 线算法,因此我需要执行一定数量的步骤,然后仅从调用返回并在步骤完成时前进到下一行代码。 (本质上,我怎样才能使这个功能阻塞但不切换 GPIO 引脚/位攻击)
这并不是为什么会发生这种情况的真正答案,但我通过在 NVIC 选项卡下禁用 CubeMX 中的计时器更新和全局中断解决了这个问题。 我从 main.h 和 main.c 中删除了回调函数,然后将 step_x 函数修改为:
void step_x(uint32_t numberSteps, uint16_t direction){
RELEASE_X=0;
steps_x_target = numberSteps;
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_5, direction_x);
__HAL_TIM_ENABLE_IT(&htim1, TIM_IT_UPDATE);
HAL_TIM_PWM_Start_IT(&htim1, TIM_CHANNEL_1);
while(RELEASE_X!=1){
if (__HAL_TIM_GET_FLAG(&htim1, TIM_FLAG_UPDATE))
{
if (__HAL_TIM_GET_IT_SOURCE(&htim1, TIM_IT_UPDATE))
{
step_update('X');
__HAL_TIM_CLEAR_FLAG(&htim1, TIM_FLAG_UPDATE);
__HAL_TIM_CLEAR_FLAG(&htim1,TIM_FLAG_CC1 );
}
}
}
}
基本上只是将回调函数中的代码移动到 step_x 函数中的 while 循环中。 该函数现在是一个阻塞函数,无论如何这正是我所需要的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.