首页 > 解决方案 > ISR 无法更改嵌入式 C 中的外部结构字段

问题描述

我在 Nucleo 上遇到了 STM32F091RCT 的问题,我用它来控制步进电机驱动器 DRV8825。

下面代码部分的主要目标是在步进电机旋转过多时停止步进电机,使用霍尔开关和磁铁的中断。我还在为 STM32 使用 HAL 库,当然还有 C 语言。

我有这些文件:

电机.h:

typedef struct{
   volatile uint8_t STOP_FLAG
} Motor;

电机.c:

#include "motor.h"

void ClearStopFlag(Motor *motor)
{
  motor->STOP_FLAG = 0;
}

void SetStopFlag(Motor *motor)
{
  motor->STOP_FLAG = 1;
}

uint8_t GetStopFlag(Motor *motor)
{
  return motor->STOP_FLAG;
}

void Init(Motor *motor)
{
  ClearStopFlag(motor); 
}

void Rotate(Motor *motor)
{
  int i;
  for(i = 0; i < 50; i++)      // every iteration is a motor step
  {
    if(GetStopFlag(motor)) break;
    // irrelevant code switching the output used for driver step input ----
  }
}

void Disable(Motor *motor)
{
  // Code that sets the GPIO pin responsible for ENABLE pin in the driver ----
}

大厅.c:

#include "motor.h"
#include "exec.h"

extern Motor m;

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
  SetStopFlag(&m);
}

执行.c:

#include "hall.h"
#include "motor.h"

Motor m;

void SomeFunction(void)
{
  Init(&m);
  Rotate(&m); // here GPIO ISR in hall.c doesn't set the STOP_FLAG while Rotate() is executing
}

主.c:

#include "exec.h"
int main(void)
{
  SomeFunction();
  return 0;
}

首先,原始代码要复杂得多,这里我没有包含一些用于函数原型、其他 Motor 结构字段、其他函数等的头文件。我现在无法访问代码它也很多这样更干净。

我测试了很多,问题是GPIO中断回调函数不能改变STOP_FLAG变量。这是它的行为方式:

有人知道为什么 hall.c 在访问 struct 字段时遇到问题吗?

标签: cembeddedstm32hal

解决方案


问题出在其他地方。

您提供的代码无法重现它。

我为带有两个 LED(LD3onPB7LD4on PB6)和一个按钮(B1on PA0)的 Discovery 板创建了一个最小的 CubeMX 项目,然后添加了您的代码。

motor.c:将循环更改为无限循环,因为我不相信自己能够在几微秒内按下按钮并测量差异

void Rotate(Motor *motor)
{
  while(1)      // every iteration is a motor step
  {
    if(GetStopFlag(motor))
        break;
    // irrelevant code switching the output used for driver step input ----
  }
}

main.c:添加了初始化和反馈。

#include "main.h"
#include "stm32l1xx_hal.h"

void EXTI0_IRQHandler(void) {
    HAL_GPIO_EXTI_IRQHandler(B1_Pin);
}

void EXTILine0_Config(void) {
    GPIO_InitTypeDef GPIO_InitStructure = { 0 };
    GPIO_InitStructure.Mode = GPIO_MODE_IT_FALLING;
    GPIO_InitStructure.Pull = GPIO_NOPULL;
    GPIO_InitStructure.Pin = B1_Pin;
    HAL_GPIO_Init(B1_GPIO_Port, &GPIO_InitStructure);
    HAL_NVIC_SetPriority(EXTI0_IRQn, 3, 0);
    HAL_NVIC_EnableIRQ(EXTI0_IRQn);
}

int main(void) {
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  EXTILine0_Config();
  SomeFunction();
  HAL_GPIO_WritePin(LD4_GPIO_Port, LD4_Pin, GPIO_PIN_SET);
  while(1)
      ;
}

其余的都是一样的。

用这个编译器编译它: arm-none-eabi-gcc (GNU Tools for Arm Embedded Processors 7-2017-q4-major) 7.2.1 20170904 (release) [ARM/embedded-7-branch revision 255204]和这些选项:-mcpu=cortex-m3 -mthumb -O3 -fmessage-length=0 -ffunction-sections -fdata-sections -flto -Wall -Wextra -g3 -std=gnu11

它按预期工作。按下按钮触发 EXTI 中断,设置结构中的标志,循环停止,LD4 亮起。


推荐阅读