Python可以這樣玩(13):外部LED控制

我們不能每次都使用內部PIN 13LED燈號,因為有時候我們要讓使用者可以在電路板上看到,UNO開發板通常會藏在後面,所以我們就必須使用到下面兩個元件:




由於是外部控制,我們就必須使用外部的電阻,也就是說,必須先認識電阻。我目前拿到的是五條線的電阻,順序是前四條線比較接近,第五條線有一點間隔,先認識這點前後順序就不會錯。

電阻的五色色碼

接下來就是要依照五色色碼來判斷歐姆數,如下圖:


現在我們需要的是 220歐姆的電阻,那就是 紅紅黑黑 X”,最後的顏色是誤差值,下圖是運算結果(先背下黑棕紅三色的代表意義 0, 1, 2)


如果真的背不起來,可以上網試算。

什麼是發光二極體LED

發光二極體簡稱為 LED。由鎵(Ga)與砷(AS)、磷(P)的化合物製成的二極
管,當電子與空穴複合時能輻射出可見光,因而可以用來製成發光二極體,在電路及儀器中作為指示燈,或者組成文字或數字顯示。磷砷化鎵二極體發紅光,磷化鎵二極體發綠光,碳化矽二極體發黃光。

LED工作原理

發光二極體的反向擊穿電壓約 5 伏。它的正向伏安特性曲線很陡,使用時必須串聯限流電阻以控制通過管子的電流。限流電阻 R 可用下式計算:
R=(EVF)/I
式中 E 為電源電壓,VF LED 的正向電壓,I LED 的一般工作電流。發光二極管的工作電壓一般為 1.52.0V,其工作電流一般為 1020mA。所以在 5v 的數位邏輯電路中,可使用 220Ω的電阻作為限流電阻。

發光二極體的兩根引線中較長的一根為正極,應連接電源正極。有的發光二極體的兩根引線一樣長,但管殼上有一凸起的小舌,靠近小舌的引線是正極。

LED燈有兩種連線方法:當 LED燈的陽極通過限流電阻(順序相反亦可,串聯)與板子上的數位 I/O 口相連,另一端接地,數位口輸出高電壓時,LED導通,發光二極體發出亮光;數位口輸出低電壓時,LED截止,發光二極體熄滅。

另一種接法是,當 LED燈的陰極與板子上的數位 I/O 口相連時,另一端接5V,數位口輸出高電壓,LED截止,發光二極體熄滅;數位口輸出低電壓,LED燈導通,發光二極體點亮。

現在我們就讓 PIN 7 設定成輸出MODE 然後透過HIGH and LOW 閃爍。電路板的接法如下:


程式碼可以從此網站下載:https://gist.github.com/lazytomatolab

int led = 7;
void setup() {
  pinMode(led, OUTPUT);
}
void loop() {
  digitalWrite(led, HIGH);
  delay(1000);
  digitalWrite(led, LOW);
  delay(1000);
}

Arduino 教程中我們可以知道,Arduino 語法是以 setup()開頭,loop()作為主體的一個程式極架。setup() 是用來初始化PIN模式,調用庫函數等等,此函數只運行一次。本程式在 setup()中用數位 IO 口輸入輸出模式定義函數 pinModepinmode),將數字的第 7 引腳設置為輸出模式。

loop()函數是一個迴圈函數,函數內的語句周而復始的迴圈執行,本程式在 loop()中先用 數位 IO 口輸出電壓定義函數 digitalWrite(pin, value),將PIN 7 定義為高電壓,點亮 LED燈;接著調用延時函數 delay(ms)(單位 ms)延時 1000ms,讓發光二極體亮 1s;再用數位IO 口輸出電壓定義函數 digitalWrite(pin, value),將數字 7 口定義為低電壓,熄滅 LED燈;接
著再調用延時函數 delay(ms)(單位 ms)延時 1000ms,讓發光二極體熄滅 1s。因為 loop() 函數是一個迴圈函數,所以這個過程會不斷的迴圈。

Pulse Width Modulation

就是通常所說的PWM,譯為脈衝寬度調製,簡稱脈寬調製。脈衝寬度調製(PWM)是一種對類比信號電壓進行數位編碼的方法,由於電腦不能輸出類比電壓,只能輸出0 5V 的的數位電壓值,我們就通過使用高解析度計數器,利用方波的占空比被調製的方法來對一個具體類比信號的電壓進行編碼。

PWM 信號仍然是數字的,因為在給定的任何時刻,滿幅值的直流供電要麼是5V(ON),要麼是0V(OFF)。電壓或電流源是以一種通(ON)或斷(OFF)的重複脈衝序列被加到類比負載上去的。通的時候即是直流供電被加到負載上的時候,斷的時候即是供電被斷開的時候。只要頻寬足夠,任何模擬值都可以使用PWM 進行編碼。輸出的電壓值是通過通和斷的時間進行計算的。

輸出電壓=(接通時間/脈衝時間)*最大電壓值。



Arduino 埠的輸入電壓只有兩個 0V 5V。如我想要 3V 的輸出電壓怎麼辦… ,也許你會說串聯電阻 ? OK,這個方法是正確的。但是如果我想 1V, 3V, 3.5V 等等之間來回變動怎麼辦呢?不可能不停地切換電阻吧。這種情況下… 就需要使用 PWM 了。他是怎麼控制的呢,對於 arduino 的數位埠電壓輸出只有 LOW HIGH 兩個開關,對應的就是0V 5V 的電壓輸出,我們本把 LOW 定義為 0HIGH 定義為 1 一秒內讓 arduino 輸出 500 0 或者 1 的信號。如果這 500 個全部為 1,那就是完整的 5V,如果全部為 0,那就是 0V。如果 010101010101 這樣輸出,剛好一半一半,這樣輸出埠實際的輸出電壓是2.5V。這個類似我們放映電影,我們所看的電影並不是完全連續的,它其實是每秒輸出 25張圖片,在這種情況下人的肉眼是分辨不出來的,看上去就是連續的了。PWM 也是同樣的道理,如果想要不同的電壓,就控制 0 1 的輸出比例就 ok 當然… 這和真實的連續輸出還是有差別的,單位時間內輸出的 0,1 信號越多,控制的就越精確。


在上圖中,綠線之間代表一個週期,其值也是 PWM 頻率的倒數。換句話說,如果 Arduino PWM 的頻率是 500Hz,那麼兩綠線之間的週期就是 2 毫秒。 analogWrite() 命令中可以操控的範圍為 0-255 analogWrite(255)表示 100%占空比(常開), analogWrite(127)占空比大約為 50%(一半的時間)。

analogWrite() :作用是給埠寫入一個模擬值(PWM )。可以用來控制 LED 燈的亮度變化,或者以不同的速度驅動馬達。當執行 analogWrite()命令後,埠會輸出一個穩定的占空比的方波。除非有下一個命令來改變它。PWM 信號的頻率大約為 490Hz

在使用 ATmega168 ATmega328 UNO arduino 控制板上,其工作在 3,5,6,9,10,11埠。 Arduino Mega 2560 控制板,可以工作於 2-13 號埠。在更古老的基於 ATmega8 arduino 控制板上,analogWrite()命令只能工作於 9,10,11 號埠。在使用 analogWrite()命令前,可以不使用 pinMode()命令把埠定義為輸出埠,當然如果定義了更好,這樣利於程式語言規範。

語法:analogWrite(pin, value)

參數:Pin : 寫入的埠,value:占空比: 0-255 之間。

線路請按照下面方式連接:



程式碼如下:

// Andrew 修改成類比

int bright=0;
int fade=5;
int ledPin=9; //设定控制LED的数字IO
void setup()
{
    pinMode(ledPin,OUTPUT);//设定数字IO口的模式,OUTPUT 为输出
}
void loop()
{ 
    analogWrite(ledPin,bright); //bright 一開始是0
bright += fade;

    if (bright==0 || bright==255) {
         fade = -fade;
    }
   
    delay(30); //设定延时时间,1000 = 1
}

看到LED慢慢變亮然後慢慢變暗,你就成功了。講到這裡,本書就要分成兩個分支,一條會開始討論如何使用Python 來控制開發板,由於這整本書的主題是以Python為主,所以接下來我們就會開始。另一條繼續談 Arduino 的進階電路設計,會以傳統的C語言與麵包板的操作為主,如果你對此有興趣,可以直接跳到該處。

使用 Firmata 協定與 pySerial 函式庫

我們每次要更改板子的功能的時候,都必須在 Arduino IDE裡面重寫程式,有另一種方式,就是把標準的 Firmata 上傳至開發板之後,以後就透過 Python 寫程式來與 Firmata 溝通即可,這樣可以加速開發。

上傳 Firmata 草稿碼至開發板

首先打開 [檔案] [範例] [Firmata] [Standard Firmata],就會開啟範例程式,我們就用這個標準程式來做為與 Python 的通訊橋樑,所以不要修改任何東西,直接將其上傳到 UNO

編譯以及上傳成功之後,會在狀態列上面寫是成功,如下圖,這時,您的開發板已經安裝了最新版的 Firmata 韌體,準備好接受電腦所下的指令,讓我們進入下一段,開始測試Firmata 通訊協定吧:



測試 Firmata 通訊協定


請將前一個範例的麵包板接法稍作調整,將正極接到PIN 13上面,其餘不變。接著我們要使用 pySerial 來做一些測試,請在cmd底下安裝 pySerial

$ pip install pySerial


為了測試 pySerial 可以正常運作,我們需要再上傳一個測試草稿到UNO,請選取 [檔案] [範例] [Basic] [DigitalReadSerial] ,上傳完畢之後,我們先用 COM port Monitor 看一下結果:



前面的章節有提醒過,請先關閉 Monitor程式,不然會和 Python衝突,接著進入 Python IDLE,輸入下面命令:

>>> import serial
>>> s = serial.Serial('COM3',9600)
>>> while True:
    print(s.readline())

b'0\r\n'
b'0\r\n'
b'0\r\n'
b'0\r\n'
b'0\r\n'
b'0\r\n'
b'0\r\n'
b'0\r\n'
b'0\r\n'
b'0\r\n'
b'0\r\n'
b'0\r\n'
b'0\r\n'
b'0\r\n'

看到這樣的字串一直輸出,就代表你成功了,請按 Ctrl-C 中斷,接下來我們就可以正式對接。

對接 Python Firmata

要對接之前,我們必須再重新上傳 Standard Firmata UNO板上面,這一步不要忘記了,不然等下會有錯誤,這種錯誤常常會發生,因為上傳到板子上面的程式我們看不見,而且 Arduino IDE 又可以同時開啟好幾個視窗同時編輯,一不小心就會忘了到底上傳了哪個程式。

PS: Arduino UNO 板是一種 Hardware,我的寫的程式是 Software,燒錄到 Hardware 裡面的 Software 我們會稱之為 Firmware

接著,我們必須再安裝一個Python擴展庫 pyFirmata,它是一個以 pySerial 為基礎的擴展庫,請按照下面的指令安裝:

$ pip install pyfirmata

安裝完成之後,我們就可以用 Python 來控制了:

>>> import pyfirmata
>>> pin = 13
>>> port = 'COM3'
>>> board = pyfirmata.Arduino(port)
>>> board.digital[pin].write(1)
>>> board.digital[pin].write(0)
>>> 

有沒有看到LED燈亮起再關閉呢? 恭喜大功告成。用 Python 來做的好處是,我們可以在 Python 的互動環境裡面,直接跟 Arduino UNO互動,讓它開燈關燈,例如我可以在PIN 9 的位置在接一個LED燈,直接下命令:

>>> pin2 = 9
>>> board.digital[pin2].write(1)

還可以把命令存在 PlayLED.py,我們避開原本的 PIN 13,改成PIN 8

import pyfirmata
pin = 8
pin2 = 9
port = 'COM3'
board = pyfirmata.Arduino(port)

board.digital[pin].write(1)
board.digital[pin2].write(1)

兩個燈就同時打開了。我可以讓兩個燈交互閃爍100次嗎?當然可以:

import pyfirmata
import time

pin = 8
pin2 = 9
port = 'COM3'
board = pyfirmata.Arduino(port)

for i in range(100):
    board.digital[pin].write(0)
    board.digital[pin2].write(1)
    time.sleep(1)
    board.digital[pin].write(1)
    board.digital[pin2].write(0)
    time.sleep(1)

有感覺了嗎?當你使用 Arduino IDE 寫程式的時候,除了每次改寫要上傳之外,其執行結果就是一直在 loop() 裡面繞,當你要玩些其他東西的時候,就必須重新編譯然後再重新上傳,很多時間就會浪費在這裡。
Python 的互動式環境或是程式裡面,你可以隨時按照你的需求修改,不需要動到 Firmware,因此彈性很大。

有鑑於此,我後面的分享方式,會使用兩個分支交錯的方式,用 Arduino IDE設計好一個程式之後,在用 Python 來玩些其他的變化。


硬體系統設計

工欲善其事必先利其器,首次接觸麵包板線路的人,總會覺得手忙腳亂,推薦你使用一個名為 Fritzing的工具,可以在下面的網站取得,當然,建議您可以捐錢給這個工具,實在太好用了:
下載完畢之後,安裝過程或許是個問題,因為它不像一般安裝程式那樣 double cliek 就可以安裝,必須自行解壓縮,放到一個新的目錄裡面,然後直接執行裡面的 Fritzing.exe 即可。

執行之後如下圖,就可以開始把右邊的元件拖曳到左邊的麵包板上面,操作上非常直觀,自己測是一下便知。



很好,上一個Python LED閃爍的例子的安裝圖就是這樣。除此之外,還可以自動產生概要圖,讓使用者更清楚線路是否正確,例如,在這裡我有兩條線接到 GND,在概要圖裡面就可以看出其實只要接到一個GND即可。

建議你可以在實際接麵包板線路之前,使用 Fritzing 繪圖,這樣發生錯誤的機會比較低。接下來,我們就會開始用交錯的方式,把 Arduino 分支與 Python 分支交叉說明,保證可以快速入門。

留言

  1. 我可以當您的紛絲嗎? 謝謝您貼文. 我也在玩python. 做計算.

    回覆刪除

張貼留言

這個網誌中的熱門文章

Python可以這樣玩(16):共陰/共陽七段顯示器

Python可以這樣玩(11):數學繪圖

Python可以這樣玩(15):蜂鳴器與音樂