繁体   English   中英

STM32 - 步进电机应用程序中 timerUpdate 回调的 While 循环阻塞行为

[英]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 引脚/位攻击)

https://github.com/Blargian/EPR400

这并不是为什么会发生这种情况的真正答案,但我通过在 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM