簡體   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