---
tags: 單晶片助教
---
# [6] Arduino講義:超音波&步進馬達(TA版)
[ToC]
## 超音波感測器(Ultrasonic sensor)
* 超音波模組工作原理:

* 觸發 : 採用I/O觸發測距,給至少為 <font color="red">10us</font> 的高電位信號。
* 發射 : 模組自動發送 8 個 40KHz 的方波,自動檢測是否有信號返回。
* 接收 : 有信號返回,通過模組之 I/O 輸出高電位,<font color="red">高電位持續的時間</font>就是超聲波 從發射到返回的時間。

* 距離計算 = (高電位時間 / 2) * 聲速 。
* 讀取高電位時間 : 使用 <font color="red">pulseIn( )</font> 此Function,單位為microsecond(µs)。
* Reference: [Arduino pulseln()](https://www.arduino.cc/en/Reference.PulseIn)
* 聲速 = 331.5 + 0.607 * t(攝氏溫度)。
Ex : 溫度為攝氏 20 度,則聲速為 331.5 + 0.607 * 20 = 343.64 m/s。
* 將聲速還算成 cm/µs => 343.64 * 100 / 1000000 = 0.034364 cm/µs。
* 超音波模組規格與腳位 :
* 電源需求 : DC 5V / 2mA
* 輸出電位( 1/ 0):5V/ 0V
* 精度:3mm
* <font color="red">距離範圍:2 ~ 450cm</font>
* 有效的角度:<15℃

* 超音波使用須知
* 不可少於2公分

* 每次訊號間隔不可太短

* 待測物注意反射角度

* 待測物圓柱體時反射角度較廣

### Lab1-1 - 超聲波測距器+7段顯示
#### 實作說明:
* 實作目的 : 學習使用超聲波模組以及7段顯示器之應用。
* 實作範例 : 使用超聲波模組搭配 LCD 顯示器與7段顯示器,將超音波感測器讀取到之數值換算成距離顯示在7段顯示器上。顯示整數需能支援百位數,小數則需顯示到小數點第一位。
* Ex:測得距離=20.3cm,7段顯示器顯示"020.3"。
* Ex:測得距離=115cm,7段顯示器顯示"115.0"。
* <font color="red">Hint : round()函式</font>
* 實作腳位配置 :
| HC-SR04 | Arduino | LCM 1602 |Arduino|
| -------- | -------- | -------- | -------- |
| Vcc | 5V | GND | GND |
| Trig | Pin12(可自行決定) | Vcc | 5V |
| Echo | Pin11(可自行決定) | SDA | A4 |
| Gnd | GND | SCL | A5 |
* 實作影片 :
{%youtube Oac_2GWuUnU %}
```c=
const int SEG_COM[4] = {A0,A1,A2,A3}; //控制線
const int SEG_data[10][7] = {{1, 1, 1, 1, 1, 1, 0}, //"0" //資料線
{0, 1, 1, 0, 0, 0, 0}, //"1"
{1, 1, 0, 1, 1, 0, 1}, //"2"
{1, 1, 1, 1, 0, 0, 1}, //"3"
{0, 1, 1, 0, 0, 1, 1}, //"4"
{1, 0, 1, 1, 0, 1, 1}, //"5"
{1, 0, 1, 1, 1, 1, 1}, //"6"
{1, 1, 1, 0, 0, 0, 0}, //"7"
{1, 1, 1, 1, 1, 1, 1}, //"8"
{1, 1, 1, 0, 0, 1, 1}}; //"9"
int echoPin = 11; //Echo Pin
int trigPin = 12; //Trig Pin
float cm;
float duration;
float soundspeed=0.034;
void setup() {
Serial.begin (9600); // Serial Port begin
for(int i=2; i<=9; i++){
pinMode(i, OUTPUT);
digitalWrite(i, HIGH); //共陽極
}
for(int i=0; i<=3; i++){
pinMode(SEG_COM[i], OUTPUT);
digitalWrite(SEG_COM[i], HIGH); //共陽極
}
pinMode(trigPin, OUTPUT); // 定義輸入及輸出
pinMode(echoPin, INPUT);
}
void loop() {
// To do:給 Trig 高電位,持續 10微秒
duration = pulseIn(echoPin, HIGH); // 收到高電位時的時間
//To do:算出距離
//To do:顯示在7段顯示器
}
void SEG_Drive(int number){ //將字元變數從SEG_data[][]找到相對應的位置,並寫入a~g中
for(int i=0;i<=6;i++)
{
//To do:輸出至7段顯示器
}
}
```
### Lab1-2 - 測距控制LED燈閃爍
#### 實作說明:
* 實作目的 : 學習透過距離控制LED燈閃爍。
* [下載LCD_I2C模組程式庫](https://github.com/johnrickman/LiquidCrystal_I2C)
* 實作範例 : 使用超聲波模組搭配三科LED燈。
* 當物體距離 0~20 公分時,一號LED隨距離愈近閃爍越快,距離愈遠閃爍愈慢。
* 當物體距離 20~40 公分時,二號LED隨距離愈近閃爍越快,距離愈遠閃爍愈慢。
* 當物體距離 40~60 公分時,三號LED隨距離愈近閃爍越快,距離愈遠閃爍愈慢。
* 當物體距離 >60 公分時,三顆LED均熄滅。
* 實作影片 :
{%youtube 5c6yjdvmGk0 %}
```c=
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#define led1 3
#define led2 4
#define led3 5
int trigPin = 12;
int echoPin = 11;
LiquidCrystal_I2C lcd(0x27, 16, 2);
float duration;
int cm;
float soundspeed=0.034;
void setup() {
Serial.begin (9600);
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
pinMode(led1,OUTPUT);
digitalWrite(led1, LOW);
pinMode(led2,OUTPUT);
digitalWrite(led2, LOW);
pinMode(led3,OUTPUT);
digitalWrite(led3, LOW);
lcd.init();
lcd.backlight();
}
void loop() {
// ex.給 Trig 高電位,持續 10微秒
duration = pulseIn(echoPin, HIGH);
//To do : 算出距離
if(cm>0 && cm<=20)
{
//To do
}
else if(cm>20 && cm<=40)
{
//To do
}
else if(cm>40 && cm<=60)
{
//To do
}
else if(cm>60)
{
//To do
}
//To do : 顯示距離於lcd上
}
```
## 步進馬達(Stepping motor)
* 步進馬達工作原理:
由電流通過線圈激磁後,使得線圈產生磁場(電磁鐵)吸引中間轉子磁鐵轉動,所以若要控制馬達旋轉,需控制好線圈的激磁順序。
* <font color="red">紅色線</font>:電源線供給馬達電力。
* <font color="blue">藍色線</font>:線圈。
* <font color="pink">粉色線</font>:線圈。
* <font color="FFDD00">黃色線</font>:線圈。
* <font color="Orange">橘色線</font>:線圈。

* 步進馬達規格 :
* 額定電壓:5 VDC
* 相數:4
* 變速比:64/1 圈 (輸入/輸出)
( 1 : 9,2 : 32/11,3 : 22/9,4 : 27/8,5 : 24 )(齒輪比)

* 步進角度:5.625度
藉由以上數據可得知
輸出的轉速(度) = 主軸轉速(度) x 9/32 x 11/22 x 9/27 x 8/24 = 主軸轉速(度) x 1/64
假設馬達步進角為5.625度 x 1/64 = 0.087890625度
所以若要轉一圈,則需360/0.087890625 = 4096步
經過角度與步數的運算,馬達就可以依需求來做控制。
* 步進馬達控制方法 :
* 單相激磁(優點:省電,缺點:力矩小)

* 二相激磁(優點:力矩大,缺點:耗電)

* 一二相激磁(優點:省電,缺點:力矩小)

<font color="blue">hint</font> : 一二相與單相二相差異點為輸出所需的步數,假設一二相所需一圈為4096步,那單相與二相就只需2048步,由此可知,一二相可做到較精準的角度控制。
* ULN2003A驅動IC :

此IC特點在於,透過控制數位訊號來控制哪個輸出接腳要接地。
### Example
```c=
//單相激磁
int t= 10; //換相所需的時間
void setup() {
pinMode(7,OUTPUT);
pinMode(8,OUTPUT);
pinMode(9,OUTPUT);
pinMode(10,OUTPUT);
}
void loop() {
digitalWrite(7,1);
digitalWrite(8,0);
digitalWrite(9,0);
digitalWrite(10,0);
delay(t);
digitalWrite(7,0);
digitalWrite(8,1);
digitalWrite(9,0);
digitalWrite(10,0);
delay(t);
digitalWrite(7,0);
digitalWrite(8,0);
digitalWrite(9,1);
digitalWrite(10,0);
delay(t);
digitalWrite(7,0);
digitalWrite(8,0);
digitalWrite(9,0);
digitalWrite(10,1);
delay(t);
}
```
### Lab2-1 - 步進馬達角度控制
#### 實作說明:
* 實作目的 : 學習控制步進馬達轉動角度。
* 實作範例 : 使用步進馬達搭配 LCD 顯示器與按鈕。
按鈕A:按1下時,馬達逆轉90度;長按2秒以上,馬達逆轉720度。
按鈕B:按1下時,馬達順轉180度;長按2秒以上,馬達順轉135度。
LCD第一行顯示自己學號,第二行顯示"Steps : 步數"。
hint : 必須確實計算所需角度得步數
* 實作影片 :
{%youtube lKkT2FSfM8Q %}
```c=
//0.17578125
//8192 2048 1536 1024
//720 180 135 90
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);
int t = 1000;
int Count ;
int but[2] = {3, 4};
int state1[5] = {1,1,1,1,1};
int state2[5] = {1,1,1,1,1};
boolean a[] = {1, 1, 0, 0, 0, 0, 0, 1};
boolean b[] = {0, 1, 1, 1, 0, 0, 0, 0};
boolean c[] = {0, 0, 0, 1, 1, 1, 0, 0};
boolean d[] = {0, 0, 0, 0, 0, 1, 1, 1};
void setup() {
Serial.begin(9600);
lcd.init(); //初始化LCD
lcd.backlight(); //開啟背光
pinMode(7,OUTPUT);
pinMode(8,OUTPUT);
pinMode(9,OUTPUT);
pinMode(10,OUTPUT);
pinMode(but[0],INPUT_PULLUP);
pinMode(but[1],INPUT_PULLUP);
}
void loop() {
int IN1 = digitalRead(but[0]);
int IN2 = digitalRead(but[1]);
Count = 0;
if (state1[0] == 0 && state1[1] == 0 && state1[2] == 0 && state1[3] == 0 && state1[4] == 0 && IN1==1)
{
mode720();
}
else if (state1[4] == 0 && IN1==1)
{
mode90();
}
if (state2[0] == 0 && state2[1] == 0 && state2[2] == 0 && state2[3] == 0 && state2[4] == 0 && IN2==1)
{
mode135();
}
else if (state2[4] == 0 && IN2==1)
{
mode180();
}
delay(??); //To do:該怎麼delay才能達到計時2秒的效果?
for(int i=0;i<=3;i++)
{
state1[i] = state1[i + 1];
state2[i] = state2[i + 1];
}
state1[4] = IN1;
state2[4] = IN2;
}
void mode90()
{
for (int j = 0; j < 128 ; j++) {
for (int i = 0; i < 8 ; i++) {
digitalWrite(7, a[i]);
digitalWrite(8, b[i]);
digitalWrite(9, c[i]);
digitalWrite(10, d[i]);
delayMicroseconds(t);
Count++;
}
}
lcd.clear();
lcd.print("M16121051");
lcd.setCursor(0, 1);
lcd.print("Steps : ");
lcd.print(Count);
}
void mode135()
{
// To do
}
void mode180()
{
// To do
}
void mode720()
{
// To do
}
```
### Bonus - 超音波+按鈕控制步進馬達
#### 實作說明:
* 實作目的 : 學習更加進階之步進馬達控制。
* 實作範例 : 利用超音波量得距離控制步進馬達旋轉速度及方向。
* 預設馬達逆時針轉動,當按下按鈕時變順時針運轉,再按一次逆時針,以此類推。
* 物體距離愈遠馬達旋轉愈慢,距離愈近旋轉愈快。
* 需在LCD上第一列顯示clockwise或counterclockwise,第二列顯示距離(cm)。
* 參考影片 :
{%youtube 7LeSqDdeqcI %}
## 課後問題 (三題)
:::info
* Q1.詳述 超聲波模組感測原理。
* Q2.詳述 步進馬達動作原理。
* Q3.請列舉 3 個超音波感測器在現實生活中之應用。並詳述你列舉的應用如何使用超音波感測器收集到的資訊。
回答請勿直接複製上述講義內容!
:::
Arduino *1
超音波感測器 *1
步進馬達+ULN2003AN驅動板 *1
LCD *1
LED燈 *3
按鈕 *2
電阻10K歐姆 *2