要控制Arduino 的 I/O Port最常見的方式是使用digitalWrite 和 digitalRead 指令,但這個方法要每個 Port 逐一定義,速度較慢。有另一個比較快速的方法是直接從 Port 暫存器修改接腳的狀態,讓位元直接存入0或1,來表示 Pin腳的輸入或輸出。實做使用7個GPIO接腳,來控制兩個七段顯示器,讓數字從 1跳到 100。
B: 對應 Arduino 的 Digital pin 8 to 13
C: 對應 Arduino 的 Analog input pin 0 to 5
D: 對應 Arduino 的 Digital pins 0 to 7
例如,位於PortB 的 Digital Pin 8 簡稱作 PB0,PortD Digital Pin 0 簡稱作 PD1;位於 PortC 的 Analog Pin 2也可以說是 PC2。
在晶片內是透過暫存器(register)來對腳位進行設定,對於Arduino這種AVR晶片來說,每個Port都受三個暫存器控制,分別是(x可以用B, C, D代替):
DDRx (Data Direction Register):可讀可寫的暫存器,指定輸入/輸出,類似pinMode()。
Portx (Data Register):透過這類暫存器設定電壓為高電位或低電位,類似digitalWrite()。
PINx (Port Input Pins):唯讀,可以知道哪個 Pin 的電壓是高電位或低電位,類似 analogRead()。
[I/O Ports暫存器]
Arduino UNO 開發板用的晶片是 ATmega8 或 ATmega168/328 爲主,有3個 8-bit 的 PORTx(x 代表 B, C, D) :B: 對應 Arduino 的 Digital pin 8 to 13
C: 對應 Arduino 的 Analog input pin 0 to 5
D: 對應 Arduino 的 Digital pins 0 to 7
例如,位於PortB 的 Digital Pin 8 簡稱作 PB0,PortD Digital Pin 0 簡稱作 PD1;位於 PortC 的 Analog Pin 2也可以說是 PC2。
在晶片內是透過暫存器(register)來對腳位進行設定,對於Arduino這種AVR晶片來說,每個Port都受三個暫存器控制,分別是(x可以用B, C, D代替):
DDRx (Data Direction Register):可讀可寫的暫存器,指定輸入/輸出,類似pinMode()。
Portx (Data Register):透過這類暫存器設定電壓為高電位或低電位,類似digitalWrite()。
PINx (Port Input Pins):唯讀,可以知道哪個 Pin 的電壓是高電位或低電位,類似 analogRead()。
來源:arduino.cc
[材料]
- Arduino UNO R3 x 1
- 七段LED顯示器 x 2
- 麵包板 x 1
- 連接線 x n
[接線圖]
[程式]
void setup() { // B0-B1(Set as output); DDR-Data Direvction Register // 被用來設定 pin爲input(0) 或 output(1) DDRB = 0b00000011; //D1-D7(Set as output) DDRD = 0b11111110; } void loop() { start(); for (int i = 0; i < 10; i++) { for ( int j = 0; j < 10; j++) { for (int del = 0; del < 10; del++) { disp(i, j); } } } } void start() { int i = 2; while (i != 0) { if (i == 2) { //開啓 PORT B 的 1-Pin 並將其他 Pin 設定成 OFF. PORTB = 0b00000010; } if (i == 1) { PORTB = 0b00000001; } // 以下 PORTD 被註解是共陰型的七段顯示器, // 目前程式執行的是共陽式的七段顯示器 // PORTD = 0b00000010; PORTD = 0b11111101; delay(100); // PORTD = 0b00000110; PORTD = 0b11111001; delay(100); // PORTD = 0b00001110; PORTD = 0b11110001; delay(100); // PORTD = 0b00011110; PORTD = 0b11100001; delay(100); // PORTD = 0b00111110; PORTD = 0b11000001; delay(100); // PORTD = 0b01111110; PORTD = 0b10000001; delay(100); // PORTD = 0b11111110; PORTD = 0b00000001; delay(200); // PORTD = 0b01111110; PORTD = 0b10000001; delay(100); // PORTD = 0b00111110; PORTD = 0b11000001; delay(100); // PORTD = 0b00011110; PORTD = 0b11100001; delay(100); // PORTD = 0b00001110; PORTD = 0b11110001; delay(100); // PORTD = 0b00000110; PORTD = 0b11111001; delay(100); // PORTD = 0b00000010; PORTD = 0b11111101; delay(100); // PORTD = 0b00000000; PORTD = 0b11111111; delay(200); i--; } } void zero() { // PORTD = 0b01111110; PORTD = 0b10000001; } void one() { // PORTD = 0b00001100; PORTD = 0b11110011; } void two() { // PORTD = 0b10110110; PORTD = 0b01001001; } void three() { // PORTD = 0b10011110; PORTD = 0b01100001; } void four() { // PORTD = 0b11001100; PORTD = 0b00110011; } void five() { // PORTD = 0b11011010; PORTD = 0b00100101; } void six() { // PORTD = 0b11111010; PORTD = 0b00000101; } void seven() { // PORTD = 0b00001110; PORTD = 0b11110001; } void eight() { // PORTD = 0b11111110; PORTD = 0b00000001; } void nine() { // PORTD = 0b11001110; PORTD = 0b00110001; } void digit1(int x) { PORTB = 0b00000001; switch (x) { case 1: one(); break; case 2: two(); break; case 3: three(); break; case 4: four(); break; case 5: five(); break; case 6: six(); break; case 7: seven(); break; case 8: eight(); break; case 9: nine(); break; case 10: zero(); break; case 0: zero(); break; } } void digit2(int x) { PORTB = 0b000000010; switch (x) { case 1: one(); break; case 2: two(); break; case 3: three(); break; case 4: four(); break; case 5: five(); break; case 6: six(); break; case 7: seven(); break; case 8: eight(); break; case 9: nine(); break; case 0: zero(); break; case 10: zero(); break; } } void disp(int i, int j) { digit1(i); delay(10); digit2(j); delay(10); }
[實作結果]
[參考資料]
- Instructables: 2 Digit Seven Segment Display
- Arduino.cc: Port Registers
張貼留言