---
tags: 單晶片上課講義
---
# Arduino講義: Environment與跑馬燈&多工七段顯示器與掃描鍵盤
# Install the Arduino
* 至Arduino官方網站下載開發環境: (https://www.arduino.cc/en/Main/Software)
* 開起「裝置管理員」,將 Arduino 接上,看一下是否有新增 USB 序列裝置(COM6),**不一定為 COM6**。
![](https://i.imgur.com/7n0TLcm.png)
* **假如「USB序列裝置」出現無法辨識的裝置:
方法一、按滑鼠右鍵,選擇「更新驅動程式」,並點選「自動搜尋更新的驅動程式軟體」,可以排除問題。
方法二、按滑鼠右鍵,選擇「更新驅動程式」,並點選「瀏覽電腦上的驅動程式軟體」,瀏覽下載Arduino的地方(arduino-1.8.8),找到drivers檔,點選並安裝。**![](https://i.imgur.com/SSvHWRm.png)
**方法三、搜尋COM port安裝檔,下載後執行 https://sparks.gogo.co.nz/ch340.html**
![](https://i.imgur.com/sWmkzdc.jpg)
* 將檔案開啟
![](https://i.imgur.com/Dwc2efw.png)
* 按下工具→序列埠,同時將arduino接上,選擇 COM6,即可以使用。
![](https://i.imgur.com/BPaazpM.png)
* 在「開發板」的部分記得確認是**Arduino/Genuino Uno**,否則可能會發生無法預期的錯誤。
![](https://i.imgur.com/Z2JcGLV.png)
## Arduino Common Function
**1.setup()**
設定程式參數,如:指定接腳的輸入輸出狀態,setup()裡的程式碼只會執行一次。
**2.loop()**
在loop()函式中的程式碼將會不停地重複執行,直到電源關閉為止。
![](https://i.imgur.com/bJVIF0x.png)
**3.pinMode(pin,mode)**
用於設定接腳模式,該函數無返回值,pin代表所要配置的接腳,mode代表設置的模式-INPUT或OUTPUT。
Ex:
```C++=
pinMode(13,OUTPUT)//將第13腳設定成「輸出」模式
```
**4.digitalWrite(pin,value)**
函數有兩個參數 digitalWrite(pin 接腳,電壓值), 電壓值為HIGH(高電位)與LOW(低電位)。
Ex:
```C++=
digitalWrite(13,HIGH)//第13腳位為輸出「高電位」
```
**5.digitalRead(pin)**
在接腳為輸入的情況下,可以獲取接腳的電壓情況—HIGH或LOW。
---
> ## Introduction of GPIO (General Purpose Input Output)
![](https://i.imgur.com/ukpB4Ih.png)
>通用輸入/輸出,每個 GPIO 端口可透過軟件分別配置成 INPUT 或者 OUTPUT ,其接腳可以供使用者由程式控制自由使用。
>* **Input mode:** MCU 透過 GPIO 腳從外面收資料/信號,可以進行外接感測器(溫度、紅外線感測器等)狀態、高低電位等資訊的獲取。
>* **Output mode:** MCU 透過 GPIO 腳將資料/信號送出,可用於控制LED、蜂鳴器及伺服馬達…等。
>* GPIO 端口可以當 I2C(**LCD 16x2**)、SPI (10~13)、UART(**Bluetooth**)…等多種用途,也能作為 IRQ (中斷要求)(2、3)的信號。
---
**6.delay()**
設定程式運行停止時間長度,單位為ms,故delay(1000)為延遲1秒。
**7.millis()**
millis()函數會回傳Arduino從執行程式碼開始至目前為止的milliseconds數值,其資料型態為unsigned long,該數值大約在50天之後會溢位(overflow),屆時會從0開始重新計數。
![](https://i.imgur.com/Iq2nZV6.png)
以上方程式碼為例,每一秒印出millis()的回傳值,利用delay(1000)產生1000毫秒的延遲。
然而,相鄰的兩個數值的差值可能並未完全為1000,則是Serial.print()印出資料需要的時間差。
## **Serial Library**
**1. Serial.begin()**
開啟Serial Port並設定鮑率(baud rate)
Ex:
``` C++=
Serial.begin(9600);//開啟Serial Port,且通訊速率為9600bps(Bits Per Second)
```
**2. Serial.print()**
將字串透過TX腳位傳遞出去,並且顯示在Serial Monitor中
**3. Serial.println()**
傳送資料到外部電腦並切換至下一行
![](https://i.imgur.com/uP3t3at.png)
**4. Serial.write()**
以二進位碼(byte)輸出
![](https://i.imgur.com/iIpMaef.png)
**5. Serial.read()**
讀取進來的第一個位元組 (first incoming byte)。
**6. Serial.available()**
取得 Serial Port 可讀取的資料位元組數目 (number of bytes),如果 Serial port 有資料進來,Serial.available() 會回傳大於 0 的數值。
---
通常我們會使用Serial.available()來檢查是否有資料進來,在使用Serial.read()把資料讀取出來放到變數後供後續使用。例如:
```c++=
int incomingByte = 0; // 用來儲存收進來的 data byte
void setup() {
Serial.begin(9600);
Serial.println("Hello");
}
void loop() {
// 檢查是否有資料可供讀取
if (Serial.available() > 0) {
// 讀取進來的 byte
incomingByte = Serial.read();
// 印出收到的資料
Serial.print("data received: ");
Serial.print(incomingByte, DEC);
Serial.print(", ");
Serial.print(incomingByte, HEX);
Serial.println(" (HEX)");
}
```
---
**<<Note>>**
Arduino其他相關語法請參考:[Arduino語言手冊](https://h2maker.wordpress.com/arduino/)
## **Arduino講義:跑馬燈 + 按鍵 + 多工七段顯示器 + 4 x 4鍵盤**
## **1.跑馬燈(Electronic Marquee)**
### 模組說明
![](https://i.imgur.com/cxsQfH9.png)
**<<Note>>**
<font color = "red">需要限流電阻(大概 220Ω 或 330Ω),使 LED 流進電流不超過20mA。</font>
## Arduino LED Blink
![](https://i.imgur.com/0LaJnpz.png)
> ### 程式說明
![](https://i.imgur.com/rNeIjTu.png)
## LAB 1-1
* 實驗目的:學習對Arduino的GPIO及LED基本控制方式。
* 實驗目標:設定10個GPIO來實現跑馬燈
![](https://i.imgur.com/buyuzPP.png)
* 實驗結果:
<iframe width="966" height="550" src="https://www.youtube.com/embed/uvPa0gkWV3s" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
## LAB 1-2
* 實驗目的:學習對Arduino的GPIO及LED基本控制方式。
* 實驗目標:由左到右,輪流點亮每一個LED燈(10顆),一次只點亮一顆,再從右往左點亮。接著,再以隨機的方式點亮五顆燈之後,不斷循環。
**<hint>** random函數
* 實驗結果
<iframe width="966" height="550" src="https://www.youtube.com/embed/3nzcmYLseY4" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
## 2.按鈕(Button)
![](https://i.imgur.com/jzfqQzY.png)
> ### 開關的接法
![](https://i.imgur.com/dUD0QDi.png)
若未按下開關,Arduino的接腳沒接地,但也沒有接到高電位。輸入的訊號會在0到1之間飄移,造成浮動訊號,Arduino就無法正確判斷輸入值。
![](https://i.imgur.com/oh3j52w.png)
若開關沒有被按下,Pin2將會透過10kΩ接地,讀取到低電位(LOW);按下開關時,5V電源將流入Pin2,產生高電位(HIGH)。
![](https://i.imgur.com/RHULvQZ.png)
若將電阻接到電源,則此電阻稱為「**上拉(pull-up)電阻**」(在開關接通時,輸入為「低電位」)。
> ### 使用Arduino內部的上拉電阻
Arduino內部的pin腳考量到拿來做數位輸入,所以有內建上拉電阻。
```C++=
pinMode(pin,INPUT_PULLUP);
```
## LAB 2-1 Button & LED
* 實驗目的:知道上拉電阻與下拉電阻的接法差別,並用Button控制LED
* 實驗目標:按上拉電阻的Button時,LED向左一顆亮;按下拉電阻的Button時,LED向右邊一顆亮。
* 程式碼:
```c++=
int led[4]={8,9,10,11};
int sw_up=2;
int sw_down=3;
void setup() {
for(int i=0;i<5;i++){
pinMode(led[i],OUTPUT);
digitalWrite(led[i],LOW);
}
digitalWrite(led[3],HIGH);
pinMode(sw_up,INPUT_PULLUP);
pinMode(sw_down,INPUT);
}
void loop() {
boolean swstate_up=digitalRead(sw_up);
boolean swstate_down=digitalRead(sw_down);
...
...
...
}
```
<iframe width="966" height="550" src="https://www.youtube.com/embed/_M4Q7sz1Rcc" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
### 彈跳問題
機械式開關在切換的過程中,訊號並非立即從1變成0或從0變成1,而是會經過如下圖一般有忽高忽低的情況。
雖然彈跳的時間很短暫,但arduino仍會讀取到其連續變化的開關訊號,而導致誤差。
![](https://i.imgur.com/wTXp74A.png)
> ### 消除彈跳(de-bouncing)方法
在發現訊號開始變化時先讀取,在經過一段時間後,若訊號仍為HIGH,則視為按下第二次按鈕。
## LAB 2-2 de-bouncing
* 實驗目的:解決Button彈跳問題
* 實驗目標:按一下開關點亮LED,再按一下開關熄滅LED
PS.請勿使用delay()函式。
* 程式碼:
![](https://i.imgur.com/nmwBKE6.png)
* 實驗結果:
<iframe width="966" height="550" src="https://www.youtube.com/embed/M1BagsM8tYg" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
# Arduino講義:多工七段顯示器與掃描鍵盤
## 3. 多工七段顯示器(Multiplexed Seven-Segment display)
> ### 七段顯示器
![](https://i.imgur.com/CL8AjzP.png)
![](https://i.imgur.com/jCHvCki.png)
**<<Note>>**
**注意!!需額外增加限流電阻,否則內部可能會燒毀!!**
![](https://i.imgur.com/bg7CQ4b.png)
依據電源連接方式的不同,七段顯示器可以分成「**共陽極**」與「**共陰極**」兩種:
共陰極代表所有的LED接地端都相連,故LED的另一端接「高電位」就會發光;相反地,共陽極則是輸入「低電位」來發光。
| 十進位數 | a | b |c|d|e|f|g|
| - | - | - | - | - | - | - | - |
|0|1|1|1|1|1|1|0|
|1|0|1|1|0|0|0|0|
|2|1|1|0|1|1|0|1|
|3|1|1|1|1|0|0|1|
|4|0|1|1|0|0|1|1|
|5|1|0|1|1|0|1|1|
|6|1|0|1|1|1|1|1|
|7|1|1|1|0|0|0|0|
|8|1|1|1|1|1|1|1|
|9|1|1|1|1|0|1|1|
> ### 多工七段顯示器
![](https://i.imgur.com/k4HT6lO.png)
![](https://i.imgur.com/NTsPOqR.png)
![](https://i.imgur.com/d4zoQH0.png)
* 實際接腳位置:
| 多工七段顯示器 | Arduino |
| -------- | -------- |
| 0 |Pin10|
| 1 |Pin11|
| 2 |Pin12|
| 3 |Pin13|
| a |Pin2 |
| b |Pin3 |
| c |Pin4 |
| d |Pin5 |
| e |Pin6 |
| f |Pin7 |
| g |Pin8 |
| dp |Pin9|
## LAB 3-1 多工七段顯示器
* 實驗目的:學習對Arduino的GPIO與多工七段顯示器掃描基本控制方式
* 實驗目標:控制4個七段顯示器顯示"**1234**"
* 程式碼:
```c++=
int seg_com[4]={10,11,12,13};
int seg_data[10][8]={{1,1,1,1,1,1,0,0},//0
{0,1,1,0,0,0,0,0},//1
{1,1,0,1,1,0,1,0},//2
{1,1,1,1,0,0,1,0},//3
{0,1,1,0,0,1,1,0},//4
{1,0,1,1,0,1,1,0},//5
{1,0,1,1,1,1,1,0},//6
{1,1,1,0,0,0,0,0},//7
{1,1,1,1,1,1,1,0},//8
{1,1,1,0,0,1,1,0},//9
};
int number=1234;
int disp[4]={0,0,0,0};
int i=0;
int j=0;
void setup() {
for(int i=2;i<10;i++){
pinMode(i,OUTPUT);
digitalWrite(i,LOW);
}
for(int i=10;i<14;i++){
pinMode(i,OUTPUT);
digitalWrite(i,HIGH);
}
}
void loop() {
number_transfer(number);
for(i=0;i<4;i++){ //個 十 百 千
digitalWrite(seg_com[i],LOW);
seg_drive(disp[i]);
delay(5);
digitalWrite(seg_com[i],HIGH);
}
}
void number_transfer(int num ){
//將四位數的number拆成獨立的四個數字,存入陣列disp[]中
}
void seg_drive(int number){
//將字元變數從SEG_DATA[][]找到相對應的位置,並寫入a-g中
}
```
* 實驗結果:
![](https://i.imgur.com/KO0ZAdd.jpg)
## (Bonus)LAB 3-2 多工七段顯示器數數
* 實驗目的:學習對Arduino的GPIO與多工七段顯示器掃描基本控制方式
* 實驗目標:控制4個七段顯示器每隔一段時間會自動計數加一
* 實驗結果:
<iframe width="966" height="550" src="https://www.youtube.com/embed/DvoNgDxAOhQ" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
## 4. 4x4 鍵盤(4x4 Keypad)
![](https://i.imgur.com/9LfIBf6.png)
> ### 按鈕偵測與掃描原理(1x3簡化版)
---
![](https://i.imgur.com/1oR4N7l.png)
假設開關的「行1」~「行3」輸入端全部都輸出高電位,則無論開關是否被按下,Arduino都將會接收到**高電位**。因此,為了偵測到使用者按下的開關鍵,撰寫程式時必須依序將「行1」~「行3」設置成**低電位**來檢測。
* 輪到「行1」腳被掃描時,「行1」腳輸入低電位,但A開關沒有被按下,所以Arduino的微控腳接收到高電位(1)
![](https://i.imgur.com/n9dBBz0.png)
* 在掃描到「行2」時,「行2」腳輸入低電位,且Arduino的微控腳也接收到低電位(0),因此可以判斷出「行2」的B開關被按下。
![](https://i.imgur.com/lTn2icb.png)
* 輪到「行3」腳被掃描時,「行3」腳輸入低電位,但C開關沒有被按下,所以Arduino的微控腳接收到高電位(1)
![](https://i.imgur.com/crZsTYq.png)
---
實際上的使用需要運用到**雙重迴圈(4x4)**,才能夠分批掃描到每一列:
![](https://i.imgur.com/8YSHIj2.png)
> ### 實際腳位配置
| 4x4 Keypad | Arduino |
| -------- | -------- |
| 1(ROW1) | Pin A0 |
| 2(ROW2) | Pin A1 |
| 3(ROW3) | Pin A2 |
| 4(ROW4) | Pin A3 |
| 5(COL1) | Pin 2 |
| 6(COL2) | Pin 3 |
| 7(COL3) | Pin 4 |
| 8(COL4) | Pin 5 |
## LAB 4-1 掃描式鍵盤
* 實作目的:學習如何使用掃描式鍵盤
* 實作目標:<font color = "red">**在不使用<Keypad.h>的情況**</font>,以Keypad鍵入資料,將資料透過UART傳輸至內建的Serial Monitor
* 程式碼:
![](https://i.imgur.com/1CW6RBF.png)
* 實作結果:
<iframe width="966" height="543" src="https://www.youtube.com/embed/tTJy4KFk67g" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
> ### 匯入Keypad函式庫
Keypad程式庫的運作方式與LAB 4-1 大致相同,且多了除彈跳(de-bouncing)的部分。LAB 4-1有助於了解掃瞄鍵盤的原理,實際使用上仍是Keypad程式庫為主。
Keypad Library: [Download](https://www.arduinolibraries.info/libraries/keypad)
![](https://i.imgur.com/aIS1wcX.png)
![](https://i.imgur.com/z7ufiOA.png)
使用Keypad函式庫,程式碼需定義按鍵模組的**行(col)**、**列(row)**、**連接Arduino的腳位**以及**按鍵所代表的字元**。
![](https://i.imgur.com/MrWNGmx.png)
```c++=
#include <Keypad.h> //引用Keypad函式庫
#define KEY_ROWS 4 //按鍵模組的列數
#define KEY_COLS 4 //按鍵模組的行數
const byte colPins[4] = {2, 3, 4, 5};
const byte rowPins[4] = {A0, A1, A2, A3};
const char keymap[KEY_ROWS][KEY_COLS] = {
{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'*','0','#','D'}
};
Keypad myKeypad = Keypad(makeKeymap(keymap),rowPins,colPins,KEY_ROWS,KEY_COLS);
void setup(){
Serial.begin(9600);
}
void loop(){
//透過Keypad函式庫裡的getkey()方法讀取按鍵的字元
char key = myKeypad.getKey();
if(key){ //若有按鍵按下則顯示按下的字元
Serial.println(key);
}
}
```
## LAB 4-2 Keypad 輸出字串
* 實驗目的:學習如何使用掃描式鍵盤及其應用
* 實驗目標:利用Keypad輸入按鍵,並且將值暫存在buffer中,在按'#'後會將之前按過的字元依序印到Serial Monitor上。
* 實驗結果:
<iframe width="966" height="543" src="https://www.youtube.com/embed/jHz5F3q41Y0" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
## (Bonus) LAB 4-3 碼錶
* 實驗目的:學習如何使用掃描式鍵盤與七段顯示器之結合應用
* 實驗目標:利用Keypad輸入按鍵,按'A'會進入計時模式,按'B'則會進入倒數計時模式,按'C'為開始,按'D'為暫停,按'*'為重新開始,按'#'為離開並進入選擇模式。(註:進入倒數計時模式時須先輸入欲倒數秒數)
建議pin腳 :
| 多工七段顯示器 | Arduino | 4x4 Keypad|Arduino|
| -------- | -------- |--------|--------|
| 0 |Pin10|Row1|A0|
| 1 |Pin11|Row2|A1|
| 2 |Pin12|Row3|A2|
| a |Pin2 |Row4|A3|
| b |Pin3 |Col1|13|
| c |Pin4 |Col2|9|
| d |Pin5 |Col3|A4|
| e |Pin6 |Col4|A5|
| f |Pin7 |
| g |Pin8 |
註:若要使用 Pin 0 & 1 也可,但就不能使用Serial.print()等函式
* 實驗結果:
<iframe width="966" height="543" src="https://www.youtube.com/embed/VzLXtCO996c" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
:::info
## 課後習題
1. Arduino微處理器不僅包含MCU,還內建記憶體、類比/數位訊號轉換器以及周邊控制介面,相當於將完整的電腦功能塞入一個矽晶片中,所採用的微處理器是ATmega328P。根據下圖,標示在Arduino UNO板上的digital 與 analog I/O的位置、數量以及相關用途(如:通訊、中斷...)。
![](https://i.imgur.com/mRo7MTS.png)
2. (1)描述機械式開關的彈跳現象
(2)在ATmeg328p微控器的數位接腳有內建上拉電阻,預設沒有啟用,該上拉電阻值介於20kΩ至50kΩ之間;而一般外接10kΩ的上拉電阻,甚至在要求高反應速率的電子訊號切換時會使用4.7kΩ或是1kΩ的上拉電阻。試問:上拉電阻值的高低對於處理雜訊干擾的能力之間的關係?
3. 描述多工七段顯示器及鍵盤掃描的工作原理
4. 心得
:::
:::success
## 作業繳交格式
**W2結報_第XX組.zip**
壓縮檔裡包含:
1.W(週數)結報.pdf
2.資料夾:W(週數)
Lab1-1.ino
Lab1-2.ino
...
:::