用Arduino做一個精密的百元頻率測量儀

以前學習 555 振盪器電路時,最困擾的事情,莫過於電路接好之後,沒有儀器可以驗證輸出的頻率,只能將輸出接上放大電路,湊合一顆馬達來看看轉速變化,就算學會方波產生電路了,到底出來的頻率對不對,只有老天知道了。總不會要我為了業餘興趣,買一台示波器吧?

現在,隨手可得的 Arduino 跟一片便宜的 1602 I2C LCD 液晶螢幕,幾行短短的程式,就能弄出一台精密的頻率測試儀(雖然看起來挺簡陋的)。除了測 IC 的輸出信號之外,也可以湊一些簡單的感測電路,像光遮斷器、雷射、紅外線感測器,來測馬達轉速風扇轉速風速振動頻率,只要把 Sensor 出來的類比信號,接入史密特觸發電路 (Schmitt trigger),變成比較乾淨整齊的 5V方波,再接進來做好的 Arduino 頻率測量儀,馬上就知道頻率了,有的感測器模組,本身就有觸發電路。若懶得搞這複雜,而且不是要測量很精密的頻率,只要感測器電壓不要大到會燒壞Arduino DI 腳位,或者太低感測不到,跳過上述觸發電路,直接接進來看看信號大概的頻率,也未嘗不可。

頻率測量儀原理

Arduino 的心臟 ATmega328P 中,有三顆 Timer/Counter。這個頻率測量儀的原理,是用其中一顆 Timer/Counter,執行 Timer 功能,產生一個固定時間間隔的中斷信號,比方說 1秒鐘。然後利用這個準確的時間間隔,控制另外一顆 Timer/Counter,去執行 Counter 計數任務。在這一秒鐘期間,Timer去控制Counter的啟動(Timer開始時)、停止計數(Timer時間到,並發出中斷信號時),然後讀出Counter的計數震盪的數目,將這個值,除以 Timer 這個我們預設的時間間隔 (上面舉例1秒鐘),就得到頻率了。ATmega328P 的 16MHz 的核心頻率,讓你可以測出MHz級的頻率。這個方法最佳的頻率測量範圍是 1KHz 到 8MHz,實際高頻的效果,會跟你的線路安排有關係。我想,一般創客碰這類MHz級的高頻應用的機會應該不多,測測 KHz 級的頻率,對大部分非射頻的控制信號來說,我想算是綽綽有餘了。

Arduino 配線

從上面照片,你就知道沒有什麼好配的。基本的 Arduino 供電兩條線,I2C 螢幕信號加螢幕供電四條線,然後從 Arduino Nano D5 接一條線出來(照片下方白色線),給待測信號輸入計數,配線就結束了。

Arduino 程式

要做出這個頻率測量儀,需要安裝 FreqCount 函式庫來用,你就可以跳過大費周章去設定 ATmega328P 複雜的Timer/Counter暫存器。用這個函數庫,Call兩個函數就完成了。之前做完 GRBL CNC with 28BYJ-48 and SG90 低價步進馬達伺服機控制的程式之後,我再也不想去碰這部份了,到現在對於控制暫存器的那幾個 bit 的排列組合設定,還是懵懵懂懂,要自己去整個讀懂,得花太多時間。真是佩服最早設計這種 Timer/Counter 的工程師前輩們啊,竟然可以逐漸想出這麼複雜的模式選項,讓 Timer/Counter 可以湊出超多功能、應用到最廣的應用領域。
另外也非常感謝這個函式庫的作者 Paul Stoffregen,提供這個方便的函式庫讓大家免費使用。在這個網頁中,可以看到頻率測出來的結果,跟儀器幾乎一樣呢。而且 Arduino Nano 的成本,含運只要百來塊就有了~。
安裝好上述的函式庫之後,用 Arduino IDE 寫一個像下面這樣的程式,百元頻率測量儀就完成了。待測量的頻率信號,從 T1 (Timer 1) 接進去,也就是 Arduino Uno 或 Arduino Nano 的 D5,這個腳位,有幾個信號共用腳位。其他種類的 Arduino,請自行了解其 T1信號腳位。

#include <FreqCount.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 16, 2); // 1602 LCD 是 16x2 的畫面,如果你是別種螢幕,可自行改這行。

void setup() {
  lcd.noBacklight(); //先將背光設定成不亮
  lcd.init(); //初始化LCD
  lcd.backlight(); //開啟背光
  lcd.setCursor(0, 0);
  lcd.print("FREQUENCY:");
  FreqCount.begin(1000);//這個就是時間間隔,單位是 milliseconds,設成1000,得到計數結果,就是Hz了。
}

void loop() {
  char outstr[16];//輸出字串變數
  if (FreqCount.available()) {
    unsigned long count = FreqCount.read();//讀出計數器的計數值
    lcd.setCursor(0, 1);
    sprintf(outstr,"%13d Hz", count);//把頻率輸出印出成靠右對齊
    lcd.print(outstr);
  }
}

2 則留言:

  1. 請問一下可以測量的頻率範圍是多少?

    回覆刪除
  2. 用這個方法,最佳的測量範圍是 1kHz 到 8MHz

    回覆刪除