簡體   English   中英

帶有霍爾編碼器的 STM32F407 定時器

[英]STM32F407 timers with hall encoders

鑒於我對 STM32 的了解,我有點不確定解決問題的最佳方法是什么。 我想測量帶有每轉 6400 個上升/下降沿的集成霍爾編碼器的電機的速度和位置,分為兩個通道(一個 CH 提供 3200 個上升/下降沿)。

最好的方法是什么?

問題是……我有 4 個電機要測量。 我考慮了很多選擇,但我想要一個只在位置數據已知時才產生中斷的選項(基本上,所以我不會在每個脈沖時增加自己的位置變量,而是讓計時器為我做)。

據我所知,一些計時器支持一種稱為“編碼器模式”的模式。 我不知道有關此模式的詳細信息,但我希望(如果可能)能夠在固定時間(例如大約 20 毫秒)內計算我的速度。 是否有可能在編碼器模式下,使用一個定時器,同時知道上升/下降沿計數(我猜這將在 CNT 寄存器中)並讓它在每 20 毫秒觸發一次中斷,以便我可以划分 CNT 寄存器20ms 以獲得 ISR 內的計數/秒速度?

我的另一個選擇是使用輸入捕獲直接模式進行計數,每個計時器上有兩個通道(每個電機一個),並使用另一個固定周期為 20 毫秒的計時器,並計算那里 4 個電機的所有速度。 但它需要5個計時器......

如果還有其他問題,DMA 是否可以幫助將其保持在 4 個計時器? 例如,我們可以用 DMA 計數嗎?

謝謝!

定時器 1 和 8(高級控制定時器 - 16 位)和定時器 2 至 5(通用定時器 - 16/32 位)支持 STM32F407 上的編碼器接口模式。 定時器 9 到 14(也是通用的)不支持正交編碼輸入。

重要的是,在這種模式下,定時器作為計數器而不是定時器運行。 正交輸入允許根據方向向上/向下計數,以便提供相對位置

請注意,如果您的電機只在一個方向上運行,則您不需要編碼器模式,您可以簡單地從單個通道為計時器計時,盡管這會顯着降低分辨率,因此低速下的精度可能會受到影響。

要確定速度,您需要計算相對位置時間的變化

所有 ARM Cortex-M 設備都有一個 SYSTICK 定時器,它將產生一個周期性中斷。 您可以使用它來計算時間。

那么你有兩種可能:

  • 定期讀取編碼器計數器,從而計數的變化與速度成正比(因為時間的變化將是一個常數),
  • 不定期讀取編碼器並計算位置時間的變化

編碼器接口模式的重載值是可配置的,對於此應用程序(速度而不是位置),您應該將其設置為最大值(0xffff 或 0xffffffff),因為它使算術更簡單,因為您不必處理換行 -周圍(只要它在讀取之間不環繞兩次)。

對於非周期性方法並假設您在 32 位模式下使用計時器 2 到 5,以下偽代碼將生成 RPM 速度,例如:

int speedRPM_Aperiodic( int timer_id )
{
    int rpm = 0 ;

    static struct
    {
        uint32_t count ;
        uint32_t time ;
    } previous[] = {{0,0},{0,0},{0,0},{0,0}} ;

    if( timer_id < sizeof(previous) / sizeof(*previous) )
    {
        uint32_t current_count = getEncoderCount( timer_id ) ;
        int delta_count = previous[timer_id].count - current_count ;
        previous[timer_id].count = current_count ;

        uint32_t current_time = getTick() ;
        int delta_time = previous[timer_id].time - current_time ;
        previous[timer_id].time = current_time ;

        rpm = (TICKS_PER_MINUTE * delta_count) / 
              (delta_time * COUNTS_PER_REVOLUTION) ;
    }

    return rpm ;
}

該函數需要被足夠頻繁地調用,以便計數不會超過一次,並且不能太快以至於計數太小而無法進行准確測量。

這可以適用於delta_time固定且非常准確的周期性方法(例如來自定時器中斷或定時器處理程序):

int speedRPM_Periodic( int timer_id )
{
    int rpm = 0 ;

    uint32_t previous_count[] = {0,0,0,0} ;

    if( timer_id < sizeof(previous_count) / sizeof(*previous_count) )
    {
        uint32_t current_count = getEncoderCount( timer_id ) ;
        int delta_count = previous[timer_id].count - current_count ;
        previous_count[timer_id] = current_count ;

        rpm = (TICKS_PER_MINUTE * delta_count) / 
              (SPEED_UPDATE_TICKS * COUNTS_PER_REVOLUTION) ;
    }

    return rpm ;
}

然后必須准確地在每個SPEED_UPDATE_TICKS調用此函數。

非周期性方法也許是容易實現,是要知道在經過時間的平均速度應用良好。 適用於例如可能更新較慢的人類可讀顯示。

周期性方法更適合於使用反饋回路來控制電機速度的速度控制應用。 如果反饋定時不恆定,您將無法控制。

非周期性函數當然可以定期調用,但在增量時間是確定性的情況下會產生不必要的開銷。

計時器可以依靠一種類型的事件

它可以依靠某些外部信號(如傳感器)或時鍾信號,但不能同時依靠它們。 如果你想每 20 毫秒做一些事情,你需要一些依靠穩定時鍾源的東西。

DMA 當然可以計算它正在執行的傳輸,但是要使其每 20 毫秒執行一次操作,它必須以固定的時間間隔被某些操作觸發。

因此,您需要第五個計時器。

幸運的是,有很多計時器可供選擇

  • 10 個以上的計時器

F407 有 14 個硬件定時器。 您不想使用超過 4 個,我假設其中 10 個在您的應用程序的其他地方使用。 檢查它們的使用情況。 也許有一個依靠合適的時鍾頻率,並且可以產生一個頻率適合您的編碼器采樣的中斷。

  • SysTick 計時器

Cortex-M 內核有一個稱為 SysTick 的內部定時器。 許多應用程序使用它每 1ms 產生一個中斷,用於計時和其他周期性任務。 如果是這種情況,您可以在每 20 個 SysTick 中斷中讀取編碼器值 - 這樣做的優點是不需要額外的中斷進入/退出開銷。 否則,您可以直接將其設置為每 20 毫秒生成一個中斷。 請注意,您在參考手冊中找不到 SysTick,它記錄在 STM32F4 程序員手冊中。

  • 實時時鍾

RTC 具有周期性自動喚醒功能,可以每 20 ms 產生一次中斷。

  • 串口

除非您使用所有 6 個 UART,否則您可以將其中一個設置為非常慢的波特率,例如 1000 波特,並繼續傳輸虛擬數據(您不必為其分配物理引腳)。 以 1000 波特傳輸,8 位,一個起始位和一個停止位,每 10 ms 產生一次中斷。 (除非您的 APB 頻率低於允許的最大值,否則它不會讓您降至 500 波特)

暫無
暫無

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

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