3

我想我的嵌入式固件代码中可能存在堆栈溢出问题或类似问题。我是一名新程序员,从未处理过 SO,所以我不确定这是否正在发生。

固件控制一个设备,该设备的轮子周围均匀分布着磁铁,电路板上有一个霍尔效应传感器,可以感应磁铁何时在上面。我的固件在监控磁传感器的同时操作步进器并计算步数,以检测车轮是否失速。

我在我的芯片上使用定时器中断(8 位,8057 acrh。)来设置输出端口来控制电机和失速检测。失速检测代码如下所示...

    //   Enter ISR
    //   Change the ports to the appropriate value for the next step
    //    ...

    StallDetector++;      // Increment the stall detector

    if(PosSensor != LastPosMagState)
    {
        StallDetector = 0;

        LastPosMagState = PosSensor;
    }
    else
    {
        if (PosSensor == ON) 
        {
            if (StallDetector > (MagnetSize + 10))
            {
                HandleStallEvent();
            }
        }
        else if (PosSensor == OFF) 
        {
            if (StallDetector > (GapSize + 10))
            {
                HandleStallEvent();
            }
        }
    }

每次触发 ISR 时都会调用此代码。PosSensor 是磁传感器。MagnetSize 是通过磁场所需的步进数。GapSize 是两个磁铁之间的步数。所以我想检测车轮是否被传感器卡在磁铁上或没有卡在磁铁上。

这在很长一段时间内都很好用,但过了一会儿,第一个失速事件会发生,因为“StallDetector > (MagnetSize + 10)”但是当我查看 StallDetector 的值时,它总是在 220 左右!这没有意义,因为 MagnetSize 总是在 35 左右。所以停止事件应该在 46 时触发,但不知何故它一直到 220?而且我没有在我的代码中的其他任何地方设置失速检测器的值。

你对我如何追查这个问题的根源有什么建议吗?

ISR 看起来像这样

void Timer3_ISR(void) interrupt 14
{
    OperateStepper();  // This is the function shown above
    TMR3CN &= ~0x80;   // Clear Timer3 interrupt flag        
}

HandleStallEvent只是将一些变量设置回它们的默认值,以便它可以尝试另一个动作......

#pragma save
#pragma nooverlay
void HandleStallEvent()
{
///*
    PulseMotor = 0;                 //Stop the wheel from moving
    SetMotorPower(0);               //Set motor power low
    MotorSpeed = LOW_SPEED;
    SetSpeedHz();
    ERROR_STATE = 2;
    DEVICE_IS_HOMED = FALSE;
    DEVICE_IS_HOMING = FALSE;
    DEVICE_IS_MOVING = FALSE;
    HOMING_STATE = 0;
    MOVING_STATE = 0;
    CURRENT_POSITION = 0;
    StallDetector = 0;
    return;
//*/
}
#pragma restore
4

6 回答 6

2

PosSensor 易挥发吗?也就是说,您是在某处更新 PosSensor,还是直接读取 GPIO?

我认为 GapSize 相当大(> 220?)在我看来,您可能有竞争条件。

// PosSensor == OFF, LastPosMagState == OFF
    if(PosSensor != LastPosMagState)
    {
        StallDetector = 0;

        LastPosMagState = PosSensor;
    }
    else
    {
// Race Condition: PosSensor turns ON here
// while LastPosMagState still == OFF
        if (PosSensor == ON) 
        {
            if (StallDetector > (MagnetSize + 10))
            {
                HandleStallEvent();
            }
        }
        else if (PosSensor == OFF) 
        {
            if (StallDetector > (GapSize + 10))
            {
                HandleStallEvent();
            }
        }
    }

在执行 StallDetector++ 之后,您应该缓存一次 PosSensor 的值,以便在代码期间 PosSensor 发生更改的情况下,您不会开始测试新值。

于 2010-04-16T17:59:13.523 回答
1

检查您的参数类型。如果您以与调用者期望的方式不同的方式定义参数,那么调用您的方法可能会覆盖存储变量的空间。(例如,如果您编写的函数需要一个 int 但它会将一个 long 推入堆栈。)

于 2010-04-16T17:47:14.617 回答
1

HandleStallEvent()是在 ISR 中“查看”StallDetector还是触发了主循环中的某些内容?如果它在主循环中,您是否清除了中断位?

StallDetector或者您是从 ISR 外部的调试器中查看的?然后重新触发的中断每次都会使用正确的值,但执行次数过多,您只会看到最终的膨胀值。

再想一想,您更有可能不必清除中断生成寄存器,而是中断引脚仍然由传感器断言。您需要在第一次处理中断后忽略该中断,直到该行置低,例如通过让原始 ISR 自行禁用并将其重新安装到处理 1->0 转换的第二个 ISR 中。

然后,您可能还需要添加去抖动硬件或调整它(如果有的话)。

于 2010-04-16T17:16:54.433 回答
1

您可以看到您的调试器支持哪些附加选项。例如,在 Visual Studio 中,可以设置“数据断点”,当内存位置更改(或设置为某个值,或高于阈值,......)时,您会在该断点处中断。

如果在您的情况下可能发生这样的事情,您可以看到数据更改的位置以及是否有其他人错误地写入内存。

于 2010-04-16T17:52:38.360 回答
1

这绝对不是堆栈溢出。如果你破坏了堆栈(溢出它),你的应用程序就会崩溃。这听起来更像是我们在我的 C++ 时代曾经称之为内存踩踏的东西。您可能无法单独通过 StallDetector 变量访问 StallDetector 值占用的内存位置。您的代码的另一部分可能错误地“踩踏”了这个特定的内存位置。

不幸的是,这类问题很难追查。您唯一能做的就是系统地隔离(从执行中删除)代码块,直到您缩小范围并找到错误。

于 2010-04-16T17:23:27.093 回答
1

您的系统上是否有嵌套 ISR?可能类似于启动 ISR 并增加计数,然后中断它并再次执行。这样做足够多次,您的中断堆栈可能会溢出。它也可以解释如此高的反变量。

于 2010-04-16T17:23:30.537 回答