---
# System prepended metadata

title: Arduino講義：Keypad密碼鎖

---


---
tags: 單晶片
---
# Arduino講義：Keypad密碼鎖
## Intoduction of UART
* **UART** 全文為 **Universal Asynchronous Receiver/Transmitter** ，即**通用非同步收發傳輸器**。
* 通用非同步收發傳輸器是一種異步收發傳輸器
* 將資料由串列傳輸 (Serial communication) 與並列傳輸 (Parallel communication) 間作傳輸轉換。
![](http://wiki.csie.ncku.edu.tw/embedded/USART_DataTransmission.gif)
* **單工、半雙工與全雙工**

| 單工 | 半雙工 | 全雙工 |
| -------- | -------- | -------- |
|![](https://i.imgur.com/NkVAamw.jpg)|![](https://i.imgur.com/rICbdJp.jpg)  |![](https://i.imgur.com/RBbG5hN.jpg)|
|只支持信號在一個方向上傳輸(正向或反向)，任何時候不能改變訊號的方向。 EX:計算機和印表機之間的通信、B.B.Call。 | 允許信號在兩個方向上傳輸，但同一時間只允許信號在一個信道上單向傳輸。EX:傳統的對講機。 |允許數據同時在兩個方向上傳輸，即有兩個信道，因此允許同時進行雙向傳輸。 EX:電話、手機、RS232。 |
* 原文網址：https://kknews.cc/zh-tw/other/y2av3rj.html 
* **串列 v.s 並列**
  * 串列
  ![](https://i.imgur.com/iR4wqGW.jpg)
    * 一次傳送一個 bit，傳輸速率較慢、成本較低、可遠距離傳輸。
    * EX :滑鼠、鍵盤、電腦網路傳輸、RS-232 介面。
  * 並列
  ![](https://i.imgur.com/WqHNHVN.jpg)
    * 一次傳送多個 bit，傳輸速率快、成本高、僅限短距離使用。
    * EX :25Pin D-Type印表機。

* 注意:並列傳輸的線路較多，但傳輸速度不一定比較快(因為接收端要同時將傳進來的資料整合及排列，虛耗額外的位元及處理時間)
* **非同步 (Asynchronous) v.s 同步 (Synchronous)**
  * 非同步
  ![](https://i.imgur.com/gvCSISx.jpg)

    * 雙方有各自的時脈， 在傳送資料時插入額外資訊，表示資料起始、結束。優點是設定時間短、硬體成本低、機器時脈不同也能傳資料，缺點是單次傳輸的資料量較少。
    * EX : RS-232 (實現方式簡單低廉)、 RS-422 (較長距離的傳輸)、RS-485 (較多的裝置連接數目)。
  * 同步
  ![](https://i.imgur.com/cDlmMqx.jpg)

    * 雙方共用時脈(一次只做一件事)，額外提供時脈訊號，使兩端機器在溝通時能夠藉此同步收發資料。比起非同步傳輸，同步傳輸不需要 start/stop bit ，因此能夠一次傳較多的資料。
    * EX : I2C 、 SPI 。
* **UART**
  * 全雙工
  * 串列
  * 非同步
* 由2個獨立的接收 (RX) 、發送 (TX) 緩衝器構成，可同時發送和接收資料。
* 若 baud 為 9600 (bits/sec)，表示每秒可以傳 960 Bytes 的資料量。
* UART 傳送1 Byte (=8 bits)資料，加上頭尾共為10 bits。

 $$\frac{9600(bits)}{startbit(1 bits)+data(8 bits)+stop bit(1 bits)}= 960Bytes$$
 
[參考資料](https://zh.wikipedia.org/wiki/%E6%B3%A2%E7%89%B9%E7%8E%87)


## UART Protocol
![](https://i.imgur.com/EFrYOMa.png)
* 每個符號由三種資料共10個位元所組成，共分為：
    1. 起始位元 (Start Bit)
    2. 資料內容 (Data)
    3. 停止位元 (Stop Bit)
* 每個資料在傳送前都會有一個低電位的起始位 (start bit) ；資料傳完之後會接著一組停止位元 (stop bit)。
* 因此，若假設資料長度為 8bits，加上頭尾，每傳 1byte 至少需要 10bits。
:::info
在起始位 (start bit) 期間，資料發送端 (TX) 處於低電位；在停止位 (stop bit) 期間，資料發送端 (TX) 處於高電位。
:::
* [UART歷史](http://makerpro.cc/2016/04/understand-what-is-uart/)
* USART_BaudRate:

    * **Baud** 指的是有效數據信號調製載波的速率，**1鮑即指每秒傳輸1個符號**，而通過不同的調製方式，可以在一個碼元符號上負載多個bit位信息。
    * Asynchronous Normal Mode: $$Baud = \frac{f_{osc}}{16\times (UBRRn+1) }$$
    $$UBRR = \frac{f_{OSC}}{16\times baud } – 1$$
    * **Baud(bits/sec)** ： Baud rate 
    * **f~OSC~** ： System oscillator clock frequency
    * **UBRRn** ： Contents of the UBRRnH and UBRRnL Registers(用來設定 Baud Rate )。![](https://i.imgur.com/Xgarr18.jpg)
     
     


---
## UART register description
   * **Receive buffer** : 只能讀出不能寫入。
   * **Transmitter buffer** :只能寫入不能讀出。
   * **Interrupt Enable Register** : CPU寫入暫存器告訴UART何時中斷。
### UCSR0A(USART Control and Status Register 0 A)
![](https://i.imgur.com/DSOuooD.png)
* 它是一個暫存器，用於指示串行通信的控制和狀態。
* **RXC0** ( USART Receive Complete ) : 當**接收緩衝區**中存在未讀取的數據時，旗標設為1。用來知道何時能收到一個位元組。
* **TXC0**( USART Transmit Complete ) : 當**發送緩衝區**中發送數據時，**TXC0**（ USART 發送完成 ）變為1。
* **UDRE0** ( USART Data Register Empty ) : 當數據可寫入**傳輸緩衝區**時，**UDRE0**（USART數據暫存器為空）變為1。
### UCSR0B(USART Control and Status Register 0 B)
![](https://i.imgur.com/H73A9Qc.png)
* 它同樣是一個暫存器，用於指示串行通信的控制和狀態。
* **UCSR0B** 暫存器比較重要的是 **RXEN0** 和 **TXEN0**，這兩個位元用來啟用接收器 (receiver) 和發射器 (transmitter)，一般來說，我們會啟用這兩個元，可以用來開啟傳送、接收的位元。
* **UDRIE0** (USART Data Register Empty Interrupt Enable 0) : 決定要不要啟用中斷的位元。如果 **UDRIE0** 設置為 1，則允許UDRIE0標誌中斷。
### UDR0(USART I/O Data Register 0)
![](https://i.imgur.com/4BfEyf4.png)
* 它是用來存放資料的暫存器。
* **TXB** 和 **RXB** 具有相同的 I/O address (共用UDR0)。
* 當寫入資料到 **UDR0** 時，資料會寫入**TXB register**。
* 當要讀取 **UDR0** 的內容時，實際上是從 **RXB register** 讀取內容。


---

## Bluetooth 

* 藍芽模組 HC-05，使用 UART 介面與 Ardunio 溝通。
* 藍芽模組也可以視為一塊 MCU 並且可以透過 UART 介面進行設定。
* 設定方式:
  * 透過 USB to UART 轉換電路 ，從電腦開啟 Serial Port 做寫入動作。
  * 利用 Ardunio uno 開發板本身就有的 IC 來做轉換即可寫入 AT 指令。
* 藍芽設定接線方式
  * **同時按住紅框鈕及接上 5v 即可進入 AT 模式。** 
   ![](https://i.imgur.com/K11ITRH.png)
  * 接線:
    | Arduino  | 藍芽模組  | 備註 |
    | -------- | -------- | -------- |
    | 5V       | VCC      |注意電源不可接錯 |
    | GND      | GND      |注意電源不可接錯 |
    | RXD(pin0)| TXD      |         |
    | TXD(pin1)| RXD      |      |
    
    ![](https://i.imgur.com/pDl8ZEn.png)
    ![](https://i.imgur.com/IazhLIr.png)

    *  程式碼:
  ```c++=
  #include  <SoftwareSerial.h>
  SoftwareSerial BTSerial(10, 11); // RX 、 TX
  void setup()
   {
    Serial.begin(9600);
    BTSerial.begin(38400);  // HC-05 default speed in AT command more
   }
  void loop()
   {
  // Keep reading from HC-05 and send to Arduino Serial Monitor
  if (BTSerial.available())
    Serial.write(BTSerial.read());
  // Keep reading from Arduino Serial Monitor and send to HC-05
  if (Serial.available())
     BTSerial.write(Serial.read());
     }
  ```


* HC-05 AT 指令設定
  * 打開 Serial Port。
  * Serial Monitor 的鮑率選**9600**，另外一個選項要選 **NL&CR**，即可下 AT 指令。
  * 輸入 AT 指令第一次會出現 ERROR:(0)，第二次輸入 AT 出現 OK ，即可進入 AT 模式。

  
  ![](https://i.imgur.com/9zBsLA4.jpg)



  * **指令查詢** :
     - **查詢 Baud rate:**
       AT+UART?
       
     - **查詢 address:**
       AT+ADDR?
       
     - **查名字:**
       AT+NAME?
       
     - **查模式:**
       AT+ROLE?

  * **設定名稱 ：** 
    AT + NAME=XXXX 
  * **設定密碼 ：** 
    AT + PSWD=XXXX 
  * **設定模式 ：** 
    AT + ROLE=1/0 
  * **設定 Baud Rate (bit/sec) ：** (若設定為9600)
    AT + UART=9600,0,0  (鮑率 , 停止位元 , 同位位元)
* 其他參數設定可以參考 [HC-05	Datasheet](http://www.techbitar.com/uploads/2/0/3/1/20316977/hc-05_at_commands.pdf)
   
* 利用 Android 手機下載“Bluetooth Terminal”。![](https://i.imgur.com/oDo5zqU.jpg)
* 進入藍芽設定介面，按掃描裝置，找尋自己的的藍芽名稱。
* 輸入密碼(若無設定，預設為1234)。
* 開啟 app ，選定裝置後按下 connect 即可連線。
* <font color="red">成功連線時，藍芽模組上的警示燈呈快閃兩次循環。</font>
:::info
藍芽燈狀態:
  1. 不停閃爍:正常模式/等待連接模式
  2. 2秒亮2秒滅: AT 模式/配置模式
  3. 每秒閃爍2次:連接成功
:::

---



# Lab1:
  ### 藍芽實作
  * 實驗目的：學習使用藍芽控制。
  * 實驗目標：透過手機藍芽來控制led明滅燈。
  * 程式碼:
  ![](https://i.imgur.com/3wnIBv4.png)




  
  
  * 結果:
  <iframe width="800" height="600" src="https://www.youtube.com/embed/qLwyM35YIow" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>
  
# Lab2:
  ### 藍芽實作
  * 實驗目的:練習藍芽控制<font color="red">(請用delay()以外的方式執行)</font>
  * 實驗目標:透過手機藍芽控制led跑馬燈的速度
  (按1每秒閃一顆;按2每0.75秒閃一顆;按3每0.5秒閃一顆;按4每0.25秒閃一顆)
  * 結果:
  <iframe width="800" height="600" src="https://www.youtube.com/embed/m2m4Vx-d5w0" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>


# Lab3:
### 密碼鎖實作
  

  * [Password Library](https://drive.google.com/open?id=1oM_e01neNDaTDAonkNs00_GTtC1ygflV)

  * 實驗目的：學習使用Keypad及序列埠視窗。
  * 實驗目標：使用Keypad來輸入4位數密碼(如:1234)，輸入正確即印出Unlock!，錯誤即印出Wrong passwords!。
  * 程式碼:
    ![](https://i.imgur.com/OYH56xc.png)



  
# Lab4:
### 密碼鎖實作
  * 實驗目的：學習使用 Keypad 及序列埠視窗。
  * 實驗目標：呈上題，增加可以修改密碼及 reset (若密碼輸錯，可重新輸入密碼)的功能。
  * 結果:![](https://i.imgur.com/V2BIuJ3.png)





# 加分題:
### 密碼鎖實作
  * 實驗目的：學習使用 Keypad 實現終極密碼。
  * 實驗目標：使用keypad輸入一個三位數字，猜測一個介於100和999之間的數字。
  * 結果:(hint:產生終極密碼請使用random函式)
  ![](https://i.imgur.com/NO3MCVj.png)

  
 ## 課後問題 (3個)
:::info
* **Q1.** 請說明非同步傳輸中的"RS-232","RS-422"以及"RS-485"，並討論這三者的差別為何?
* **Q2.** 請說明 **HC-05** 作為 **master** 以及 **slave** 的功用是什麼?
* **Q3.** 下方為Password.cpp，請為其做完整的註解。
```c=
#include "Password.h"

//construct object in memory, set all variables
Password::Password(char* pass){
	set( pass );
	reset();
}

//set the password
void Password::set(char* pass){
	target = pass;
}

//evaluate a string, is it equal to the password?
bool Password::is(char* pass){ 
	byte i=0;
	while (*pass && i<MAX_PASSWORD_LENGTH){
		guess[i] = pass[i];
		i++;
	}
	return evaluate();
}

//append a char to the guessed password
bool Password::append(char character){ 
	if (currentIndex+1==MAX_PASSWORD_LENGTH){
		return false;
	}else{
		guess[currentIndex++] = character;
		guess[currentIndex] = STRING_TERMINATOR; //ensure a valid c string
	}
	return true;
}

//reset the guessed password, one can guess again
void Password::reset(){ 
	currentIndex = 0;
	guess[currentIndex] = STRING_TERMINATOR;
}

//is the current guessed password equal to the target password?
bool Password::evaluate(){ 
	char pass = target[0];
	char guessed = guess[0];
	for (byte i=1; i<MAX_PASSWORD_LENGTH; i++){
		
		//check if guessed char is equal to the password char
		if (pass==STRING_TERMINATOR && guessed==STRING_TERMINATOR){
			return true; //both strings ended and all previous characters are equal 
		}else if (pass!=guessed || pass==STRING_TERMINATOR || guessed==STRING_TERMINATOR){
			return false; //difference OR end of string has been reached
		}
		
		//read next char
		pass = target[i];
		guessed = guess[i];
	}
	return false; //a 'true' condition has not been met
}

bool Password::check(){
	int i=-1;
	if(strlen(target)==strlen(guess)){
		do{
			i++;
			if(target[i]>guess[i]) return 1;
			else if(target[i]<guess[i]) return 0;
		}while(target[i]==guess[i]);
	}
	else if(strlen(target)>strlen(guess)) return 1;
	else if(strlen(target)<strlen(guess)) return 0;
}

```

:::