簡體   English   中英

使用ARM Cortex SysTick計算經過的時間; 當SysTick計數器翻身時會發生什么?

[英]Using ARM Cortex SysTick for calculating elapsed time; what happens when SysTick counter rolls over?

我目前正在審核有關嵌入式系統的在線edX課程,並學習如何使用SysTick計時器計算經過的時間。

我所指的邏輯圖片

我所指的邏輯代碼

但是,有一點令我感到困惑。 我理解從“最后”減去“現在”以獲得經過時間的想法。 但是,當SysTick定時器到達0並重新加載時,當“now”翻轉時你會怎么做,但是“last”是來自SysTick定時器翻轉之前的值(所以“現在”>>“last”,通常它應該更小)? 該值存儲在unsigned long中,它是否會破壞程序? 或者這種情況從未發生過,如果是這樣,為什么呢? 我很感激有任何幫助清理它!

我查看了我能找到的唯一一個與我的問題類似的鏈接: 如何處理嵌入式C中的包裝計數器,但我沒有從中找到一個明確的答案。

拿一個3位計數器,它都可以擴展到24或32(我認為systick定時器是24。

因此,向上或向下計數無關緊要,您只需要正確調整操作數即可。 所以說倒計時7,6,5,4 7 - 4是3計數。 但是二進制1 - 6 = 001 - 110中的1,0,7,6怎么樣?

     1
   001
+  001
=======

並解決它

   011
   001
+  001
=======
   011     

並剪切為3位,這是正確的答案。

編寫一個4位或5位計數器的程序應該很簡單,嘗試隨機大小的計數。 或者使用固定大小的計數,允許使用素數進行翻轉

#include <stdio.h>
#define BITMASK 0xF
int main ( void )
{
    unsigned int now;
    unsigned int beg;
    unsigned int end;
    unsigned int ra;
    unsigned int rb;
    now=0;
    for(ra=0;ra<100000;ra++)
    {
        beg=now;
        for(rb=0;rb<13;rb++) now--;
        end=now;
        if(((beg-now)&BITMASK)!=13)
        {
            printf("Error 0x%X 0x%X\n",beg,end);
        }
    }
    printf("Done.\n");
    return(1);
}

只有當它是一個從全零到全部或全部為零的計數器取決於方向時,它才有效。 我希望很明顯,如果你設置一個假設的3位定時器從5開始,它從零回到5設定點然后三步可能是1,0,5,4和1-4不是3

    111
    001
+   011
=========
    101

考慮到這一點的另一種方式是兩個補充的另一個特征,靠近環繞點

101  -3
110  -2
111  -1
000  +0
001  +1
010  +2

它就像我們在小學時使用的數字線。 從位模式110到010在數字線上是4步+2-2 = 4或4個單位。 基本上使用二進制補碼的美,我們知道二進制補碼中的加法和減法不是無符號或有符號特定的相同位模式導致相同的位模式。 這就是我們如何解釋它們。 所以我們作弊一點,采用有符號的數學並將結果解釋為無符號。

old_timer有一個很棒的答案,在對我自己做了一些更多的研究之后,我在Stack Overflow上發現了另一個很好的答案,我想我也會鏈接: 如何用環繞或溢出減去兩個無符號整數

有一個簡單的解決方案來計算兩個整數之間的差異,這兩個整數與任何標准整數類型的大小不同。 您只需移動整數以使其MSB處於標准類型的MSB位置,執行算術,然后可選地將結果移回原位,使其與原始值的單位相同。

在這種情況下,systick是一個24位計數器,所以:

uint32_t start_time = getSystick() ;

// do something

uint32_t end_time = getSystick() ;

uint32_t elapsed_time_in_systicks = ((start_time << 8) - (end_time << 8)) >> 8 ;

注意操作數的順序 - systick 向下計數。 這假設您將最大重新加載值設置為0xffffff ,並且該systick不會包裝多次。

如果時間間隔使得計數器可以包裝多次,那么您可能不需要這么高的分辨率,並且可能使用較低的重載值和使計數器遞增的中斷處理程序,並使用該較低分辨率計數器進行時間測量。

或者,您可以使用uint8_t計數器在重載中斷時遞增。 然后該計數器可以與24位的systick組合以創建一個真正的32位計數器。 但是為了確保一致性,必須要小心 - 這樣你就不會在它剛剛重新加載重載計數器之前組合一個systick(反之亦然)。 這可以通過以下方式完成:

uint32_t getSystick32()
{
    uint8_t msb ;
    uint32_t systick ;
    do
    {
       msb = getSystickReloadCounter() ;
       systick = getSystick() ;

    } while( msb != systick_reload_counter ) ;

    return msb << 24 | systick ;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM