要控制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


張貼留言