繁体   English   中英

这听起来像是堆栈溢出吗?

[英]Does this sound like a stack overflow?

我想我的嵌入式固件代码中可能存在堆栈溢出问题或类似问题。 我是一个新的程序员,从来没有处理过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

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更改时,您不会开始测试新值。

HandleStallEvent() “查看”ISR中的StallDetector还是在主循环上触发了什么? 如果它在主循环上,你清除中断位吗?

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

再想一想,您更有可能不必清除产生中断的寄存器,而是由传感器保持断言中断引脚。 您需要在第一次处理之后忽略该中断,直到线路无效为止,例如让原始ISR自行禁用,然后在处理1-> 0转换的第二个ISR中重新安装。

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

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

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

你的系统上有嵌套ISR吗? 可能是启动你的ISR并增加你的计数,然后中断它并再次执行的东西。 这样做足够多,中断堆栈可能会溢出。 它也可以解释这么高的计数器变量。

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

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

如果在您的情况下可能出现类似的情况,您可以看到数据的更改位置以及是否有其他人错误地写入内存。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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