c - 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变量。这是它的行为方式:
- 中断运行良好——当我尝试打开中断部分的二极管时——它会打开;当我尝试使用 motor.c 中的 Disable() 函数禁用驱动程序时,它可以工作并设置正确的 GPIO 端口
- 当我尝试在没有功能的情况下在 ISR 中设置 STOP_FLAG 时,使用
m->STOP_FLAG = 1;
它不起作用 - 当我从 exec.c 调用 SetStopFlag() 函数时(例如,在 Rotate() 行之前的 SomeFunction() 中)它可以正常工作
有人知道为什么 hall.c 在访问 struct 字段时遇到问题吗?
解决方案
问题出在其他地方。
您提供的代码无法重现它。
我为带有两个 LED(LD3
onPB7
和LD4
on PB6
)和一个按钮(B1
on 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 亮起。
推荐阅读
- php - 试图在laravel中获取非对象问题的属性
- scala - 为什么我在 Spark 中使用 combineByKey 的字数是值总和的两倍?
- javascript - DataTable 列过滤不提取值
- windows - 如何在启动时停止出现命令提示符?
- jbase - 在jbase中找到死代码的好方法是什么?
- python - 如何在 python 中替换 dict 中的字符
- java - 无法解析 commons-collections:commons-collections:2.1
- https - create-react-app:如何使用 https 但带有签名证书?
- visual-studio-code - VSCode 中用于 IntelliSense 信息的提供程序是什么?
- android - 显示一个菜单元素并隐藏另一个