使用Arduino 沒有真正的類比輸出(analog output),只有用 PWM 技術模擬出的類比輸出。
所謂 PWM 就是脈衝寬度調變(Pulse Width Modulation),也就是不斷的快速開與關以便模擬出0伏特到5伏特之間的電壓,
所以共匪翻譯為模擬輸出,我們則稱類比輸出。
Arduino Uno 板子只有六支數位腳(3, 5, 6, 9, 10, 11)可使用 analogWrite(pin, val);做類比輸出,因3個計時器只能幫六支腳做PWM輸出。
參數val 可用0到255,若比255大則會自動做除以256取餘數,
注意對該六支腳以外的其他腳使用analogWrite() 則會被自動改為digitalWrite() 輸出0 或 1
(輸出的val大於或等於128就改為HIGH 也就是1否則是0)!
有些程式庫會影響 PWM 類比輸出的使用,例如 Servo.h 的程式庫與發聲的 tone( )函數。
使用 Servo.h 程式庫最多可以控制 12 個伺服馬達(Servo Motor),且可以使用任何數位腳與類比腳A0到A5共20支腳。
這是因為Servo.h 庫並不是直接使用該三個 timer 的 PWM 功能,不過它用掉了 timer1 計時器。
請注意,一旦用了 Servo.h 的程式庫控制伺服馬達, 則pin 9 與 pin 10 就不可再用類比輸出analogWrite( ),
這是因為 Servo.h 程式庫用掉了計時器1 (timer1), 可是對 pin 9 與 pin 10 做 analogWrite( )需要該timer1計時器的幫忙!!
如果你使用程式庫的 tone( ) 發聲音,則 pin 11與 pin 3 也不能當作類比輸出(會變不準確),
因為 tone( )用了 timer2 計時器,該計時器是幫助 pin 11 與 pin 3 做 PWM 模擬的,這時對 pin 11 與 pin 3 做analogWrite( )輸出值會受 tone( )發出聲音頻率影響!
所以如果你用了 Servo.h 伺服馬達的程式庫,又用了 tone( ) 發聲音(蜂鳴器可接任何腳),則你就只剩下被 timer0 計時器幫忙的 pin 5與pin 6 可以當 PWM 腳做類比輸出了。
再摘要一下,pin 5 與 pin 6 的 PWM 是靠 timer0 幫忙,
pin 9 與 pin 10 的 PWM 是靠 timer1 幫忙,
pin 11 與 pin 3 則是連接到 timer2計時器(別懷疑,我沒寫錯!)。
叫用 int k = analogRead(pin); 做類比輸入(共匪稱模擬輸入)時,會得到 0 到1023間的值。
此時 pin 可為 0到5 或 A0到A5 或 14到19,都是指類比輸入腳 A0 到 A5;
實際上,寫 A0 就等於是寫 14,因為 A0 是一個預先定義的常數(不會變的變數)。
因為Arduino規定analogRead只能用於類比腳A0到A5,所以寫A0或0或14都代表A0,不會誤解。
請注意,類比輸入腳 A0 到 A5 即使不接任何感應器,analogRead( )通常仍會讀到大約一兩百的浮動值。
另外, 因為 analogRead( ) 讀到的值是 0 到 1023,有時我們想轉換為 0 到 255,這時可用內建的 map( ) 函數,例如:
int k = map(val, 0, 1023, 0, 255);
這可以把0到1023的 val 轉為 0到255 的 k 值。
當你數位腳不夠用來輸出,可以把 A0 到 A5 拿來做數位輸出(就是說可以用 digitalWrite( )函數),
當然要先對其用 pinMode(pin, OUTPUT); 把 pin 設為輸出(只能數位輸出),
例如 pinMode(A0, OUTPUT); analogWrite(14, 38); 這樣會對類比腳 A0 輸出 LOW 也就是 0伏特,
因為 A0 就是 14,這時只能用 digitalWrite( )輸出 HIGH 或 LOW,用了 analogWrite( ) 則會被偷換掉喔。
要輸出大於127就被換為數位 HIGH (就是 1),輸出38小於 128 就被換為 LOW (就是 0)。
如果你一定要對 A0 到 A5 做類比輸出(PWM),
那只能自己用軟體偷偷快速不斷的切換 HIGH 與 LOW做軟體式PWM。
這時可以參考前面(P.17)我的範例使用 delayMicroseconds( )幫忙,或者也可以自己使用 timer 搭配 ISR 幫忙以便可同時做其他事。
請注意,delay( ) 與 millis( ) 等相關函數是使用 timer0 幫忙計時,
不過只要你不去改變 timer0 的內部 prescaler,
使用 delay( )與 millis( )等相關函數仍然可以正確對 pin 5 與 pin 6 當作 PWM 腳做 analogWrite( ) 輸出(還記得pin 5 與 pin 6 的 PWM 是靠 timer0 幫忙吧)。
以下我寫的這幾篇可能是你很想看的:
【教程】使用 SimpleTimer(修正Bug)定時做很多事(定時器相關)
如何每隔幾次才做某事(教程)與定時器無關+外部中斷太快?
不使用 Timer 庫要定時做某事或做兩三件事(教程)定時器相關
自己控制 timer1 計時器定時做多件事(教程, 設定timer1 定時器)
自己控制 timer2 計時器定時做多件事(教程, 設定timer2 定時器)
補充設定 timer1 計時器和 timer2 定時器定時做多件事(教程)
如果你想瞭解更多關於計時器(timer)的技術概念與使用技巧, 可以看看以下我寫的這幾篇...
關於delay(), millis(), micros(),delayMicroseconds與定時器(教程)計時
如何偷改 millis( ) 與 micros( )的值方便測試(教程)(定時器相關)
millis() 溢出(overflow)歸零(rollover)有沒問題?(教程)定時器相關
不可能delayMicroseconds(1)要如何delay一個 microsecond?(教程)定?器
【教程】關於中?(Interrupt)的一些五四三... 中斷 . .
如果你對 PWM 想有更多的瞭解,
可以看看我寫的這篇!
可以看看我寫的這篇!
初學者可以點這看我寫的 "Arduino 初體驗" 講義(pdf)
投資自己,讓今天的自己 比 昨天的自己 更值錢 !