You are currently viewing Arduino範例講解(四)

Arduino範例講解(四)

以Switch(Button)作為輸入端

我們也可以將Arduino的I / O引腳用作輸入。在本節中,我們會以按鈕用作輸入設備,當然也可以使用任何開關。

上拉和下拉

Arduino可以使用邏輯輸入:1 = 5v,0 = 0v。為了使按鈕輸出這些電壓,我們將使用上拉或下拉電阻。(圖1和2)
對於下拉電阻(圖1),我們將開關的一個分支連接到5v,另一分支通過一個電阻(在這種情況下為10kΩ)連接到地(0v)。連接電阻的支腳連接到Arduino的輸入引腳。

這樣,當未按下按鈕(且未連接2條支腳)時,輸入為0v,因為它通過電阻接地。按下按鈕時,輸入為5v,因為它通過開關直接連接到5v。按下按鈕時的電阻無關緊要,僅當不按下按鈕時確保輸入為0v。

上拉電阻(圖2)的工作原理完全相同,但是所有部分都被交換了:第一條腳通過電阻接地而不是5v,第二條腳通過電阻連接到5v(因此名稱為上拉電阻,因為它將其拉至5v)。輸入引腳仍與電阻側相連,但是現在,當不按下按鈕時該引腳為高電位,而當該開關閉合時該引腳變為低電位。

按鈕邏輯狀態上拉邏輯狀態下拉
放開10
按下01

現在,將帶有下拉電阻的按鈕連接到Arduino的引腳3,並將帶有上拉電阻的按鈕連接到引腳5。然後將兩個LED(及其相應的電阻)連接到引腳10和12。圖片3)

現在看範例button2。該程序僅讀取兩個輸入,並將輸出設置為讀取的兩個輪入端口。

只有兩行程式碼是新的,很明顯可以看出來:我們使用INPUT而不是OUTPUT常數將按鈕的引腳設置為輸入,而digitalRead(pin)函數僅返回給定輸入引腳的狀態。

digitalWrite(10,digitalRead(3));//這裏把OUTPUT改成由digitalRead(3)輸入引數狀態

注意:實際上不需要使用pinMode(pin,INPUT),因為Arduino上的所有引腳預設都是輸入,但是為了使代碼更具可讀性,通常還是這樣做。

上傳本程式碼後,按一下按鈕,您會看到狀態跟上面表反應相同:引腳12上的LED一直亮著,直到您按引腳5上的按鈕,這是因為它具有上拉電阻。

如果希望僅在按下按鈕時LED才點亮,則可以使用Boolean型非運算式判斷:這只是將“ true”更改為“ false”(或將1更改為0),反之亦然。在C ++(在Arduino IDE中)中,此運算符是感嘆號(!)。

digitalWrite(12,!digitalRead(5));

內部上拉電阻

每次我們要使用普通開關時,如果必須使用額外的電阻和額外的電線,那將會非常不便的。這就是為什麼Arduino晶片的每個引腳上都有一個內置上拉電阻的原因。

有兩種方法可以啟用它們:

pinMode(pin,INPUT); 
digitalWrite(pin,HIGH);
pinMode(pin,INPUT_PULLUP);

兩者俱有相同的效果,但是後一種效果更好,因為它更具可讀性。

注意:如果忘記使用pinMode(pin,OUTPUT),然後再使用digitalWrite(pin,HIGH),則將啟用上拉電阻,因為預設情況下所有引腳都設置為輸入。

現在連接沒有電阻的按鈕,只需連接到地面即可(如上圖所示)。
您可以看到我們不再需要使用Arduino的5v引腳了,假設我們要大規模生產成品,這種模式可以省下兩個電阻也會明顯降低生產成本。

範例button2-b。如您所見,我使用了兩種方式來啟用上拉電阻。另請注意,我使用了“非”運算符,因此按下按鈕時LED亮起。

小結

  • 要將buttons和switches與Arduino一起使用,您必須使用上拉或下拉電阻。
  • pinMode(pin,INPUT_PULLUP); 啟用Arduino的內部上拉電阻。
    digitalWrite(pin,HIGH); 輸入引腳啟用內部上拉電阻。
  • digitalRead(pin)返回輸入引腳1 = 5v,0 = 0v的狀態。
    如果你使用帶有上拉電阻的按鈕(例如內部電阻),則1表示未按下該按鈕,0表示已按下。
  • 你可以使用非運算符(!)交換1和0。例如,!digitalRead(pin)在未按下按鈕時返回0,在按下按鈕時返回1。

補充:直接端口操作(進階)

DigitalRead,digitalWrite和pinMode是好用且簡單的功能,但相對較慢。同樣,您不能完全同時打開或關閉2個引腳,也無法同時寫入8 bits用於同步通信。有時候,當您的記憶體不足時,這三個功能也可能佔用大量可用空間。

這些問題的解決方案是直接端口操作。Atmel晶片有一些(在大多數Arduinos上為3個)I / O引腳暫存器,這些bytes只是儲存了有關引腳是輸入還是輸出,設定為高還是低電位等信息的bytes。每個bytes中的bit對應Arduino上的I / O相對的引腳。

在Arduino Uno上,port D包含引腳0至7,port B的引腳是8至13而port C 是A0至A5。

晶片每個 port 都受三個暫存器控制,分別是 (x 代表 B, C, D):

  • DDRx:Data Direction Register:用來決定腳位是 INPUT 或 OUTPUT。(pinMode)
  • PORTx:Port Data Register:用來控制腳位輸出訊號為 HIGH 或為 LOW,以及禁用或啟用輸入上拉電阻。(digitalWrite)
  • PINx:Port Input Register:用來讀取腳位的輸入訊號。

在上圖中,您可以看到Arduino Uno 的整個引腳架構圖,埠口號位於引腳旁邊的黃色字段中。(圖片來源)

由於byte的每一個bit都代表一個引腳,因此以二進位表示法寫入值更加容易。您可以通過在數字前添加大寫字母B來實現此目的,例如B111是十進制的7(2 2 + 2 1 + 2 0)。

同樣,您可以使用前導0來使用八進位表示法,或者使用0x表示十六進位表示法,但是在這種情況下,使用這兩種表示法實際上沒有任何意義。

在計算bits(進位)時,最右邊的 (least significant, LSB) bit為0,因此它對應於埠口的第一個引腳,而MSB(最高有效位)對應於埠口的第八個引腳。

一些例子:

將引腳7設置為輸出,並將引腳0-6設置為輸入:

DDRD = B10000000;

將(輸出)引腳7設置為高:

PORTD = B10000000;

在(輸入)引腳6上啟用內部上拉電阻器:

PORTD = B01000000;

讀取引腳0到7的狀態:

byte state = PIND;

但以這種方式使用可能會有一些問題:例如,在第二個範例中,引腳7設置為高電位,但埠口中的所有其他引腳均設置為零,無論它們先前的狀態如何。要一次只更改一個引腳,我們可以使用一些位元運算。

要設定一個高電位而不改變其他電位,可以使用位元運算子|)。注意:這只是一個|,而boolean 運算子是||。位元運算表示分別應用設置於每一個bit。我們使用遮罩將右邊的bit設置為高:設定1為高的bit,其他bit設為0。

byte previousPORTD = PORTD;//讀取資料暫存器,並將其儲存在變數中
PORTD = previousPORTD | B10000000; //將第7個bit設置為high

如果遮罩中的一個bit為1,則該bit將在PORTD暫存器中設置為1;如果它為0,則將其值保留在以前的PORTD中。您可以在上面的圖片中查看真相表和一些案例。

要將bit設置為low,而不更改其他bit,可以使用位元運算子)。注意:這只是一個&,而boolean 運算子是&&。現在我們必須反轉遮罩:要設置為low的bit為0,所有其他bit為1。

byte previousPORTD = PORTD;//讀取data暫存器,並將其儲存在變數中
PORTD = previousPORTD&B01111111; //將第7個bit設置為low

這種表示法很好用,但我們可以使其更具可讀性。不用寫一個完整的二進位數作為遮罩,我們可以使用左移位元運算子(<<)。它是將所有數字向左移動給定數量的位置。例如:1 << 2 = B100,B101 << 1 = B1010,依此類推。這也是計算2的次方的簡單方法:1 << 7 = B10000000 = 128 = 2 7

我們將使用它來建立遮罩:例如,遮罩 B10000000可以寫為1 << 7,現在您可以輕鬆地看到它是暫存器中的第八個引腳,而不必計算0。

為了建立反遮罩,對於反向標記,我們可以使用位元非運算子)反轉每個位:B01111111可以寫為〜(1 << 7)。(見圖片)

如果只想翻轉一位或多位,則可以使用互斥運算子。(xor^)。如果輸入bit之一為1,則返回1;如果兩個bit輸入相同,則返回0。

byte previousPORTD = PORTD;//讀取data暫存器,並將其儲存在變數中
PORTD = previousPORTD ^ B10000000;//翻轉第7個bit

我們可以使用複合運算子來縮小代碼:x = x + 1; 可以寫成x + = 1; 例如。位元運算子也是如此。我們不再需要臨時變數。

PORTD | = 1 << 7; //將第7bit設置為high
PORTD&=〜(1 << 7); //將第7bit設置為low
PORTD ^ = 1 << 7; //翻轉第7bit

例如,要從輸入暫存器中獲取一個特定的bit,可以使用bitRead(byte,bit)函數:

boolean state = bitRead(PIND,6); //讀取port D的第6引腳的狀態

您可以使用一些基本數學來達到相同的結果:

boolean state =(PIND >> 6)%2; //讀取port D的第6引腳的狀態

這使用了右移>>)和餘數運算子):>>與<<相同,但方向相反。例如,如果PIND為B10101010,則PIND >> 6 = B10,則它將截斷最後6位(二進位)數字。現在,我們要檢查的bit是最右邊的bit。取餘給你一個除法的餘數,例如10%3 = 1,因為3 * 3 + 1 = 10,5%6 = 5,因為0 * 6 + 5 = 5,23%8 = 7,因為2 * 8 + 7=23。如果x為偶數,x%2將為您提供0,如果x為奇數,則將為您提供1。用二進位表示法,偶數的最後一個bit(最右邊的bit)為0,奇數的最後一個bit為1。因此,如果我們只想知道二進制數的最後一個bit,則可以使用x% 2。

僅獲得一個數字的另一種方法是使用條件運算子 (?: )

boolean state =(PIND&(1 << 6))== 0?0:1; //讀取port D的第6引腳的狀態

PIND&(1 << 6)僅保留PIND的第6個bit,所有其他數字均為0。例如,如果PIND為B10101010,則PIND&(1 << 6)= B00000000,如果PIND為B01010101,則PIND &(1 << 6)= B01000000。從這些示例中,您可以看到如果bit 6為0,則結果為零。因此,如果測試此結果是否== 0,我們將知道bit 6的狀態。使用條件運算子:condition?resultIfTrue:resultIfFalse;如果條件為true,則運算子將返回resultIfTrue;如果為false,則將返回resultIfFalse。

注意兼容性:port-to-pin的對映匹配取決於晶片。意思是如果使用另一個Arduino,則必須更改程序。對於個人使用來說,這並不是什麼大問題,但是如果您正在為團體編寫程序或程式庫或要在網上共享,則應考慮到這一點。

Arduino參考:整數常量

他殺了我的電線:使用數位埠口直接進行埠口操作

Arduino參考:埠口操作

Atmel ATmega 328p數據表第91頁 14.4

Arduino參考:bitRead

發佈留言