電子工程系車用電子與資訊組
Arduino基礎IO控制
吳錫修
sswu@nkut.edu.tw
Revised on July 8, 2018
數位訊號與類比訊號、IO腳位設定、數位輸出/入控制、
暫存器作業指令、類比輸出/入控制、矩陣鍵盤掃描、7段
顯示器、點矩陣LED、伺服馬達控制、LCD顯示控制
Makeeachdaycount
 類比訊號 (analog signal)
 連續變化的物理訊號,訊號的振幅、頻率或相位可能隨時間變化
 溫度、聲音、亮度、位移、壓力…
 數位訊號 (digital signal)
 只有高電位、低電位狀態訊號
 微電腦只能處理數位訊號,類比訊號必須先經過轉換才能處理
類比訊號與數位訊號
2
Makeeachdaycount
 D0 to D13可動態規劃做為數位輸入或數位輸出控制
 pinMode(接腳編號,INPUT|OUTPUT)
 接腳編號:0~13數字表示D0~D13
 範例
#define RED_LED 12
#define SW 8
void setup() {
pinMode(RED_LED, OUTPUT); //設定D12為輸出
pinMode(SW, INPUT); //設定D8為輸入
}
Arduino Uno數位IO腳位設定
3
Makeeachdaycount
 digitalWrite(接腳編號,HIGH|LOW)
 接腳編號:0~13數字表示D0~D13
 範例
#define RED_LED 12
void setup() {
pinMode(RED_LED, OUTPUT);
digitalWrite(RED_LED, HIGH);
}
Arduino Uno數位輸出控制
4
Makeeachdaycount
 使程式暫停指定時間
 delay(ms)
 ms: 暫停時間,單位毫秒 (milliseconds)
 delayMicroseconds(us)
 us: 暫停時間,單位微秒 (microseconds)
delay()指令
5
Makeeachdaycount
 當順向電壓超過切入電壓時,LED開始導通發光,電流會開始快速上
升,必須加限流電阻以免燒毀LED
 ⼀般限流電阻約150Ω~330Ω。若LED導通電壓1.7V,使用330Ω限流
電阻,則LED電流10mA
發光二極體 (Light-emitting diode)
6
材料 發光顏色 順向電壓
GaAs 紅外線 1.2V
GaAsP 紅光、黃光、橙光 2V
GaP 綠光 2.2V
GaN 藍光 5V
GaN+YAG 白光 4.1V
Makeeachdaycount
 實驗目的
 熟用數位輸出控制
 使LED每秒亮暗交錯
 LED D12
Lab LED閃爍控制 1/2
7
Makeeachdaycount
 參考程式
#define RED_LED 12
void setup() {
pinMode(RED_LED, OUTPUT);
}
void loop() {
digitalWrite(RED_LED, HIGH);
delay(1000);
digitalWrite(RED_LED, LOW);
delay(1000);
}
LED閃爍控制 2/2
8
Makeeachdaycount
 實驗目的
 熟用數位輸出控制
 使D11 D12 D13 三個LED輪流亮暗交錯
Lab LED跑馬燈控制I 1/2
9
Makeeachdaycount
 參考程式
byte counter = 0;
byte ledPins[] = {11, 12, 13};
void setup(){
for (byte i = 0; i < 3; i++) {
pinMode(ledPins[i], OUTPUT);
}
}
void loop() {
for (byte i = 0; i < 3; i++) {
digitalWrite(ledPins[i], counter == i);
}
delay(250);
counter = ++counter % 3; //counter值0, 1, 2循環變化
}
Lab LED跑馬燈控制I 2/2
10
Makeeachdaycount
 暫存器作業指令可同時控制多個IO接腳
 數位I/O接腳D0~D13
 PD0~PD7, PB0~PB5
 PORT D方向暫存器DDRD,PORT B方向暫存器DDRB
 0表示輸入,1表示輸出
 DDRB = B00111000
 設定D11 D12 D13為輸出
 設定D8 D9 D0為輸入
暫存器作業指令 1/2
11
Makeeachdaycount
 PORT D資料暫存器PORTD,PORT B資料暫存器PORTB
 0表示LOW,1表示HIGH
 PORTB = B00001000
 D11輸出HIGH
 D12 D13輸出LOW
 PORT D輸入暫存器PIND,PORT B輸入暫存器PINB
暫存器作業指令 2/2
12
Makeeachdaycount
 實驗目的
 熟用暫存器IO控制指令
 使D11 D12 D13三個LED輪流亮暗交錯
Lab LED跑馬燈控制II 1/2
13
Makeeachdaycount
 參考程式
byte data = B00001000;
byte shift = 0;
void setup()
{
DDRB = B00111000;
}
void loop()
{
PORTB = data << shift; //data本身資料不變
shift = ++shift % 3; //shift值0, 1, 2循環變化
delay(250); //等0.25秒
}
Lab LED跑馬燈控制II 2/2
14
Makeeachdaycount
路口紅綠燈時序
15
直
行
號
誌
橫
向
號
誌
紅
黃
綠
紅
黃
綠
Makeeachdaycount
 實驗目的
 熟用數位輸出狀態控制
 模擬十字路口紅綠燈號誌變化
Lab 路口紅綠燈控制I 1/4
16
Makeeachdaycount
 參考程式
byte rowLEDs[]={5, 6, 7}; //R1, Y1, G1
byte columnLEDs[]={2, 3, 4}; //R2, Y2, G2
void setup(){
for (byte i = 0; i < 3; i++) {
pinMode(rowLEDs[i], OUTPUT);
pinMode(columnLEDs[i], OUTPUT);
}
for (byte i = 0; i < 3; i++) {
digitalWrite(rowLEDs[i], LOW);
digitalWrite(columnLEDs[i], LOW);
}
}
Lab 路口紅綠燈控制I 2/4
17
Makeeachdaycount
void loop() {
digitalWrite(rowLEDs[2],HIGH); //Turn G1 on
digitalWrite(columnLEDs[0],HIGH); //Turn R2 on
delay(5000);
for (byte i = 0; i < 4; i++) { //Flash G1 4 times
digitalWrite(rowLEDs[2], LOW);
delay(250);
digitalWrite(rowLEDs[2], HIGH);
delay(250);
}
digitalWrite(rowLEDs[2], LOW); //Turn G1 off
digitalWrite(rowLEDs[1], HIGH); //Turn Y1 On
delay(2000);
digitalWrite(rowLEDs[1], LOW); //Turn Y1 Off
digitalWrite(columnLEDs[0],LOW); //Turn R2 off
Lab 路口紅綠燈控制I 3/4
18
G1
Y1
R1
G2Y2R2
Makeeachdaycount
digitalWrite(columnLEDs[2],HIGH); //Turn G2 on
digitalWrite(rowLEDs[0],HIGH); //Turn R1 on
delay(5000);
for (byte i = 0; i < 4; i++) { //Flash G2 4 times
digitalWrite(columnLEDs[2], LOW);
delay(250);
digitalWrite(columnLEDs[2], HIGH);
delay(250);
}
digitalWrite(columnLEDs[2], LOW); //Turn G2 off
digitalWrite(columnLEDs[1], HIGH); //Turn Y2 on
delay(2000);
digitalWrite(columnLEDs[1], LOW); //Turn Y2 off
digitalWrite(rowLEDs[0],LOW); //Turn R1 off
}
Lab 路口紅綠燈控制I 4/4
19
G1
Y1
R1
G2Y2R2
Makeeachdaycount
 實驗目的
 熟用暫存器IO控制指令
 模擬十字路口紅綠燈號誌變化
Lab 路口紅綠燈控制II 1/3
20
Makeeachdaycount
 參考程式
void setup(){
DDRD = B11111100; //G1, Y1, R1, G2, Y2, R2, X, X
}
void loop() {
PORTD = B10000100; //Turn G1 and R2 on
delay(5000);
for (byte i = 0; i < 8; i++) { //Flash G1 4 times
PORTD ^= B10000000;
delay(250);
}
PORTD = B01000100; //Turn Y1 and R2 on
delay(2000);
Lab 路口紅綠燈控制II 2/3
21
G1
Y1
R1
G2Y2R2
Makeeachdaycount
//PORTD = G1, Y1, R1, G2, Y2, R2, X, X
PORTD = B00110000; //Turn R1 and G2 on
delay(5000);
for (byte i = 0; i < 8; i++) { //Flash G2 4 times
PORTD ^= B00010000;
delay(250);
}
PORTD = B00101000; //Turn R1 and Y2 on
delay(2000);
}
Lab 路口紅綠燈控制II 3/3
22
G1
Y1
R1
G2Y2R2
Makeeachdaycount
 變數 = digitalRead(接腳編號);
 接腳編號:0~13數字表示D0~D13
 傳回值:HIGH or LOW
 範例
#define SW 8
bool keystate;
void setup() {
pinMode(SW, INPUT);
keystate = digitalRead(SW);
}
Arduino數位輸入控制
23
Makeeachdaycount
開關 (switch)
24
Makeeachdaycount
 按下時高電位  按下時低電位
開關接法
25
10KΩ
10KΩ
Button Pressed Button Released
Input Input
Button Pressed Button Released
Makeeachdaycount
 ATmeg328微控制器數位接腳有內建上接電阻 (Pull-up resistors),阻
值在20K~50K之間,只是預設並未啟用
 要啟用上接電阻必須將輸入接腳模式設定為INPUT_PULLUP
 pinMode(接腳編號, INPUT_PULLUP)
 接腳編號:0~13數字表示D0~D13
使用內建上接電阻
26
pull-up resistor
Makeeachdaycount
 按下按鈕時,開關訊號並不是很單純的由HIGH變LOW (或由LOW變
HIGH ),而可能會在高低電位之間彈跳 (bounce) ⼀段時間
 彈跳時間的⻑短和機械開關特性有關,⼀般為5ms到10ms。若沒有防
彈跳 (debounce) 處理,程式可能會解讀成按了好幾次按鈕
開關彈跳處理 1/2
27
Logic HIGH threshold
Button Pressed
Logic LOW threshold
Input signal
Makeeachdaycount
 防彈跳處理
 硬體式
 軟體式
 利用狀態變數及延遲,確認開關動作
開關彈跳處理 2/2
28
Logic HIGH threshold
Button Pressed
Logic LOW threshold
Check button state Check button state
dealy 20 ms
Makeeachdaycount
 實驗目的
 熟用開關輸入控制及防彈跳處理
 使用內建上接電阻
 每Click⼀次D8開關時,切換D12 LED狀態
Lab 開關控制LED 1/3
29
Makeeachdaycount
 參考程式
#define RED_LED 2
#define SW 3
bool ledState = LOW; //目前LED輸出腳位之狀態
bool lastState = HIGH; //前⼀次開關腳位之狀態
byte click = 0;
void setup() {
pinMode(RED_LED, OUTPUT);
pinMode(SW, INPUT_PULLUP);
}
Lab 開關控制LED 2/3
30
Makeeachdaycount
void loop() {
bool b1 = digitalRead(SW); //讀取開關目前狀態
if (b1 != lastState) { //開關狀態改變
delay(20); //防彈跳
if (b1 == digitalRead(SW)) { //再次確認開關狀態
lastState = b1;
click++;
}
}
if (click == 2){ //已Click開關
click = 0;
ledState = !ledState;
digitalWrite(RED_LED, ledState);
}
}
Lab 開關控制LED 3/3
31
Makeeachdaycount
 脈衝寬度調變(Pulse Width Modulation, PWM) 是⼀種透過數位的
方式所產⽣的類比訊號。⼀個脈衝寬度調變訊號包含了兩個主要的參
數:工作週期與頻率。工作週期所描述的是訊號中邏輯高準位所占的
時間與完成⼀個訊號週期的比例
 PWM常應用在調光燈具、馬達調速、伺服馬達角度控制等
脈波寬度調變 (PWM)
32
Makeeachdaycount
 D3, D5, D6, D9, D10, D11 支援PWM輸出
 analogWrite(接腳編號, 0~255)
 接腳編號:3, 5, 6, 9, 10, 11分別表示D3, D5, D6, D9, D10, D11
 範例
#define RED_LED 3
void setup() {
pinMode(RED_LED, OUTPUT);
analogWrite(RED_LED, 128);
}
Arduino類比輸出控制
33
Makeeachdaycount
 實驗目的
 熟用PWM輸出控制
 使D3腳位所控制之LED漸亮漸暗循環變化
Lab LED亮度控制 1/2
34
Makeeachdaycount
 參考程式
#define RED_LED 3
int lightness = 5; //LED亮度值
int change = 5; //LED亮度變化值
void setup() {
pinMode(RED_LED, OUTPUT);
}
void loop() {
for (; lightness >= 0 && lightness <= 255; lightness += change ) {
analogWrite(RED_LED, lightness);
delay(25);
}
delay(1000);
change = -change;
lightness += change;
}
Lab LED亮度控制 2/2
35
Makeeachdaycount
 RGB LED
 可分別控制紅、綠、藍晶元發光強度,合成全彩效果 (16,777, 216種顏色)
 常應用於廣告看板或情境燈
 共陽極(Common anode)
 共陰極(Common cathode)
mBot全彩LED
36
red
green
blue
common cathode
R G B
common
R G B
common
(不同廠牌RGB接腳可能有所差異)
Makeeachdaycount
 隨機產⽣⼀個數值
 變數 = random(max);
 隨機產⽣⼀個⼩於max之整數
 變數 = random(min, max);
 隨機產⽣⼀個⼤於或等於min,且⼩於max之整數
 範例
lightness = random(0, 256);
lightness = random(256);
random()指令
37
Makeeachdaycount
 實驗目的
 熟用PWM輸出控制及random()指令
 使全彩LED每秒隨機變換顏色
Lab 全彩LED控制 1/2
38
Makeeachdaycount
 參考程式
#define RED_LED 3
#define GREEN_LED 5
#define BLUE_LED 6
void setup() {
DDRD = B01101000; //X, B, G, X, R, X, X, X
}
void loop() {
byte r = random(256);
byte g = random(256);
byte b = random(256);
analogWrite(RED_LED, r);
analogWrite(GREEN_LED, g);
analogWrite(BLUE_LED, b);
delay(random(1000));
}
Lab 全彩LED控制 2/2
39
Makeeachdaycount
 微處理器是數位裝置,類比訊號必須經由ADC (Analog-to-Digital
Converter) 轉換為數位訊號
 ADC程序
 取樣
 量化
 編碼
類比轉數位訊號處理 1/3
40
Makeeachdaycount
 取樣
 每隔多久時間檢測訊號⼄次
 取樣頻率愈高,取樣波形愈能精準跟隨類比訊號變化情形,但產⽣的取樣
資料筆數愈多
類比轉數位訊號處理 2/3
41
取樣 取樣
Makeeachdaycount
 量化
 將類比訊號需振幅區分成多少等份,若工作電壓5V,10位元ADC表示解
析度是5V/1024 = 4.88mV
 解析度愈高,取樣量化值與類比訊號值愈相近(誤差愈⼩),但每筆取樣資
料佔用更多資料位元
類比轉數位訊號處理 3/3
42
解
析
度
解
析
度
Makeeachdaycount
 接腳: A0, A1, A2, A3, A4,A5
 變數 = analogRead (接腳編號);
 接腳編號:A0~A5
 傳回值:0~1023
 指令執行時間約100 microseconds
 範例
#define VR A0
int value;
void setup() {
pinMode(VR, INPUT);
value = analogRead(VR);
}
Arduino類比輸入控制
43
Makeeachdaycount
 將⼀個數值從⼀個範圍重新映射到另⼀個範圍
 變數 = map(value, fromLow, fromHigh, toLow, toHigh);
 將value值依照fromLow與fromHigh之範圍,對等轉換至toLow與toHigh
之範圍
 範例
#define VR A0
...
lightness = map(analogRead(VR),0, 1023, 0, 255);
map()指令
44
fromLow fromHigh
toLow
toHigh
value
return value
Makeeachdaycount
 中文通常又稱為可變電阻 (Variable Resistor,VR)
 A型:電阻值的變化與旋轉角度呈對數關係
 用於音量調整
 B型:電阻值的變化與旋轉角度呈線性關係
 C型:電阻值的變化與旋轉角度呈反對數關係
電位器 (Potentiometer)
45
wiper turns
with dial resistive
material
R1 R2
A B
W
R1 R2
A B
W
Makeeachdaycount
 實驗目的
 熟用類比輸入控制及map()指令
 旋轉A0可變電阻調整D11 LED亮度
Lab LED調光控制 1/2
46
Makeeachdaycount
 參考程式
#define LED 3
#define VR A0
int lightness = 0;
void setup() {
pinMode(LED, OUTPUT);
pinMode(VR, INPUT);
}
void loop() {
lightness = map(analogRead(VR),0, 1023, 0, 255);
analogWrite(LED, lightness);
}
Lab LED調光控制 2/2
47
Makeeachdaycount
 簡單的聲音輸出裝置
 控制振動頻率,可輸出簡單的音階
蜂鳴器
48
音階 Do Re Mi Fa So La Si
低音 261 294 329 349 392 440 493
中音 523 587 659 698 784 880 988
高音 1046 1175 1318 1397 1568 1760 1976
繞組線圈
磁鐵
外殼
封膠
電路板
端子
鐡心
振動膜隔板
矽膠
Makeeachdaycount
 產⽣指定頻率的方波
 tone(接腳編號, 頻率, 持續時間)
 程式會繼續執行
 要輸出⼀連串音符時,需配合delay()指令使用
 範例
#define BELL 7
pinMode(BELL, OUTPUT);
tone(BELL, 523, 500);
dealy(500);
tone(BELL, 659, 500);
tone()指令
49
Makeeachdaycount
 實驗目的
 熟用蜂鳴器輸出控制
 按⼀下按鍵時,讓蜂鳴器發出音樂⾨鈴聲
 Mi Do So (低音) Do Re So Re Mi Re So (低音) Do
Lab 音樂門鈴 1/3
50
Makeeachdaycount
 參考程式
#define BELL 2
#define SW 3
const byte LENGTH = 11;
int note[LENGTH]={659,523,392,523,587,784,587,659,587,392,523}; //音符
int beat[LENGTH]={500,500,500,500,500,1000,500,500,500,500,500}; //節拍
void setup() {
pinMode(SW, INPUT_PULLUP);
pinMode(BELL, OUTPUT);
}
void loop() {
if (digitalRead(SW) == LOW) playBell();
}
Lab 音樂門鈴 2/3
51
Makeeachdaycount
void playBell(){
for(byte i = 0; i < LENGTH; i++){
tone(BELL, note[i], tempo[i]);
delay(tempo[i]);
}
}
Lab 音樂門鈴 3/3
52
Makeeachdaycount
 不同廠牌44矩陣鍵盤排針腳位及按鍵面板數值排列有所差異
44矩陣鍵盤
53
column
4321
row1
row2
row3
row4
row 1~4 col 1~4
col 1~4 row 1~4
Makeeachdaycount
0 1 1 1 Scan column0
44矩陣鍵盤掃描原理 1/4
54
+V
PD.0
PD.1
PD.2
PD.3
PD.4
PD.5
PD.6
PD.7
+V
0 4 8 C
1 5 9 D
2 6 A E
3 7 B F
column
4321
row1
row2
row3
row4
Makeeachdaycount
1 0 1 1 Scan column1
44矩陣鍵盤掃描原理 2/4
55
+V
PD.0
PD.1
PD.2
PD.3
PD.4
PD.5
PD.6
PD.7
+V
0 4 8 C
1 5 9 D
2 6 A E
3 7 B F
column
4321
row1
row2
row3
row4
Makeeachdaycount
1 1 0 1 Scan column2
44矩陣鍵盤掃描原理 3/4
56
+V
PD.0
PD.1
PD.2
PD.3
PD.4
PD.5
PD.6
PD.7
+V
0 4 8 C
1 5 9 D
2 6 A E
3 7 B F
column
4321
row1
row2
row3
row4
Makeeachdaycount
1 1 1 0 Scan column3
44矩陣鍵盤掃描原理 4/4
57
+V
PD.0
PD.1
PD.2
PD.3
PD.4
PD.5
PD.6
PD.7
+V
0 4 8 C
1 5 9 D
2 6 A E
3 7 B F
column
4321
row1
row2
row3
row4
Makeeachdaycount
 實驗目的
 熟用矩陣鍵盤掃描控制
 D4~D7鍵盤掃描輸出
 D8~D11按鍵檢測輸入
 在Serial Monitor顯示所按下的按鍵值
 注意44矩陣鍵盤排針腳位
Lab 矩陣鍵盤輸入 1/4
58
Makeeachdaycount
 參考程式
char keypad[4][4] = { //矩陣按鍵
{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'*','0','#','D'}};
byte row = 0, col = 0;
byte scan[4] = {B01110000,B10110000,B11010000,B11100000};
void setup() {
DDRD = B11110000; //D4, D5, D6, D7做為直行掃描輸出
DDRB = B00000000; //D8, D9, D10, D11做為橫列按鍵檢測輸入
Serial.begin(9600);
}
Lab 矩陣鍵盤輸入 2/4
59
Makeeachdaycount
void loop() {
for (col = 0; col < 4; col++){
PORTD = scan[col]; //送出直行掃描碼
byte k = PINB & B00001111; //讀取D8, D9, D10, D11值
switch (k){
case 14:
row = 3;
Serial.println(keypad[row][col]);
break;
case 13:
row = 2;
Serial.println(keypad[row][col]);
break;
case 11:
row = 1;
Serial.println(keypad[row][col]);
break;
Lab 矩陣鍵盤輸入 3/4
60
Makeeachdaycount
case 7:
row = 0;
Serial.println(keypad[row][col]);
break;
}
delay(25);
}
}
Lab 矩陣鍵盤輸入 4/4
61
Makeeachdaycount
 4位數密碼鎖態圖
狀態圖
62
1
0
2
開鎖
第2碼 第3碼
第1碼
其它鍵
其它鍵
其它鍵
等待5秒
3
第4碼其它鍵
關鎖
Makeeachdaycount
 實驗目的
 熟用矩陣鍵盤掃描控制
 D4~D7鍵盤掃描輸出,D8~D11按鍵檢測輸入
 密碼鎖作業
 初始為關鎖狀態 (亮D13紅色LED)
 正確輸入密碼時點亮D12綠色LED,5秒後回
復關鎖狀態
 注意44矩陣鍵盤排針腳位
Lab 密碼鎖 1/5
63
Makeeachdaycount
 參考程式
char keypad[4][4] = { //矩陣按鍵
{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'*','0','#','D'}};
byte row = 0, col = 0;
byte scan[4] = {B01110000,B10110000,B11010000,B11100000};
char password[4] = {'3','4','6','6'};
byte state = 0;
void setup() {
DDRD = B11110000; //D4~D7做為直行掃描輸出
DDRB = B00110000; //D8~D11做為橫列按鍵檢測輸入; D12,D13開鎖指示鐙
Serial.begin(9600);
}
Lab 密碼鎖 2/5
64
Makeeachdaycount
void loop() {
for (col = 0; col < 4; col++){
PORTD = scan[col]; //送出直行掃描碼
byte k = PINB & B00001111; //讀取D8, D9, D10, D11值
switch (k){
case 14:
row = 3;
check();
Serial.println(keypad[row][col]);
break;
case 13:
row = 2;
check();
Serial.println(keypad[row][col]);
break;
Lab 密碼鎖 3/5
65
Makeeachdaycount
case 11:
row = 1;
check();
Serial.println(keypad[row][col]);
break;
case 7:
row = 0;
check();
Serial.println(keypad[row][col]);
break;
}
delay(25);
}
Lab 密碼鎖 4/5
66
Makeeachdaycount
if (state == 4) {
digitalWrite(12, HIGH);
digitalWrite(13, LOW);
delay(5000);
state = 0;
}
else {
digitalWrite(12, LOW);
digitalWrite(13, HIGH);
}
}
void check(){
if (keypad[row][col] == password[state])
state++;
else
state = 0;
}
Lab 密碼鎖 5/5
67
Makeeachdaycount
 七段顯示器 (Seven-segment display) 為常用顯示元件。藉由七個發
光二極體以不同組合來顯示數字
 分為共陽極 (Common anode) 共陰極 (Common cathode) 二種,使
用時要先確認
7段顯示器 1/3
68
Makeeachdaycount
 共陽極 (Common anode) 七段顯示器
7段顯示器 2/3
69
g a bf
com
e c dpd
com
b
cd
e
f
a
g
dp
dp g f e d C b a
0 1 1 0 0 0 0 0 0
1 1 1 1 1 1 0 0 1
2 1 0 1 0 0 1 0 0
3 1 0 1 1 0 0 0 0
4 1 0 0 1 1 0 0 1
5 1 0 0 1 0 0 1 0
6 1 0 0 0 0 0 1 0
7 1 1 1 1 1 0 0 0
8 1 0 0 0 0 0 0 0
9 1 0 0 1 0 0 0 0
1 1 1 1 1 1 1 1
Makeeachdaycount
 共陰極 (Common cathode) 七段顯示器
7段顯示器 3/3
70
g a bf
com
e c dpd
com
b
cd
e
f
a
g
dp
dp g f e d c b a
0 0 0 1 1 1 1 1 1
1 0 0 0 0 0 1 1 0
2 0 1 0 1 1 0 1 1
3 0 1 0 0 1 1 1 1
4 0 1 1 0 0 1 1 0
5 0 1 1 0 1 1 0 1
6 0 1 1 1 1 1 0 1
7 0 0 0 0 0 1 1 1
8 0 1 1 1 1 1 1 1
9 0 1 1 0 1 1 1 1
0 0 0 0 0 0 0 0
Makeeachdaycount
 佔用較多IO接腳
直接驅動
71
+V
com
common anode
PD.7
PD.6
PD.5
PD.4
PD.3
PD.2
PD.1
PD.0
Arduino
0
0
1
0
0
1
0
1
a
b
c
d
e
f
g
dp
Makeeachdaycount
 實驗目的
 熟悉D1~D7直接驅動共陽七段顯示器
 0~9循環計數,每秒計數⼄次
Lab 7段顯示器輸出控制 1/2
72
Makeeachdaycount
 參考程式
byte disp_code[10] = { //g,f,e,d,c,b,a,X
B10000000, B11110010, B01001000, B01100000, B00110010,
B00100100, B00000110, B11110000, B00000000, B00110000
};
void setup() {
DDRD = B11111110; //D1~D7輸出接7段顯示器a~g
}
// the loop function runs over and over again forever
void loop() {
for (byte i = 0; i < 10; i++) {
PORTD = disp_code[i];
delay(1000);
}
}
Lab 7段顯示器輸出控制 2/2
73
Makeeachdaycount
 7447:BCD轉共陽極七段顯示器解碼驅動IC
 7448/CD4511:BCD轉共陰極七段顯示器解碼驅動IC
使用解碼IC驅動七段顯示器
74
com
common
cathode
0
1
0
0
1
1
0
1
1
0
1
BCD
display code
D0
D1
D2
D3
PB.0
PB.1
PB.2
PB.3
Arduino a
b
c
d
e
f
g
13
12
11
10
9
15
14
7
1
2
6
3 4 16
+V
/LT /BL VCC
GND /LE
8 5
CD4511
Makeeachdaycount
 BCD-to-7 Segment Latch/Decoder/Driver
CD4511
75
Makeeachdaycount
 實驗目的
 熟悉使用4511驅動共陰七段顯示器
 0~9循環計數,每秒計數⼄次
Lab CD4511驅動7段顯示器 1/2
76
Makeeachdaycount
 參考程式
byte bcd_code[10] = {
0, 1, 2, 3, 4,
5, 6, 7, 8, 9
};
void setup() {
DDRB = B00001111; //D8~D11輸出接CD4511 BCD輸入
}
void loop() {
for (byte i = 0; i < 10; i++) {
PORTB = disp_code[i];
delay(1000);
}
}
Lab CD4511驅動7段顯示器 2/2
77
Makeeachdaycount
4位數7段顯示器
78
D4 a f D3 D2 b
e d dp c g D1
Makeeachdaycount
七段顯示器掃描顯示
79
LT
RBI
RBO
1
2
4
8
A
B
C
D
E
F
G
a
b
c
d
e
f
g
PD.0
PD.1
PD.2
PD.3
PD.4
PD.5
PD.6
PD.7
+V
+V
Common anode
7447
D0D1D2D3
Arduino
Makeeachdaycount
 8-bit serial-in, parallel-out shift register
74HC595 1/3
80
Makeeachdaycount
74HC595 2/3
81
並
列
輸
出
存入資料
Makeeachdaycount
 74HC595從Arduino接收串列資料,轉為並列驅動7段顯示器
 只佔用3個Arduino IO接腳
74HC595 3/3
82
com
common
cathode
15
1
2
3
4
5
6
7
SER
RCLK
SRCLK
D2
D3
D4
Arduino
01101101
QA
QB
QC
QD
QE
QF
QG
QH
serial data
13 8
16 10
+V
a
b
c
d
e
f
g
display code
LSBFIRST
14
12
11
1
1
0
1
1
0
1
VCC /SRCLR
/OE GND
74HC595
Makeeachdaycount
 將⼀個byte資料以序列方式逐位元送出
 shiftOut(dataPin, clockPin, bitOrder, value)
 dataPin 位元資料輸出腳位
 clockPin 移位時序輸出腳位
 bitOrder 串列資料送出的順序
 MSBFIRST 由最高位元開始傳送
 LSBFIRST 由最低位元開始傳送
 value 要傳送的資料
shiftOut()指令
83
Arduino
Arduino
74HC595
74HC595
Makeeachdaycount
 實驗目的
 熟悉使用74HC595驅動共陰七段顯示器
 0~9循環計數,每秒計數⼄次
Lab 74HC595驅動7段顯示器 1/3
84
Makeeachdaycount
 參考程式
const byte dataPin = 2;
const byte latchPin = 3;
const byte clockPin = 4;
byte count = 0;
byte display_code[10] = { //_abcdefg
B01111110, B00110000, B01101101, B01111001, B00110011,
B01011011, B01011111, B01110000, B01111111, B01110011
};
void setup() {
pinMode(dataPin, OUTPUT); //D2~D4輸出接74HC595輸入
pinMode(latchPin, OUTPUT);
pinMode(clockPin, OUTPUT);
}
Lab 74HC595驅動7段顯示器 2/3
85
Makeeachdaycount
 參考程式
void loop() {
digitalWrite(latchPin, LOW);
shiftOut(dataPin, clockPin, LSBFIRST, display_code[count]);
digitalWrite(latchPin, HIGH);
delay(1000);
count = ++count % 10; //count值0, 1, 2, ..., 9循環變化
}
Lab 74HC595驅動7段顯示器 3/3
86
Makeeachdaycount
 只佔用3個Arduino IO接腳
74HC595二位數串級顯示
87
com
common
cathode
1
1
0
1
1
0
1
SER
RCLK
SRCLK
D2
D3
D4
Arduino
01101101 01111001
QA
QB
QC
QD
QE
QF
QG
QH
13 8
16 10
+V
a
b
c
d
e
f
g
com
common
cathode
1
1
1
1
0
0
1
SER
RCLK
SRCLK
QA
QB
QC
QD
QE
QF
QG
QH
13 8
16 10
+V
a
b
c
d
e
f
g
QH'
序列輸出
LSBFIRST 15
1
2
3
4
5
6
7
15
1
2
3
4
5
6
7
14
12
11
9
14
12
11
/OE GND
/OE GND
VCC /SRCLR
VCC /SRCLR
74HC59574HC595
Makeeachdaycount
 實驗目的:熟悉使用74HC595串聯驅動共陰七段顯示器
Lab 74HC595串級驅動7段顯示器 1/3
88
Makeeachdaycount
 參考程式
const byte dataPin = 2;
const byte latchPin = 3;
const byte clockPin = 4;
byte count = 0;
byte display_code[10] = { //_abcdefg
B01111110, B00110000, B01101101, B01111001, B00110011,
B01011011, B01011111, B01110000, B01111111, B01110011
};
void setup() {
pinMode(dataPin, OUTPUT); //D2~D4輸出接74HC595輸入
pinMode(latchPin, OUTPUT);
pinMode(clockPin, OUTPUT);
}
Lab 74HC595串級驅動7段顯示器 2/3
89
Makeeachdaycount
 參考程式
void loop() {
digitalWrite(latchPin, LOW);
shiftOut(dataPin, clockPin, LSBFIRST, display_code[count]);
digitalWrite(latchPin, HIGH);
delay(1000);
count = ++count % 10; //count值0, 1, 2, ..., 9循環變化
}
Lab 74HC595串級驅動7段顯示器 3/3
90
Makeeachdaycount
 序列週邊介面 (Serial Peripheral Interface)
 D13 (PB5) SCK,Serial Clock
 D12 (PB4) MISO,Master Input Slave Output
 D11 (PB3) MOSI,Master Output Slave Input
 D10 (PB2) /SS,slave select
SPI介面
91
Makeeachdaycount
LED矩陣
92
Pin No. Pin No.
Pin 1
pin 1
pin 8
pin 16
Makeeachdaycount
 可驅動8位數共陰七段顯示器或8*8點矩陣LED
 SPI介面,可串級連接
MAX7219 1/9
93
MAX7219點矩陣模組
MAX7219七段顯示器模組
Makeeachdaycount
 驅動七段顯示器
MAX7219 2/9
94
Common
cathode
Makeeachdaycount
 驅動點矩陣LED
MAX7219 3/9
95
Makeeachdaycount
 功能圖 (Functional Diagram)
MAX7219 4/9
96
Makeeachdaycount
 位數資料暫存器 (Digit register) ,共有8個,分別存放每個七段顯示
器要顯示的資料 (或8*8點矩陣LED的每⼀行資料)
 亮度暫存器 (Intensity register)
 控制顯示器亮度,數值0(最暗)~15(最亮)
 顯示檢測暫存器 (Display-test register),
 設定為1時,MAX7219將進入測試模式,所有LED都會被點亮;設定為0,
則為⼀般模式
MAX7219 5/9
97
Register Data
Corresponding
Segment Line
D7 D6 D5 D4 D3 D2 D1 D0
DP A B C D E F G
Makeeachdaycount
 解碼模式暫存器 (Decode mode register)
 暫存器中的每個位元對應⼀個顯示位數。1表示該位數啟用內建B字型碼解
碼功能,0表示該位數不啟用B字型碼解碼功能,例如:
 設定為0x0,不啟用B字型碼解碼功能,用於驅動LED矩陣
 設定為0x1,digit 0啟用B字型碼解碼功能,digits 1~7不啟用BCD解碼
 設定為0xFF,所有位數都啟用B字型碼解碼功能
 停機暫存器 (Shutdown register)
 設定為0,關閉LED,但MAX7219仍可接收資料;設定為1則為⼀般模式
 掃描限制暫存器 (Scan-Limit register)
 設定要掃描的顯示器位數,0~7分別表示顯示1位~8位七段顯示器 (或1~8
行LED矩陣)
MAX7219 6/9
98
Makeeachdaycount
 內建Code B Font
MAX7219 7/9
99
Makeeachdaycount
 暫存器識別位址
MAX7219 8/9
100
Register
Address
Hex code
D15~D12 D11 D10 D9 D8
No-Op X 0 0 0 0 0x0
Digit 0 X 0 0 0 1 0x1
Digit 1 X 0 0 1 0 0x2
Digit 2 X 0 0 1 1 0x3
Digit 3 X 0 1 0 0 0x4
Digit 4 X 0 1 0 1 0x5
Digit 5 X 0 1 1 0 0x6
Digit 6 X 0 1 1 1 0x7
Digit 7 X 1 0 0 0 0x8
Mode X 1 0 0 1 0x9
Intensity X 1 0 1 0 0xA
Scan limit X 1 0 1 1 0xB
Shutdown X 1 1 0 0 0xC
Display test X 1 1 1 1 0xF
Makeeachdaycount
 MAX7219每次接收16位元資料,前8位元表示資料,接著是4位元的
位址,最後4個高位元沒有使用
 Serial-Data Format (16 Bits)
 Arduino傳送數據時,先傳送8位元的位址 (高位元組),再傳送資料
(低位元組資料)
MAX7219 9/9
101
Arduino控制板
MAX7219
0000000101110001
要傳送給Digit 0暫存器資料內容
Makeeachdaycount
 實驗目的
 熟悉使用MAX7219驅動2位數共陰七段顯示器
 00~99循環計數,每秒計數⼄次
Lab MAX7219驅動7段顯示器 1/3
102
Makeeachdaycount
#include <SPI.h> //引用SPI程式庫
//定義MAX7219暫存器
const byte NOOP = 0x0; //不運作
const byte DECODEMODE = 0x9; //解碼模式
const byte INTENSITY = 0xA; //顯示強度
const byte SCANLIMIT = 0xB; //掃描限制
const byte SHUTDOWN = 0xC; //停機
const byte DISPLAYTEST = 0xF; //顯示器檢測
void max7219(byte reg, byte data) { //設定MAX7219暫存器資料的自訂函數
digitalWrite (SS, LOW);
SPI.transfer (reg);
SPI.transfer (data);
digitalWrite (SS, HIGH);
}
Lab MAX7219驅動7段顯示器 2/3
103
Makeeachdaycount
void setup () {
pinMode(SS, OUTPUT); //將預設的SS腳 (D10) 設成「輸出」
digitalWrite(SS, HIGH); //先在SS腳輸出高電位,表示「尚不選取周邊」
SPI.begin (); //啟動SPI連線
max7219(SCANLIMIT, 1); //設定掃描digit 0及digit 1
max7219(DECODEMODE, 0xFF); //啟用B字型碼解碼
max7219(INTENSITY, 8); //設定成中等亮度
max7219(DISPLAYTEST, 0); //關閉顯示器測試
max7219(SHUTDOWN, 1); //⼀般作業模式
}
void loop () {
for (byte i = 0; i < 10; i++)
for (byte j = 0; j <10; j++) {
max7219(0x01, j); //顯示個位數
max7219(0x02, i); //顯示十位數
delay(1000);
}
}
Lab MAX7219驅動7段顯示器 3/3
104
Makeeachdaycount
 實驗目的
 熟悉使用MAX7219驅動共陰8*8點矩陣LED
Lab MAX7219驅動點矩陣LED 1/4
105
Makeeachdaycount
byte symbol[8] = {0x0C, 0x1E, 0x3E, 0x7C, 0x7C, 0x03E, 0x1E, 0x0C};
0
0
1
1
0
0
0
0
Lab MAX7219驅動點矩陣LED 2/4
106
低位元
高位元
0
1
1
1
1
0
0
0
0
1
1
1
1
1
0
0
0
0
1
1
1
1
1
0
0
0
1
1
1
1
1
0
0
1
1
1
1
1
0
0
0
1
1
1
1
0
0
0
0
0
1
1
0
0
0
0
0x0C 0x1E 0x3E 0x7C 0x7C 0x3E 0x1E 0x0C
第1行 第8行
第1列
第8列
Makeeachdaycount
#include <SPI.h> //引用SPI程式庫
byte symbol[8] = {0x0C, 0x1E, 0x3E, 0x7C, 0x7C, 0x03E, 0x1E, 0x0C};
//定義MAX7219 暫存器
const byte NOOP = 0x0; //不運作
const byte DECODEMODE = 0x9; //解碼模式
const byte INTENSITY = 0xA; //顯示強度
const byte SCANLIMIT = 0xB; //掃描限制
const byte SHUTDOWN = 0xC; //停機
const byte DISPLAYTEST = 0xF; //顯示器檢測
void max7219(byte reg, byte data) { //設定MAX7219暫存器資料的自訂函數
digitalWrite (SS, LOW);
SPI.transfer (reg);
SPI.transfer (data);
digitalWrite (SS, HIGH);
}
Lab MAX7219驅動點矩陣LED 3/4
107
Makeeachdaycount
void setup () {
pinMode(SS, OUTPUT); //將預設的SS腳(數位 10)設成「輸出」
digitalWrite(SS, HIGH); //先在SS腳輸出高電位,表示「尚不選取周邊」
SPI.begin (); //啟動SPI連線
max7219 (SCANLIMIT, 7); //設定掃描8行
max7219 (DECODEMODE, 0); //不使用B字型碼解碼
max7219 (INTENSITY, 8); //設定成中等亮度
max7219 (DISPLAYTEST, 0); //關閉顯示器測試
max7219 (SHUTDOWN, 1); //關閉停機模式
}
void loop () {
for (byte i = 0; i < 8; i++) {
max7219 (i + 1, symbol[i]); //顯示自訂圖像
}
}
Lab MAX7219驅動點矩陣LED 4/4
108
Makeeachdaycount
 伺服馬達 (servo motor),因常用於遙控模型飛機,也稱為RC伺服機
(Remote Control Servo) 或伺服馬達舵機
 ⼀般伺服馬達有三條線,電源 (紅)、接地 (黑或棕)、訊號線(黃)
伺服馬達 1/2
109
Makeeachdaycount
 由直流馬達、減速齒輪、電位器及控制電路組成,減速齒輪可以減緩
馬達轉速同時提高轉矩,電位器則是用來回饋目前位置
 透過訊號線傳送50Hz PWM脈波來控制伺服馬達軸柄的旋轉角度
 SG90脈波寬度從1.0ms到2.0ms;也可將1.0ms當做角度0度,那麼1.5ms
會是90度,2.0ms則是轉到底180度 (注意,也有可能反過來)
 ⼩角度可能會抖動
 不同廠牌型號的伺服馬達可允許旋轉的角度各不相同
伺服馬達 2/2
110
Makeeachdaycount
 實驗目的
 熟用SG90伺服馬達控制
 使用VR控制SG90伺服馬達旋轉角度
Lab 伺服馬達角度調控 1/3
111
Makeeachdaycount
 參考程式
#include <Servo.h>
#define VR A0
#define SERVO 5
Servo servo;
int lastAngle;
int angle;
void setup() {
pinMode(SERVO, OUTPUT);
pinMode(VR, INPUT);
servo.attach(SERVO);
}
Lab 伺服馬達角度調控 2/3
112
Makeeachdaycount
void loop() {
angle = map(analogRead(VR), 0, 1023, 20, 170); //將0-1023數值映對為20-170
if (angle != lastAngle) {
servo.write(angle);
delay(15);
}
lastAngle = angle;
}
Lab 伺服馬達角度調控 3/3
113
Makeeachdaycount
 液晶顯示器 (Liquid-Crystal Display,LCD)
 利用電場改變液晶的排列方向來控制透光效果,由於液晶本身不發光,
有些會提供背光模組
 分為文字型及繪圖型
文字型LCD顯示器 1/4
114
16*2文字型LCD
128*64繪圖型LCD
Makeeachdaycount
 文字型LCD驅動控制晶片以HD44780為主
 資料滙流排可規劃成8位元或4位元連接方式,為了減少LCD與處理器的連
線,通常採用4位元方式連線 (使用DB4~DB7)
文字型LCD顯示器 2/4
115
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
VSS VDD VO RS RW E DB0 DB1 DB2 DB3 DB4 DB5 DB6 DB7 A K
0V +5V
LCD
power
supply
Register
Select
0: Command
1: Data
0: Write
1: Read
Enable
LCD
module
4-bit low order data bus 4-bit high order data bus
Backlight
+
Backlight
-
Makeeachdaycount
文字型LCD顯示器 3/4
116
DB7
DB6
DB5
DB4
E
RS
VSS RW K
16*2CharacterLCD
VDD
+V
VO
+V
A
220Ω
10KΩ
D2
D3
D4
D5
D11
D12
Arduino
Makeeachdaycount
 HD44780內部顯示資料記憶體共80byte,其排列方式視LCD為單列或雙
列而有所不同 (標示網底為顯示區)
文字型LCD顯示器 4/4
117
Display column number 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 … 39 40
Row 1 address (HEX) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 … 26 27
Row 2 address (HEX) 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 50 51 … 66 67
16*2 Character LCD
Display column number 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 … 39 40
Row 1 address (HEX) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 … 26 27
Row 2 address (HEX) 40 41 42 43 44 45 46 47 48 49 4A 4B 4C 4D 4E 4F 50 51 … 66 67
8*2 Character LCD
Display column number 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 … 79 80
Row 1 address (HEX) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 … 4E 4F
16*1 Character LCD
Display column number 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 … 79 80
Row 1 address (HEX) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F 10 11 … 4E 4F
8*1 Character LCD
Makeeachdaycount
 Arduino IDE內建已安裝LiquidCrystal函式庫,簡化的驅動HD44780
相容LCD模組作業
#include <LiquidCrystal.h>
 LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
 建構LiquidCrystal物件
 rs 連接LCD模組RS接腳之輸出腳位
 en 連接LCD模組Enable接腳之輸出腳位
 d4 連接LCD模組D4接腳之輸出腳位
 lcd.begin(col, row);
 設定LCD模組行列數
 col 行數,16
 row 列數,1或2
LiquidCrystal函式庫 1/3
118
Makeeachdaycount
 lcd.clear();
 清除顯示資料並重置游標
 lcd.setCursor(col, row);
 設定游標位置,即文字輸出位置
 col 行位置,0~15
 row 列位置,0~1
 lcd.print(val);
 輸出資料到LCD模組
 lcd.write(char);
 輸出⼀個字元到LCD模組
LiquidCrystal函式庫 2/3
119
Makeeachdaycount
 lcd.display();
 回復顯示
 lcd.noDisplay();
 關閉顯示,但資料會保留
 lcd.scrollDisplayLeft();
 將顯示資料循環左移⼀個位數
 lcd.scrollDisplayRight();
 將顯示資料循環右移⼀個位數
LiquidCrystal函式庫 3/3
120
Makeeachdaycount
 實驗目的
 熟用文字型LCD顯示控制
Lab 文字型LCD顯示控制 1/3
121
Makeeachdaycount
 參考程式
#include <LiquidCrystal.h>
const byte rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
char msg[] = "hello, arduino!";
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
void setup() {
lcd.begin(16, 2);
}
Lab 文字型LCD顯示控制 2/3
122
Makeeachdaycount
void loop() {
lcd.print("NKUT E.E."); //在第⼀列顯示NKUT E.E.
for (byte i = 0; i < sizeof(msg)-1; i++) { //在第二列以打字效果顯示hello, arduino!
delay(250);
lcd.setCursor(i, 1);
lcd.write(msg[i]);
}
//閃爍⼀次後清除
delay(1000);
lcd.noDisplay();
delay(1000);
lcd.display();
delay(1000);
lcd.clear();
delay(1000);
}
Lab 文字型LCD顯示控制 3/3
123
Makeeachdaycount
 Chris Parish以 LiquidCrystal函式庫為基礎寫了ShiftLCD函式庫,可
以使用74HC595移位暫存器控制HD44780相容的LCD模組,減少
Arduino IO接腳
 http://www.miselph.co.uk/arduino/ShiftLCD.zip
序列連接LCD 1/2
124
15
1
2
3
4
5
6
7
SER
RCLK
SRCLK
D2
D3
D4
Arduino QA
QB
QC
QD
QE
QF
QG
QH
13 8
16 10
+V
14
12
11
VCC /SRCLR
/OE GND
74HC595
DB7
DB6
DB5
DB4
E
RS
VSS RW K
16*2CharacterLCD
VDD
+V
VO
+V
A
220Ω
10KΩ
Makeeachdaycount
 參考程式
#include <ShiftLCD.h>
// initialize the library with the numbers of the interface pins
ShiftLCD lcd(2, 4, 3);
void setup() {
// set up the LCD's number of rows and columns:
lcd.begin(16, 2);
// Print a message to the LCD.
lcd.print("Hello, World!");
}
void loop() {
// set the cursor to column 0, line 1
lcd.setCursor(0, 1);
lcd.print(millis()/1000);
}
序列連接LCD 2/2
125

Arduino基礎IO控制