中文 | English

Arduino 也能顯示 CPU 使用率! —— 讓它的耍廢無所遁形

寫 Arduino 程式時,知道微控制器跑得多辛苦,可能可以在除蟲的時候幫上你很大的忙。

大部分寫 Arudiuno 的人,通常都不知道跑程式的時候 Arduino 上的微控制器的「運算負載」有多重,換句話說、到底它是正在為你拚死拚活的做事情呢、還是其實只是坐在一旁納涼等事做。如果你寫的是在電腦上跑得程式,那你就可以一個 Ctrl+Alt+Del 叫出「工作管理員」,看看現在的 CPU 使用量到底有多高。

那如果我跟你說,其實 Arduino 上一樣有辦法看到它微控制器的負載量呢?

很多人以為這是不可能,畢竟我們 Arduino 上只能跑單一一個程式而已,連作業系統也沒有,哪來的介面看微控制的負載量呢;但這篇文章就是要告訴你,「可以的!你也做得到」。

背景

Arduino 程式都會個有不斷被執行的迴圈、等待著某件事情發生/停止,並準備作出對應動作;大概就像這樣

void setup()
{
    // 初始化 Arduino
}

void loop()
{
    // 檢查外部條件 
    flagSet = flag_get();
    if (!flagSet) 
    {
        // 等待事情發生
        delay(100);
    }
    else
    {
         // 作出反應
    }
}

boolean flag_get()
{
    // 檢查外部條件的詳細程式碼
}

構想

在這個例子裡 flag_get() 會檢查外部條件是否符合,如果是,那就要開始作出反應。所以我們要做的事情很簡單,就是在檢查以及反應時,透過某種方式告訴外界「我忙得很」或「我很閒」;例如下面這樣。

void setup()
{
    // 初始化 Arduino 的程式碼
}

void loop()
{
    // 檢查外部條件 
    flagSet = flag_get();
    if (!flagSet) 
    {
        // 開始送出我很閒的訊息
        
        // 等待事情發生
        delay(100);
        
        // 改成送出我忙得很的訊息
    }
    else
    {
         // 作出反應
    }
}

boolean flag_get()
{
    // 檢查外部條件的詳細程式碼
}

雖然這個程式對「忙碌」與「空閒」的區分不盡理想(畢竟在 作出反應 的時候,程式也可能不是全然忙碌的),但這已經是個不錯的開始。

現在比較大的問題是我們要如何真的送出「我忙得很」或是「我很閒」的訊息呢?最簡單的方式就是改變任一個沒有被使用的 pin 的狀態就好。為此,勢必會要多一些設定 pin 的部分,所以程式碼會變成下面這樣。

// 設定要從哪個 pin 送出忙碌與否的訊息
int busyPin = 12;

void setup()
{
    // 設定要送出訊息的 pin 為輸出模式
    pinMode(busyPin, OUTPUT);
    // 其他初始化 Arduino 的程式碼
}

void loop()
{
    // 檢查外部條件 
    flagSet = flag_get();
    if (!flagSet) 
    {
        // 開始送出我很閒的訊息
        
        // 等待事情發生
        delay(100);
        
        // 改成送出我忙得很的訊息
    }
    else
    {
         // 作出反應
    }
}

boolean flag_get()
{
    // 檢查外部條件的詳細程式碼
}

再來透過 idlebusy 這兩個函式,正式透過改 pin 的狀態,送出「我很閒」或「我忙得很」的訊息。

// 設定要從哪個 pin 送出忙碌與否的訊息
int busyPin = 12;

void setup()
{
    // 設定要送出訊息的 pin 為輸出模式
    pinMode(busyPin, OUTPUT);
    // 其他初始化 Arduino 的程式碼
}

void loop()
{
    // 檢查外部條件 
    flagSet = flag_get();
    if (!flagSet) 
    {
        // 開始送出我很閒的訊息
        idle();
        
        // 等待事情發生
        delay(100);
        
        // 改成送出我忙得很的訊息
        busy();
    }
    else
    {
         // 作出反應
    }
}

boolean flag_get()
{
    // 檢查外部條件的詳細程式碼
}

// 透過這個函式送出「我很閒」的訊息
void idle()
{
    digitalWrite(busyPin, LOW);
}

// 透過這個函式送出「我忙得很」的訊息
void busy()
{
    digitalWrite(busyPin, HIGH);
}

接下來只要把 pin 12 (看你 busyPin 設的是哪個)接到示波器上,你就可以看到微控制器有多繁忙了;但考量到示波器並不是人人都有,我們這邊要用更簡單的方法。

實作

我們可以先從把 pin 12 ,從示波器改成接到 LED 上開始(但是別忘記接電阻,避免通過 LED 的電流過大)。由於微控制器會交替送出「我很閒」(LED亮)和「我忙得很」(LED暗)的訊息,肉眼看起來 LED 應該會是略暗的樣子(如果負載很低的話,看起來可能像是完全暗的一樣)。

但是用 LED 燈的亮度來表現微控制器的繁忙程度有個問題,那就是我們人的眼睛亮度的感覺不是線性的,也就是說當負載從 50% 變成 100% 的時候,我們不會覺得 LED 的亮變成兩倍,只會覺得它微微變亮了一點。

解決這個問題最好的辦法,就是避免靠「感覺」去理解負載,而是用數值化的方式直接呈現。所以這裡我們在一個低通濾波器(其實就是電阻+電容啦) 取電壓的平均值就好(不然電壓變化太快、不易觀測),然後再用三用電錶測量電壓;測出來的電壓越高,代表微處理器負載越高,反之亦然。

不過在量測之前我們可以再多做一件事情,那就是用分壓器先把輸出電壓降至 1V,讓負載更好解讀 (有點像是百分比的概念),下圖為分壓器加上電容的示意圖。(註:圖片的假設是輸出電壓為 3.3V,但通常我們用的 Arduino 的輸出電壓是 5V,所以可以把圖中的 62KΩ 電阻替換成 82KΩ 電阻、 27KΩ 電阻替換成 22KΩ 電阻即可達到一樣的效果)

接著只要在上圖中 Busy Factor 那邊接上你的三用電錶……登登! Arduino 負載顯示器就大功告成啦!

參考資料

分享到社群

SHY

半途出家踏入資工與資安的領域,發現軟體硬體本一家,又玩起 Arduino 與 Raspberry Pi ,基本上什麼都碰一點,夢想是成為一隻駭客犬。