嵌入式軟件實現中經常出現的一個有趣問題是弄清楚如何延遲代碼執行。有時,嵌入式開發人員可能只希望有 10 微秒的延遲,以允許 I/O 線在讀取之前穩定下來,或者可能希望在讀取之間有一個指定的時間段來消除它的抖動。在這篇文章中,我們將探討五種延遲代碼執行的技術。
技術 #1 – 條件循環
第一種可能是最常用和最簡單的技術是使用條件循環。條件循環延遲通常會使用 for、while 或 do while 循環來重復執行無操作 (NOP) 指令。例如:
有條件的延遲在緊要關頭可能很有用,但它幾乎不準確或有效。如果開發人員要針對不同的操作模式(例如低功耗操作)調整時鐘頻率,則延遲時間將完全不同。另外,總是有一個問題,那就是延遲到底有多少?有人可能認為它有 100,000 條指令,但每次循環都會有額外的指令來檢查循環變量并增加 i。這些時序循環太難以預測,無法在任何生產代碼中使用。
技巧 #2 – 使用計時器
可以使用的第二種技術是利用內置在微控制器中的硬件定時器。通常有幾種不同的硬件定時器可用于跟蹤系統時間、生成波形、捕獲輸入和通用目的。如果嵌入式開發人員需要延遲,例如 10 微秒,硬件計時器可以加載表示 10 微秒的計數值。在這種情況下,定時器將被設置為一次性定時器。代碼將啟動計時器并等待設置計時器溢出標志,這將指示時間已過。
此代碼的抽象版本可能如下所示:
這種技術比我們之前看到的條件循環要強大得多。它也更便攜,可以更容易地調整到所需的延遲時間。事實上,API 可以在整個代碼中重復使用,以允許將單個計時器用于所需的任意數量的延遲。
技術 #3 – 使用系統記號(HAL 示例)
可能存在專用硬件計時器不可用或不希望設置一次性計時器的情況。在這些情況下,開發人員可以利用板載系統滴答聲來產生延遲。即使是裸機系統通常也有一個后臺定時器,它充當系統滴答聲,以便軟件從微控制器啟動的那一刻起就有一個時間參考。通常,這些系統滴答聲在典型系統中設置為每 1 或 10 毫秒發生一次。
系統通常使用一些 API 允許開發人員訪問當前系統時鐘,例如 SysTick_Get()。開發人員可以利用它來創建類似于以下內容的延遲:
開發人員只需要確保如果他們做這樣的事情,他們不會遇到計算問題或其他潛在問題,因此應該檢查邊界條件。
技巧 #4 – 使用 RTOS 屈服函數
在使用實時操作系統 (RTOS) 的更高級系統中,嵌入式開發人員可以利用內置的 RTOS API 調用來生成任務以產生延遲。例如,如果開發人員正在使用 FreeRTOS,他們可以在他們的任務中使用如下代碼:
此延遲功能將導致任務在一個 RTOS 滴答聲中產生當前任務。根據配置,RTOS 滴答聲可以設置為 1 毫秒或 10 毫秒。使用這樣的延遲機制可能會出現問題,因為該任務將在該時間段內產生 CPU,但不能保證一旦系統滴答期到期,該任務將成為最高優先級的任務!如果任務是準備好運行的最高優先級任務,則該任務只會在延遲后立即運行,因此延遲時間可能會有一些抖動。
技巧 #5 – 使用 RTOS 對象
我們今天要討論的最后一個技術是使用其他 RTOS 對象來延遲時間。如果你仔細查看你最喜歡的 RTOS 中的信號量、互斥體和隊列等對象的 API,你會注意到大多數等待的 API 調用也包含延遲時間。此延遲時間也可用于導致應用程序延遲。
與 RTOS 對象相關的是大多數 RTOS 還包括軟定時器。這些是基于軟件的定時器,由正在運行的硬件定時器觸發。然后可以將與技術#2 和技術#3 中所示的技術類似的技術與這些軟計時器一起使用,以在代碼執行中產生延遲。
結語
有幾種不同的技術可供想要延遲代碼執行的開發人員使用,所使用的技術將取決于系統中可用的軟件和硬件資源。然后,嵌入式開發人員可以決定他們想要使用的解決方案有多復雜。不過,歸根結底,肯定有幾種機制可以幫助將代碼執行延遲定義的時間段。