Categories: Arduino

Arduino 之軟體 PWM

前一陣子忙完一個比賽,忙到連文章一直都沒有去動手完成,仍然只是兩篇的草稿。所以想一窺 Widows 8 其他功能的讀者可能還得要等等了…

先讓我用最近開始接觸的 Arduino 來補補這中間的空白吧!

Arduino 是什麼?

Arduino 是一個開放的硬體單板微控制器(Single-board microcontroller),開發語言則是採用類似 Java 或 C 的程式語言並配合官方提供的 IDE 可以快速的開發與設計,並且因為 IDE 是使用 Java 所撰寫而成的,因此也具有跨平台的特色,可支援 Windows、Linux、Mac OS 等作業系統。

關於 Arduino 的詳細介紹暫時不再這篇文章做更深入的解說,這部分如果你有興趣想先了解的話還可以到維基百科上看看~

PWM?

PWM 是 Pulse-width Modulation 的縮寫,即脈波寬度調整或稱頻寬調整,常用於電子式的電壓調整,例如燈光亮度、馬達控制、螢幕亮度…等等。 其原理是藉由調整脈波的工作週期(Duty cycle)並影響平均值(Average)來達到電壓的控制…我知道這聽起來很複雜,讓我用幾張圖來解釋給你看看吧!

這是一張工作週期(Duty Cycle)約25%的波形示意圖,波形是什麼? 這一點也不重要,重要的是那條橘紅線以及上面表示最高電壓的 VCC

那條紅橘線代表的意義是平均電壓,也就是說以這樣的脈波輸出的話,你會得到一個約 1/4 Vcc 的輸出電壓,喔,看起來很學術嗎? 沒關係,我們來假設一下。

假設 VCC 等於 4 伏特,所以這邊的平均電壓就是 1 伏特啦!然後接下來這張圖則是工作週期 50% 的波形,一樣,請注意那條橘紅線,是不是變高了呢?

最後這一張則是接近 100% 的示意圖,很明顯,就是以最高電壓輸出,而為什麼會有那些線條呢? 因為在實際情形下,晶片的輸出上還是會有些微的延遲,而這些線條是那些延遲所造成的,所以我說這是”接近”而不是真正的 100% 。

另外,這裡有一個外國拍的影片,注意他示波器上的那些波形,是不是很像我上面那些圖的連續動作版呢?

哈!對,當這些事情連貫起來之後就會出現這樣的情形,而這些變化造成的結果就是電壓會緩緩地上升或緩緩地下降,這也是為什麼那些 LED 燈可以漸亮漸滅的原因。

影片說英文不太懂嗎? 還是看不懂事波器上的線條在幹嘛?沒問題,稍後我將利用 Arduino 來實驗,讓你更清楚知道 PWM是什麼東東。

那麼,PWM的相關知識就介紹到這裡,接下來開始實驗。

實驗前

首先呢,你得需要有一個 Arduino 的板子,當然也可以沒有,但至少要有一個類似 8051 這樣的單晶片以及相關的硬體,做這個實驗你可能會需要這些:

  • 一塊麵包版,如果你沒有開發版的話
  • 一顆單晶片控制器,理由同上
  • 電腦,你現在在用的這台就可以,平板除外
  • 人 當然,光有硬體還不夠,你還會用到…

  • 燒錄軟體,依各種晶片準備,Arduino 可用官方提供

  • 燒錄器,也是依各種晶片準備,不過現在都 ICP (或 ISP )了

  • 編譯軟體、編譯器..等等

實驗開始

我先以 Arduino 的程式為主,其餘晶片的程式只要稍作修改也可以達到同樣的功能。雖然說這板子上的單晶片本身就有提供硬體 PWM 不過我還是想寫出一個軟體的,最主要原因是方便其他沒有 PWM 像號的接腳也能有 PWM的功能。

喔!等等!在放入程式之前,麻煩將一顆 LED 的正端接到第 13 腳,負端接到 GND ,Arduino UNO 可以不接,直接透過板子上原有的狀態顯示 LED 就可以觀察了。

麵包板接線示意圖

電路圖

圖片來自:Arduino

完成之後請繼續向下看… 好了,請將下面的程式碼複製到你的 Arduino 編譯視窗。

/*
  Code Name : Software PWM
  Author : Duye
  Modify Date : 2011/09/27
*/
int brightness = 0, baseTime = 1200;
boolean LED_on = false, count_up = false, delay_count_add = false;
void delay_count_fun(boolean);

void setup() {
  // 定義第13腳為輸出
  pinMode(13, OUTPUT);
}

void loop() {
   /*
    * 當 brightness 等於 0 或是等於基礎時間時就將程式裡的設定反過來,
    * 也就是說,程式會自行判斷何時上升何時下降,自動的調整頻寬與工作週期。
    */   if(brightness == 0 || brightness == baseTime){
     LED_on = !LED_on;                    // 開啟(true)或關閉(false)LED
     count_up = !count_up;                // 往上(true)計數或往下(false)
     delay_count_add = !delay_count_add;  // 延遲時間往上(true)增加還是往下(false)
   }
   /* -------- 輸出顯示部分開始 -------- */   digitalWrite(13, !LED_on);
   delay_count_fun(delay_count_add);
   digitalWrite(13, LED_on);
   delay_count_fun(!delay_count_add);
   /* -------- 輸出顯示部分結束 -------- */   // 計數判斷
   if(count_up)  brightness++;
   else  brightness--;
}

// 延遲時間判斷副程式
void delay_count_fun(boolean if_delay_up){
 if(if_delay_up)
    // +1 是為了排除 delay 時間為 0 時的Bug(停頓)
    delayMicroseconds(baseTime - brightness + 1);
  else
    delayMicroseconds(brightness + 1);
}

然後點下 upload 等待程式寫入 Arduino 上的IC後你就會看到那個 LED 漸漸變亮然後漸漸地變暗…

是,這就是 PWM 的其中一種應用,現在我們來看看他輸出的電壓變化如何,這時我們需要一台指針式或數位式的三用電表

將三用電表轉到 DC10V 的檔位,然後將代表正極的紅色探棒放到 LED 的正極,也就是 Arduino UNO 板子上的第 13 腳,黑色碳棒則接到負極(GND)。

你看見了嗎? 指針(數字)是不是正在跳動? 是不是跟著 LED 的明暗緩緩的上升與下降呢? 哈哈!對!這就是所謂的平均值,也是三用電表DCV檔位的特色。

「喔? 所以 DCV 是用來測平均值的?」

是的,在三用電表中,DCV所顯示的數值是這電壓源的平均值,所以當你將三用電表轉到 DC 250 V (注意!一定要轉到比 100 伏特還高的檔位,否則會有危險)後插入牆上的插座,理論上那個指針是不會動的,這是因為交流電的正負半週正好互相抵銷的緣故…

我知道你可能會想問那為什麼會有電,這時候請你將將碳棒從插座上拔出,然後將電表轉到 AC 250V 的檔位,然後再插進插座,是不是動了呢? 恩,這是另外一種計算方式,叫做均方根植,這,我們以後再說說,怎麼會離題離到這裡來呢?

回到 PWM 的現場,現在你的 LED 應該還是處於漸明漸暗並且不斷重複的,現在我要請你改一些小地方。請找到 baseTime = 1200; 將 1200 改成 500 ,觀察看看有什麼變化? 當然你也可以改成 2000、20000 不過我相信你會不耐煩的…

那麼,今天就講到這裡,日後我會繼續將一些我所知道或我最近在摸索的知識慢慢的寫成文章放上來,希望這些能帶給大家幫助,同時也能帶給我更多的意見與建議  =D

參考資料:

duye.chen

View Comments

  • 您好,想請問您在程式的部分,似乎沒有看到對電壓的控制,為什麼能做到與控制電壓,達到讓LED從暗轉明的效果呢? EX: analogWrite(3,255 )

    • 這篇利用 delayMicroseconds 來控制 LED 亮與滅的時間間距,如此就能達到類似於硬體 PWM 的控制方式,差別只在於,一個是用硬體也就是你提到的 analogWrite ,一個是用軟體的方式模擬出來,而這兩者效果基本上是相同的。

Recent Posts

[教學] 打造你的 NFT 智能合約 – ERC721A

GM!前些日子在幣圈亂玩,一路...

2 年 ago

JavaScript – Singleton 設計模式

前言 在設計程式時,我們有時會...

4 年 ago

PlaidML 讓你的 Mac 也能加速 Tensorflow 機器學習!

相信很多使用 Mac 或者手上...

4 年 ago

RESTful API 測試很煩,只好動手寫屬於自己的測試了

寫在最前面 嗨,大家好久不見!...

4 年 ago

Node.js 與 Socket.io – 即時聊天室實作:資料庫

經過前兩篇(一、二)文章,我們...

7 年 ago