• 沒有找到結果。

Arduino上課講義

N/A
N/A
Protected

Academic year: 2021

Share "Arduino上課講義"

Copied!
49
0
0

加載中.... (立即查看全文)

全文

(1)

泰山高中電子科陳致中老師 Arduino 上課講義分享 1. 先到http://arduino.cc/ 下載免費的 Arduino1.0.5 工具程式(目前已到 1.6.1 版本)

※ 僅一個檔案約 53MB,因為學校下載很慢,第一次上課前先自行下載到隨身碟備用。 ※ 每次上課先複製 Arduino 執行檔案到硬碟再安裝,勿從隨身碟直接安裝,因為會很慢。

(2)

2

(3)

註 1:Arduino 軟體安裝完畢後,插入 Arduino 主板,驅動程式會自動安裝,但須到控制台→裝置管理員, 務必查看 Arduino 主板被設定在 COM?,因為每台電腦均不同。

註 2:若驅動程式無法正常安裝,則在 Arduino 桌面的捷徑按右鍵→內容→開啟檔案位置,到驅動程式 drivers 資料夾執行dpinst-x86.exe,若還是不行有可能是 USB 供電不穩,請同時插入 5V 電源即可。

(4)

4 實驗 1:執行 Arduino 桌面的捷徑,File(檔案)→Examples(範例)→01Basic(基本)→Blink(閃爍),載 入現成的測試程式,以便確認 Arduino 主板的好壞,順便了解 Arduino 程式語言架構。 ※ 下載範例後尚無法燒錄,因為還要設定硬體相關資訊喔! ※ Arduino 工具程式安裝完畢後,其實已經有許多範例可以參考測試,真的很便民。 ※ Arduino 教學網站推薦http://coopermaa2nd.blogspot.tw/2011/05/arduino.html ※ 鄭聰賢老師教學網站https://sites.google.com/site/tssheegroup2011/zhu-ti-xue-xi/arduino

(5)

註 3:第一次使用需要到Tools(工具)→Serial Port(串列埠)去設定硬體的COM 為?(每台電腦均不同,需

到裝置管理員查詢),以及 Arduino 主板的硬體類型,方可進行燒寫。若裝置管理員可以看到,但 Tools 卻偵測不到,需解除安裝再拔除,然後插入重安裝,實際測試有時要好幾次才會成功?

李奧納多

(6)

6

註 4:Arduino 的燒錄動作稱為Uploading(上傳中),設定完畢即可按下『→』鍵上傳(Upload)燒錄。

若 Arduino 功能正常(啟用約需 10 秒才開始),在電源指示燈上方的 LED 會每間隔 1 秒進行閃爍。

※ 內部 Pin13 已經直接連接到該 LED,所以可以直接測試 Arduino 主板。

※ 亦可再另外並接 LED 於 Pin13 與 GND 測試之間,然後再改用其他 Pin 腳測試。 ※ 腳位若有標示『~』,表示可做PWM(Pulse Width Modulation 脈波寬度調變)的運用。

(7)

Arduino 程式架構介紹,很像 C 語言,/*……..*/中間為註解或直接用//表示註解,每句指令結束需用『分 號;』,若有多行區塊,須利用大括號{..…},在 VB 程式碼是不分大小寫,但 Arduino 程式和 C 語言都是 有區分大小寫,例如:內建常數就一定要大寫方可。 ※ 若想查詢某一指令說明,可利用http://arduino.cc/en/Reference/HomePage。 ※ setup( ) -初始化函式,程式啟動時僅被呼叫一次。 loop( ) -主迴圈函式,會不斷被執行。 名稱定義(或直接輸入) 宣告腳位為輸出/入 主程式,利用無窮迴圈 每延遲 1 秒改變輸出值

(8)

8  變數資料型態均需先宣告方可使用 http://www.86duino.com/?page_id=2255&lang=TW 常用指令線上查詢 結構  setup() 、 loop() 控制結構  if  if…else  for  switch case

 while 或 do… while

 break  continue  return  goto 更多程式結構語法  ; (分號)  { } (大括號)  // (單行註解)  /* */ (多行註解)  #define  #include 算術運算子  = (指派運算子)  + (加法運算子)  - (減法運算子)  * (乘法運算子)  / (除法運算子)  % (餘數運算子) 比較運算子  == (等於)  != (不等於) 變數 常量  HIGH | LOW  INPUT | OUTPUT | INPUT_PULLUP  true | false  整數常數  浮點常數 資料型別  void  boolean  char  unsigned char  byte  int  unsigned int  word  long  unsigned long  short  float  double  long double  string – 字元陣列  String – 物件  array 型別轉換  char()  byte()  int() 函式 數位 I/O 功能  pinMode()  digitalWrite()  digitalRead() 類比 I/O 功能  analogReference()  analogRead()  analogWrite() – PWM  analogReadResolution()  analogWriteResolution()  cpuTemperature() 進階 I/O 功能  tone()  noTone()  shiftOut()  shiftIn()  pulseIn() 時間  millis()  micros()  delay()  delayMicroseconds() 數學  min()  max()  abs()  constrain()  map()  pow()

(9)

 < (小於) 、 > (大於)  <= (小於等於) 、 >= (大於等於) 布林運算子  && (and)  || (or)  ! (not) 指標運算子  * 取值運算子  & 取址運算子 位元運算子  & (位元 and)  | (位元 or)  ^ (位元 xor)  ~ (位元 not)  << (位元左移運算)  >> (位元右移運算) 複合運算子  ++ (遞增運算子)  - - (遞減運算子)  += (複合加法運算)  -= (複合減法運算)  *= (複合乘法運算)  /= (複合除法運算)  &= (複合位元 and)  |= (複合位元 or)  word()  long()  float()  double() 作用範圍及修飾字  變數作用範圍  static  volatile  const 工具  sizeof()  sqrt() 三角函式  sin()  cos()  tan() 隨機數  randomSeed()  random() 位元及位元組操作  lowByte()  highByte()  bitRead()  bitWrite()  bitSet()  bitClear()  bit() 外部中斷  attachInterrupt()  detachInterrupt() 中斷  interrupts()  noInterrupts() 通訊  Serial  Serial232  Serial485  Stream  static 宣告的變數只能在該函式中被使用,但它不像一般區域變數,每當函式被呼叫時,就會被重新創 建然後隨著函式執行完畢後就會被釋放,靜態變數的存在不受函式的呼叫與否影響,變數的值在每次呼 叫完函式之後繼續被保留。  取”餘數”是用『%』,VB 是用『MOD』指令。

 If 判斷句常用的 AND 是用『&&』符號,OR 是用『||』符號(Enter 鍵上面)。 

(10)

10

實驗 2:練習以 PWM 控制單顆 LED,以製作漸層效果。

執行 Arduino 捷徑,File→Examples→03Analog(類比)→Fading(褪色;凋謝),載入現成的測試程式。

int ledPin = 9; // LED connected to digital pin 9

void setup() {

// nothing happens in setup }

void loop() {

// fade in from min to max in increments of 5 points:

for(int fadeValue = 0 ; fadeValue <= 255; fadeValue +=5) {

// sets the value (range from 0 to 255): analogWrite(ledPin, fadeValue);

// wait for 30 milliseconds to see the dimming effect delay(30);

}

// fade out from max to min in increments of 5 points:

for(int fadeValue = 255 ; fadeValue >= 0; fadeValue -=5) {

// sets the value (range from 0 to 255): analogWrite(ledPin, fadeValue);

// wait for 30 milliseconds to see the dimming effect delay(30);

} }

(11)
(12)

12

實驗 4:練習同時控制多顆LED 與『讀取類比輸入值』。

File→Examples→07.Display→barGraph (※利用可變電阻分壓,LED 當電量%顯示)

(13)

實驗 6:利用上述電路練習 LED不規則顯示 (※利用資料陣列與程式技巧,但未用到可變電阻)。

// 底下用來宣告常數(const)

const int ledCount = 10; // the number of LEDs in the bar graph

// 底下用來定義變數名稱

int ledPins[] = { 0,1,2,3,4,5,6,7,8,9,11 }; // 利用 array 技巧,同時定義多腳位為輸出

int LedValue[] = { 0,1,3,7,0xF,0x1F,0x3f,0x7f,0xff,0x1ff,0x3ff,0,0x3ff,0,0x3ff,0,0x3ff }; // 0x 為 16 進制

//底下為程式設置部分,主要是定義各腳位模式

void setup() {

// 利用 For 定義各腳位均為輸出模式

for (int thisLed = 0; thisLed < 11; thisLed++) {

pinMode(ledPins[thisLed], OUTPUT); } //藍色為內建常數,務必都為大寫

}

//底下為主程式部分,利用無窮迴圈反覆執行

void loop() {

for (int i = 0; i < 17; i++) { //共有多少 17 個狀態,亦可配合使用常數

int x=LedValue[i];

for(int j=0 ;j<ledCount ; j++) { //共有 10 顆 led

if (x % 2 == 1) { //化為二進制技巧,其中%是取餘數,X % 2 可取出最右邊 LSB 的值 digitalWrite(ledPins[j], HIGH); } else { digitalWrite(ledPins[j], LOW); } x=int(x/2); //化為二進制技巧 delay(50); } //FOR j 迴圈的右括號 } //FOR i 迴圈的右括號 } //無窮迴圈 LOOP 的右括號 若是 UNO 需先將電路拔除,否則燒錄會出現錯誤。但 是 UNO 優點是 DIP 的 IC,寫入程式後可拔除使用喔!

(14)

14

實驗 7:練習利用 PWM 控制 Servo (伺服電動機= servomotor)。

執行 Arduino 捷徑,File→Examples→Servo→Sweep(原為打掃涵義,實際測試為左右搖擺動作)。

硬體接線方式可到http://arduino.cc/ 下的Learning(學習)→Exapmles(範例),利用Ctrl+F尋找 Servo 關 鍵字,找到『Sweep』單字點擊即可查看相關資料,包括硬體接線方式。

(15)

#include <Servo.h>

Servo myservo; // create servo object to control a servo

// a maximum of eight servo objects can be created

int pos = 0; // variable to store the servo position

void setup() {

myservo.attach(9); // attaches the servo on pin 9 to the servo object }

void loop() {

for(pos = 0; pos < 180; pos += 1) // goes from 0 degrees to 180 degrees { // in steps of 1 degree

myservo.write(pos); // tell servo to go to position in variable 'pos' delay(15); // waits 15ms for the servo to reach the position }

for(pos = 180; pos>=1; pos-=1) // goes from 180 degrees to 0 degrees {

myservo.write(pos); // tell servo to go to position in variable 'pos' delay(15); // waits 15ms for the servo to reach the position } }  需先準備 3 條單心線,以便連接測試,紅色線接 Vcc,棕色線接 GND,黃色線接 Pin9做 PWM 控 制,當正確時伺服器馬達應會做『左右搖擺』的動作。  種類:定位型與連續旋轉型,一般沒有特別說明皆為定位型。  以 PWM 訊號控制,脈波週期 20ms,脈波寬度 1.5ms 時為中間值。  定位型:由控制訊號控制轉動角度(-90 度~+90 度),當輸入脈波寬度為 1.5ms 時為 0 度,脈波寬 度越大則越向+90 度靠近;越小則向-90 度靠近。  連續旋轉型:每接收一個脈波即向順/逆時針轉動一個角度,轉動的角度由 PWM 工作週期決定, 並可不斷 360 度旋轉。當脈波寬度為 1.5ms 時,馬達靜止;當脈波寬度大於 1.5ms 則順時針旋轉, 小於則朝反方向旋轉,距 1.5ms 越遠則轉動速度越快。 ←建議用焊接電路板,整合 實驗 1~7 在同一板子練習

(16)

16 綜合實驗 1~7:結合上述按鈕開關、類比電壓輸入、喇叭(新增)、PWM 控制 LED、Servo 伺服電動 機,希望能整合成為一個程式碼,請自行發揮創意,思考如何結合應用? 老師提供的範例功能說明如下: 1. 當按鈕開關不按時,LED 可搭配可變電阻顯示電量%大小,若低於 50%則喇叭發出聲響,電量越 低聲音越急促

2. 當按鈕開關按下時,做 LED 的 PWM 控制,一直按著時,觀察單一顆 LED 的逐亮變化,同時 Servo 伺服電動機會左右擺動,LED Bar 可同步做動畫顯示。

---

/* 泰山高中電子科陳致中老師 Arduino 上課範例

1. 讀取 A0 的類比輸入,以偵測 0~5V 電壓大小(VR 分壓),然後透過 LED bar 顯示電量百分比大小 2. LED bar 分別接到 pin 0~9

3. Pin10 用來連接開關,練習輸入

4. Pin11 連接 SERVO,練習 PWM 控制馬達 5. Pin12 接喇叭練習聲音控制

6. Pin13 用來連接一般,練習 PWM 控制 LED,但是 UNO 的 pin13 沒有 PWM,要小心 */

#include <Servo.h> //將別人寫好的 servo 程式包含進來

Servo myservo; // create servo object to control a servo // 底下用來宣告常數(const)

const int analogPin = A0; // the pin that the potentiometer is attached to

const int ledCount = 11; // the number of LEDs in the bar graph and pin12

// 底下用來定義變數名稱

int buttonState = 0; // variable for reading the pushbutton status

int PWM_Value = 0; // pin13 用來做 PWM 脈波寬度調整練習

int led_Value = 0; // 當按鈕按下可以控制 led 跑馬效果,以記錄目前位置

int ledPins[] = { 0,1,2,3,4,5,6,7,8,9,12 }; // 利用 array 技巧,同時定義多腳位為輸出

//底下為程式設置部分,主要是定義各腳位模式

void setup() {

myservo.attach(11); // attaches the servo on pin 11 to the servo object

// 利用 For 定義各腳位均為輸出模式

for (int thisLed = 0; thisLed < ledCount; thisLed++) {

pinMode(ledPins[thisLed], OUTPUT); } //藍色為內建常數,務必都為大寫

pinMode(10, INPUT); //Pin10 用來連接開關,練習輸入

//pinMode(13, OUTPUT); //做 PWM 控制必為輸出,所以無需定義

}

//底下為主程式部分,利用無窮迴圈反覆執行

void loop() {

buttonState = digitalRead(10); //讀取 Pin10 的數位資料,並做判斷執行

if (buttonState == HIGH) { //當按鈕按下

(17)

delay(30); //因為有 servo,所以暫時不用延遲

PWM_Value+=5; //相當於 PWM_Value=PWM_Value+5 遞增

if (PWM_Value>=255) {PWM_Value=255;} //底下是練習 LED 控制

for (int x = 0; x < 10; x++) {digitalWrite(ledPins[x], LOW); }

for (int x = 0; x <= led_Value; x++) {digitalWrite(ledPins[x], HIGH); } led_Value++;

led_Value=led_Value % 10; //取餘數技巧

//底下做 SERVO 馬達練習

for(int pos = 90; pos < 135; pos += 1) {

myservo.write(pos); delay(15);

}

for(int pos = 135; pos>=90; pos-=1) { myservo.write(pos); delay(15); } } //若條件成立的右括號 else { digitalWrite(12, LOW); led_Value = 0; PWM_Value=0; analogWrite(13, PWM_Value); // 底下是讀取 A0 的類比信號,再透過 LED 顯示電壓大小

int sensorReading = analogRead(analogPin);

// map(value, fromLow, fromHigh, toLow, toHigh)︰將一個數值從一個範圍映射到另外一個範圍。 // value︰需要映射的值、fromLow︰來源範圍值的下限、fromHigh︰來添範圍值的上限

// toLow︰目標範圍值的下限、toHigh︰目標範圍值的上限

int ledLevel = map(sensorReading, 0, 1023, 0, ledCount); //將值對應到十顆 LED

if (ledLevel<=5){ //電量低於 50%以下才發出警告聲

tone(12, 600,50); //tone(pin, frequency, duration),發出頻率為 600Hz,長度為 50ms 的聲音

delay(10*ledLevel);} //電量越低聲音越急促,因為時間越短

for (int thisLed = 0; thisLed < ledCount; thisLed++) { if (thisLed < ledLevel) { digitalWrite(ledPins[thisLed], HIGH); } else { digitalWrite(ledPins[thisLed], LOW); } } //FOR 迴圈的右括號 } //按鈕 else 右括號 } //無窮迴圈 LOOP 的右括號

(18)

18

綜合實驗 1~7-2:利用上述現成電路的喇叭、LED Bar 演奏小蜜蜂

--- const int speaker=12;

char toneName[]="CDEFGAB";

unsigned int frequency[7]={523,587,659,694,784,880,988}; //頻率對照表

char beeTone[]="GEEFDDCDEFGGGGEEFDDCEGGEDDDDDEFEEEEEFGGEEFDDCEGGC"; byte beeBeat[]={1,1,2,1,1,2,1,1,1,1,1,1,2,1,1,2,1,1,2,1,1,1,1,4,

1,1,1,1,1,1,2,1,1,1,1,1,1,2,1,1,2,1,1,2,1,1,1,1,4}; //節拍

int led_Value = 0;

int ledPins[] = { 0,1,2,3,4,5,6,7,8,9,12 }; const int ledCount = 11;

const int beeLen=sizeof(beeTone); //取出歌譜的長度

unsigned long tempo=180; int i,j;

void setup() {

for (int thisLed = 0; thisLed < ledCount; thisLed++) { pinMode(ledPins[thisLed], OUTPUT); } } void loop() { for(i=0;i<beeLen;i++) playTone(beeTone[i],beeBeat[i]); }

void playTone(char toneNo,byte beatNo) //發聲副程式

{

unsigned long duration=beatNo*60000/tempo; for(j=0;j<7;j++) { digitalWrite(ledPins[j], LOW); if(toneNo==toneName[j]) //將對應音符的 LED 全部熄滅 { tone(speaker,frequency[j]);

digitalWrite(ledPins[j], HIGH); //將對應音符的 LED 點亮

delay(duration);

noTone(speaker); //停止發出聲音

} } }

(19)

實驗 8:練習超音波感測器http://coopermaa2nd.blogspot.tw/2012/09/hc-sr04.html File→Examples→06Sensors(感測器)→Ping (※此範例採用 3 隻腳硬體設計,傳送與接收共用,需再修改) 說明: pinMode(13,INPUT) 放在 Loop 無窮迴圈內是因 為原本程式是設計 3 隻腳,送出與接收脈波是同 一隻腳,所以要一直切換,另外把輸入腳改為 pin13,直接指定腳位雖然方便,但較大程式時, 卻不易修改。 durnation 變數會去計算脈波為 High 的時間,透過 換算求出英吋與公分,再透過終端機 Series 將結 果送出顯示。 產生 1 脈波 接受腳不共用 直接改 pin13

(20)

20

建議先定義腳位名稱→定義pingecho 為輸入腳→讀取 pingecho 高準位訊號寬度。

※利用Notepad++免費軟體,方便查看(點擊 2 下)程式變數或副程式使用狀況

(21)

由於是利用 pin13 接收高準位訊號寬度,而 pin13 已經接 LED,所以透過查看 LED 閃爍速度即可測試超 音波感測器好壞,但距離是多少?可用右上角內部終端機查看,除了內建的終端機,XP 有內建,但 Windows7 卻沒有,可自行免費下載TeraTerm軟體安裝

(※執行 setup.exe 安裝,然後須設定串列埠 COM 是第幾個?)

(22)

22 泰山高中電子科陳致中老師 Arduino 上課範例 2 名稱:3D LED 控制 (※ 技巧同四顆七段顯示器掃描原理) 註:3D LED 如何接會比較穩固,想想最多可擴充到 ? x ? 呢? /* 泰山高中電子科陳致中老師 Arduino 上課範例 2 名稱:3D LED 控制裝置 當 SW1=ON 電源開啟 當 SW3=ON=5V 開啟蜂鳴器 當 SW4=ON=5V、當 SW4=OFF=0V 配合感測器動作(因為有些感測器是有動作為 0,有的為 1 */ // 底下為數位腳位定義

const int seg9[] = {8,9,10,11,12,13,7,5,6}; // 3D LED 控制腳陣列,分別對應 i~a 段

const int scan[] = { 4, 3, 2 }; // 上、中、下掃描端控制腳陣列

const int Shock=1; //可放置各式感測器

const int BuzzerPin = 0; // 蜂鳴器位置 // 底下為類比腳位定義

const int speed = A0; // 接到可變電阻做電壓分壓,再用類比腳位讀取,以設定變換速度

const int SW3 = A3; // SW3 位置,因為數位腳位不夠,所以利用類比腳位,OFF<100,ON>500

const int SW4 = A1; // SW4 位置,因為數位腳位不夠,所以利用類比腳位,OFF<100,ON>500

const int CDS = A2; // 光敏電阻 // 底下為七段顯示器輸出定義 int TAB[]={511,0,511,0,511,0,292,146,73,448,56,7,84,266,161,273,140,98,311,473,95,500,493,511 ,511,511}; // 3D LED 編碼表 int ii,jj; // 迴圈用的變數 int ScanLine=0; // 底下 setup 程序只有在微控制器按 reset 時執行一次 調整變換速度 調整靈敏度 光敏電阻 Cds

(23)

void setup() { pinMode(Shock,INPUT); pinMode(BuzzerPin, OUTPUT);

//pinMode(speakerPin,OUTPUT); // 初始化指定的數位腳位為輸出模式

for (ii=0; ii<12; ii++) pinMode(seg9[ii], OUTPUT); // 初始化指定的數位腳位為輸出模式

for (ii=0; ii<3; ii++) pinMode(scan[ii], OUTPUT); // 初始化指定的數位腳位為輸出模式

} // 底下 loop 程序會一直重覆執行 void loop() { int S3 = analogRead(SW3); //因為數位腳位不夠,所以利用類比腳位讀取指撥開關 int S4 = analogRead(SW4); int val=digitalRead(Shock); int cds2 = analogRead(CDS);

static int i = i % 26 ; //配合 TAB 長度值

// if((val==HIGH && S4>500) || (val==LOW && S4<100)){ //另外接其他感測器,如震動感應才要 if((cds2>500 && S4>500) || (cds2<100 && S4<100)){

int s = analogRead(speed);

int delaytime = map(s, 0, 1023, 1, 1000); //0.1 秒~2 秒

if(S3>500) tone(BuzzerPin, 400,10); OutPort(TAB[i]); //若希望三層內容獨立,則 TAB 內容須增加三倍量 i++; digitalWrite(scan[0], HIGH); // 指定的掃描端電晶體 ON delay(delaytime); //OutPort(TAB[i]); if(S3>500) tone(BuzzerPin, 400,10);

digitalWrite(scan[0], LOW); // 指定的掃描端電晶體 OFF

digitalWrite(scan[1], HIGH); // 指定的掃描端電晶體 ON

delay(delaytime); //OutPort(TAB[i]);

if(S3>500) tone(BuzzerPin, 400,10);

digitalWrite(scan[1], LOW); // 指定的掃描端電晶體 OFF

digitalWrite(scan[2], HIGH); // 指定的掃描端電晶體 ON

delay(delaytime);

digitalWrite(scan[2], LOW); // 指定的掃描端電晶體 OFF

}

} // Loop 結束

// 副程式,將指定值顯示在 3D LED 上,最低位元為 a,依序為 abcdefg

void OutPort(int dat) { for (jj=0; jj<9; jj++) { if (dat % 2==1) // 取出 dat 的最低位元 digitalWrite(seg9[jj], HIGH); else digitalWrite(seg9[jj], LOW); dat=dat/2; // 除 2,進行下一位元的處理 } }

(24)

24 泰山高中電子科陳致中老師 Arduino 上課範例 3 名稱:四合一可攜式超實用裝置

功能 1(當 SW3/4=OFF/OFF):利用超音波做測距離實驗 -- 倒車雷達(當 SW2=ON 低於 5 公分有 BiBi 聲) 功能 2(當 SW3/4=ON/OFF):讀取 A1 類比輸入,偵測 0~5V 電壓大小,然後透過七段顯示目前電量大小 功能 3(當 SW3/4=OFF/ON):利用 AD590 做溫度測量實驗,讀取 A2 類比輸入(每上升 1 度,上升 1µA) 功能 4(當 SW3/4=ON/ON):配合超音波測距實驗做電子抽籤(當低於 5 公分停止抽籤動作)

/* 泰山高中電子科陳致中老師 Arduino 上課範例 3 名稱:四合一可攜式超實用裝置

功能 1(當 SW3/4=OFF/OFF):利用超音波做測距離實驗 -- 倒車雷達(當 SW2=ON 低於 5 公分有 BiBi 聲) 功能 2(當 SW3/4=ON/OFF):讀取 A1 類比輸入,偵測 0~5V 電壓大小,然後透過七段顯示目前電量大小 功能 3(當 SW3/4=OFF/ON):利用 AD590 做溫度測量實驗,讀取 A2 類比輸入(每上升 1 度,上升 1µA) 功能 4(當 SW3/4=ON/ON):配合超音波測距實驗做電子抽籤(當低於 5 公分停止抽籤動作)

七段顯示器上排背面腳位:pin2(b)、3(com2)、4(com3)、5(f)、6(a)、7(com4) 七段顯示器下排背面腳位:pin0(com1)、1(g)、8(c)、9(dp)、10(d)、11(e) */ // 底下為數位腳位定義

const int seg7[] = {6, 2, 8, 10, 11, 5, 1,9}; // 七段控制腳陣列,分別對應 a~g 段

const int scan[] = { 0, 3, 4, 7 }; // 四位數掃描端控制腳陣列,對應千、百、十、個位數

GND GND Vcc 手機電池 溫度感測 量測電池 超音波

(25)

const byte TrigPin = 12; // 超音波觸發接腳

const byte EchoPin = 13; // 超音波反射接腳

long duration; // 測量超音波距障礙物的反射波時間,數字較大,需使用長整數

// 底下為類比腳位定義

const int analogPin0 = A0; // 接到可變電阻,以設定電子抽籤的最大值

const int analogPin1 = A1; // 讀取 0~5V 電壓

const int temp = A2; // 讀取 AD590 目前溫度值

const int BuzzerPin = A3; // 蜂鳴器位置,因為數位腳位不夠,所以利用類比腳位

const int SW3 = A4; // SW3 位置,因為數位腳位不夠,所以利用類比腳位,OFF<100,ON>500

const int SW4 = A5; // SW4 位置,因為數位腳位不夠,所以利用類比腳位,OFF<100,ON>500

// 底下為七段顯示器輸出定義 int delaytime=5; // 宣告延遲時間的變數名稱,預設為 5 ms char TAB[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x27,0x7F,0x67,0x00}; // 七段顯示器編碼表 int ii,jj; // 迴圈用的變數 int ScanLine=0; // 底下 setup 程序只有在微控制器按 reset 時執行一次 void setup() { // 初始化指定的數位腳位為輸出模式 pinMode(TrigPin, OUTPUT); // 初始化指定的數位腳位為輸出模式 pinMode(EchoPin, INPUT); // 初始化指定的數位腳位為輸入模式

for (ii=0; ii<=7; ii++) pinMode(seg7[ii], OUTPUT); // 初始化指定的數位腳位為輸出模式

for (ii=0; ii<4; ii++) pinMode(scan[ii], OUTPUT); // 初始化指定的數位腳位為輸出模式

} // 底下 loop 程序會一直重覆執行 void loop() { int S3 = analogRead(SW3); //因為數位腳位不夠,所以利用類比腳位讀取指撥開關 int S4 = analogRead(SW4); // 功能 1(當 SW3/4=OFF/OFF):利用超音波做測距離實驗 if (S3 <100 && S4 <100) { // &&表示而且 AND

int mm,x; //因為從七段顯示超音波距離,不須用 long

digitalWrite(TrigPin, LOW); // 按觸發的時序, 先讓 Trig 為低準位 2us

delayMicroseconds(2);

digitalWrite(TrigPin, HIGH); // Trig 為高準位 10us

delayMicroseconds(10);

digitalWrite(TrigPin, LOW); // Trig 為低準位 2us

delayMicroseconds(2);

(26)

26 mm = duration/5.8; // 轉換成 mm 距離 if (mm>1999) { mm=1999; } // 假設最大僅可測量 200mm=2 公尺,因為越遠,誤差越大 OutPort(TAB[mm % 10]); // %是取餘數,即取出最右邊數字 digitalWrite(scan[0], HIGH); // 指定的掃描端電晶體 ON delay(delaytime);

digitalWrite(scan[0], LOW); // 指定的掃描端電晶體 OFF

x=mm/10; // 取出第二個數字,因為 x 已經宣告為整數,所以不用再用 int 函數

OutPort(TAB[x % 10]+128); //個位數,多加小數點

digitalWrite(scan[1], HIGH); // 指定的掃描端電晶體 ON

delay(delaytime);

digitalWrite(scan[1], LOW); // 指定的掃描端電晶體 OFF

x=mm/100; // 取出第三個數字

OutPort(TAB[x % 10]);

digitalWrite(scan[2], HIGH); // 指定的掃描端電晶體 ON

delay(delaytime);

digitalWrite(scan[2], LOW); // 指定的掃描端電晶體 OFF

x=mm/1000; // 取出第四個數字

OutPort(TAB[x % 10]);

digitalWrite(scan[3], HIGH); // 指定的掃描端電晶體 ON

delay(delaytime);

digitalWrite(scan[3], LOW); // 指定的掃描端電晶體 OFF

if (mm<=50) { // 當 SW2=ON,若低於 5 公分時,蜂鳴器持續發出警告聲 tone(BuzzerPin, 400,50); delay(10); } // 延遲 0.01 秒 } // 功能 1 結束 // 功能 2(當 SW3/4=ON/OFF):讀取 A1 的類比輸入,以偵測 0~5V 電壓大小 if (S3 >500 && S4 <100) {

int sensorReading = analogRead(analogPin1);

int ledLevel = map(sensorReading, 0, 1023, 0, 5000); //將值對應到 0~5.000V

if (ledLevel >100){ //電壓低於 0.1V,過低視為雜訊,則不顯示 OutPort(TAB[ledLevel % 10]); // 顯示小數點後第三位數字 digitalWrite(scan[0], HIGH); delay(delaytime); digitalWrite(scan[0], LOW); ledLevel=ledLevel/10; OutPort(TAB[ledLevel % 10]); // 顯示小數點後第二位數字 digitalWrite(scan[1], HIGH); delay(delaytime); digitalWrite(scan[1], LOW); ledLevel=ledLevel/10; OutPort(TAB[ledLevel % 10]); // 顯示小數點後第一位數字 digitalWrite(scan[2], HIGH);

(27)

delay(delaytime); digitalWrite(scan[2], LOW); ledLevel=ledLevel/10; OutPort(TAB[ledLevel % 10]+128); // 顯示個位數,並加小數點 digitalWrite(scan[3], HIGH); delay(delaytime); digitalWrite(scan[3], LOW); } } // 功能 2 結束 // 功能 3(當 SW3/4=OFF/ON):讀取 A0 的類比輸入,以偵測 AD590 溫度大小 if (S3 <100 && S4 >500) {

int sensorReading = analogRead(temp);

//先輸入 int ledLevel = sensorReading,以紀錄室溫 min 最小值與加熱後 max 溫度最大值

int ledLevel = map(sensorReading, 755, 990, 2500, 9999); //直接對映室溫與加熱後溫度

OutPort(TAB[ledLevel % 10]); // 顯示小數點後第二位數字 digitalWrite(scan[0], HIGH); delay(delaytime); digitalWrite(scan[0], LOW); ledLevel=ledLevel/10; OutPort(TAB[ledLevel % 10]); // 顯示小數點後第一位數字 digitalWrite(scan[1], HIGH); delay(delaytime); digitalWrite(scan[1], LOW); ledLevel=ledLevel/10; OutPort(TAB[ledLevel % 10]+128); // 顯示個位數,並加小數點 digitalWrite(scan[2], HIGH); delay(delaytime); digitalWrite(scan[2], LOW); ledLevel=ledLevel/10; OutPort(TAB[ledLevel % 10]); // 顯示十位數 digitalWrite(scan[3], HIGH); delay(delaytime); digitalWrite(scan[3], LOW); } // 功能 3 結束 // 功能 4(當 SW3/4=ON/ON):配合超音波測距實驗做電子抽籤 if (S3 >=500 && S4 >=500){

int sensorReading = analogRead(analogPin0);

int no = map(sensorReading, 0, 1023, 1, 99); //將值對應到 1~99,用以紀錄班級人數

int mm,x;

digitalWrite(TrigPin, LOW); delayMicroseconds(2);

(28)

28 delayMicroseconds(10);

digitalWrite(TrigPin, LOW); delayMicroseconds(2);

duration = pulseIn(EchoPin, HIGH); mm = duration/5.8;

static int sno; //前面一定要加靜態 static,該變數才不會一直歸零

for(int i=1 ; i<=mm/200+1 ; i++) // 距離越遠顯示速度愈慢,不可用延遲,因為要掃描七段

{ OutPort(TAB[no % 10]); // 最右邊七段,顯示班上最後一號的個位數 digitalWrite(scan[0], HIGH); delay(delaytime); digitalWrite(scan[0], LOW); OutPort(TAB[int(no/10) % 10]); // 顯示班上最後一號的十位數 digitalWrite(scan[1], HIGH); delay(delaytime); digitalWrite(scan[1], LOW); OutPort(TAB[sno % 10]+128); // 顯示抽到號碼的個位數,並加小數點 digitalWrite(scan[2], HIGH); delay(delaytime); digitalWrite(scan[2], LOW); OutPort(TAB[int(sno/10) % 10]); // 顯示抽到號碼的十位數 digitalWrite(scan[3], HIGH); delay(delaytime); digitalWrite(scan[3], LOW); } if (mm > 50) sno=random(1,no); // 當距離低於 5 公分停止亂數計數,單一敘述,大括號省略

//if (mm >=50) sno=(sno % no)+1; // 或用上數,當距離低於 5 公分停止上數

} // 功能 4 結束

} // Loop 結束

// 副程式,將指定值顯示在七段顯示器上,最低位元為 a,依序為 abcdefg

void OutPort(byte dat) { for (jj=0; jj<=7; jj++) { if (dat % 2==1) // 取出 dat 的最低位元 digitalWrite(seg7[jj], LOW); // 若為 0 代表該段要亮,因為共陽(缺點是亮度不平均) else digitalWrite(seg7[jj], HIGH); // 若為 1 代表該段要滅 dat=dat/2; // 除 2,進行下一位元的處理 } }

(29)

泰山高中電子科陳致中老師 Arduino 上課範例 4 名稱:利用手機藍芽直接控制 Arduino 的 LED 與音樂控制(演奏小蜜蜂與小星星) 功能 1(當 SW1=ON):打開電源,若電壓低於 2.6V 有 BiBi 聲 功能 2(當 SW4=ON):可偵測 3V 電壓,並傳於手機顯示目前電壓值,若 SW4=OFF 則不傳送 --- //泰山高中電子科陳致中老師 Arduino 上課範例 4,利用手機藍芽直接控制 Arduino

const int speaker=12; char chr, index; int fadeValue=0; //紀錄目前 PWM 值 int jj; int TAB[]={1023,0,1023,0,1023,0,1,3,7,15,31,62,124,248,496,992,960,896,768,512,513,771,903 ,975,1023,1023,1023,0,48,120,252,510,1023,1023,0}; // LED 編碼表 char toneName[]="CDEFGAB";

unsigned int frequency[7]={523,587,659,694,784,880,988}; char Tone[]="CDEFGAB"; char beeTone[]="GEEFDDCDEFGGGGEEFDDCEGGEDDDDDEFEEEEEFGGEEFDDCEGGC"; //小蜜蜂歌譜 char starTone[]="CCGGAAGFFEEDDCGGFFEEDGGFFEEDCCGGAAGFFEEDDC"; //小星星歌譜 byte beeBeat[]={ 1,1,2,1,1,2,1,1,1,1,1,1,2,1,1,2,1,1,2,1,1,1,1,4,1,1,1,1,1,1,2,1,1,1,1,1 ,1,2,1,1,2,1,1,2,1,1,1,1,4}; //小蜜蜂節拍 byte starBeat[]={ 1,1,1,1,1,1,2,1,1,1,1,1,1,2,1,1,1,1,1,1,2,1,1,1,1,1,1,2,1,1,1,1,1,1,2,1 ,1,1,1,1,1,2}; //小星星節拍

int led_Value = 0; //記錄 LED 動態顯示目前的位置

int ledPins[] = { 2,3,4,5,6,7,8,9,13,11,12 }; // 利用 array 技巧,同時定義多腳位為輸出

const int ledCount = 11; // the number of LEDs in the bar graph and pin12

const int beeLen=sizeof(beeTone); const int starLen=sizeof(starTone); const int TABLen=35; //LED 展示長度

unsigned long tempo=180; int i,j;

(30)

30 const int Volt = A2; // test 3V

const int SW4 = A5; // SW4 位置,因為數位腳位不夠,所以利用類比腳位,OFF<100,ON>50

void setup() {

for (int thisLed = 0; thisLed < ledCount; thisLed++) { pinMode(ledPins[thisLed], OUTPUT);

} //藍色為內建常數,務必都為大寫

Serial.begin(12800); //藍芽 Baud rate,石英晶體為 12MHz,若是 16MHz 則用 9600bps }

void loop() {

int S4 = analogRead(SW4); if (S4 <100) {

int sensorReading = analogRead(Volt);

float ledLevel = map(sensorReading, 0, 1023, 0, 500); //將值對應到 0~5.00V

digitalWrite(10, LOW); if (ledLevel < 260){ //電壓低於 2.6V,綠色亮表示電壓過低 digitalWrite(10, HIGH); tone(speaker, 400,50); delay(10); } // 延遲 0.01 秒 // 判斷串列埠緩衝區有無資料 if (Serial.available()) { chr=Serial.read(); // 從串列埠緩衝區中讀取下一個有效的字元資料 if (ledLevel >10){ //電壓低於 0.1V,過低視為雜訊,則不顯示

Serial.print("Now Voltage="); // 在 Serial Monitor 中顯示訊息

Serial.print(ledLevel/100); Serial.println("V"); } } if (chr=='9') { //控制所有 PWM 接腳的 LED 漸亮 analogWrite(3, fadeValue); analogWrite(5, fadeValue); analogWrite(6, fadeValue); analogWrite(9, fadeValue); analogWrite(10, fadeValue); analogWrite(11, fadeValue); fadeValue=fadeValue+2; if(fadeValue> 255) fadeValue=255; } if (chr=='8') { //控制所有 PWM 接腳的 LED 漸暗 analogWrite(3, fadeValue); analogWrite(5, fadeValue); analogWrite(6, fadeValue); analogWrite(9, fadeValue); analogWrite(10, fadeValue); analogWrite(11, fadeValue); fadeValue=fadeValue-2;

(31)

if(fadeValue<0) fadeValue=0; } if (chr=='0') { //長按直接關閉 PWM fadeValue=0; analogWrite(3, fadeValue); analogWrite(5, fadeValue); analogWrite(6, fadeValue); analogWrite(9, fadeValue); analogWrite(10, fadeValue); analogWrite(11, fadeValue); } if (chr=='A') { //小蜜蜂音樂撥放 for(i=0;i<beeLen;i++) playTone(beeTone[i],beeBeat[i]); delay(3000); } if (chr=='B') { //小星星音樂撥放 for(i=0;i<starLen;i++) playTone(starTone[i],starBeat[i]); delay(3000); } if (chr=='C') { //LED 動態展示 for(i=0;i<TABLen;i++){ OutPort(TAB[i]); delay(300); } } if ((chr-'1')>=0 && (chr-'7')<=0) { // 判斷讀入的字元是否介於'1'~'7' index=chr-'1'; // 取得音調陣列中的索引值 playTone(Tone[index],1); } } }

void playTone(char toneNo,byte beatNo) { unsigned long duration=beatNo*60000/tempo; for(j=0;j<7;j++) { digitalWrite(ledPins[j], LOW); if(toneNo==toneName[j]) { tone(speaker,frequency[j]); digitalWrite(ledPins[j], HIGH); delay(duration); digitalWrite(ledPins[j], LOW);

(32)

32 noTone(speaker); } } } // 副程式,將指定值顯示在 LED 上

void OutPort(int dat) { for (jj=0; jj<10 ;jj++) { if (dat % 2==1) // 取出 dat 的最低位元 digitalWrite(ledPins[jj], HIGH); else digitalWrite(ledPins[jj], LOW); dat=dat/2; // 除 2,進行下一位元的處理 } } 補充說明: 1. 藍芽模組的 Rx 與 Tx 腳位不一定相同,需將藍芽模組的 Rx 與 Tx 接到 Arduino 的 Tx 與 Rx(反接), 即 pin0 接藍芽模組的 Tx,pin1 接藍芽模組的 Rx,另外還有 Vcc 與 GND,所以僅需使用 4 隻腳。 2. 本電路使用現成的 3V 轉 5V 的升壓模組,用一般電池即可,還可當緊急行動電源,但電壓會下降。

3. 利用 UNO 當作燒錄器,ATMEGA328 為 DIP 規格,可直接進行相關電路焊接,腳位說明如下: Vcc ND GND ND  Arduino 的數位 0~7 分別對應到 ATMEGA328 的 pin2.3.4.5.6.11.12.13  Arduino 的數位 8~13 分別對應到 ATMEGA328 的 pin14.15.16.17.18.19

 Arduino 的類比 AD0~5 分別對應到 ATMEGA328 的 pin23.24.25.26.27.28  pin1:接限流電阻 10K→Vcc (接開關到地當 Reset)  pin7:Vcc  pin8:GND  pin9、10 接 12MHz 石英整盪,同時並接 30p 電容 到 GND  pin2:接藍芽模組的 Tx、pin3:接藍芽模組的 Rx 相反 ND

(33)

4. 手機 App 搜尋『藍芽串口助手』,操作與設定請參閱下圖 (※第一次藍芽配對會出現 Null)

→ → →

→ → →

(34)

34 //設定藍芽名稱與密碼的程式碼

#include <SoftwareSerial.h>

SoftwareSerial BTSerial(10, 11); // 藍芽 HC-05 可以設定,但 HC-06 不可設定,YFRobot 可以設定, 但是傳送 Tx 與接收 Rx 腳位和 HC-05 相反,所以腳位定義須改為 BTSerial(11, 10),且 AT 指令不同 void setup()

{

pinMode(9, OUTPUT); // 讓 Key/SET 腳位為 1,以便進入 AT 模式設定

digitalWrite(9, HIGH); Serial.begin(9600); Serial.println("Enter AT commands:"); BTSerial.begin(9600); } void loop() { if (BTSerial.available()) Serial.write(BTSerial.read()); if (Serial.available()) BTSerial.write(Serial.read()); }

(35)

 YFRobot 藍牙模組採用大 陸公司自行開發藍牙核心 板 BC-04,與一般市面常 用 HC-05 不同。所以,AT 指令集也不太相同。  YFRobot 藍牙模組的 AT 指令結尾不能加 '?' ,而且 大小寫均可接受。  YFRobot 密碼稱為PIN  YFRobot 鮑率設定BAUD  YFRobot 設定時,中間不 可加入冒號: 1. HC-05 藍牙模組的 AT 指令結尾需加 '?' ,僅支援大寫。 2. HC-05 密碼稱為PSWD 3. HC-05 鮑率設定UART 4. HC-05 設定時,中間要加入冒號,正確會顯示 OK

(36)

36

補充:若想用較便宜的 ATMEGA8 取代 ATMEGA328,使用前須自行將 Bootloader 寫進 ATMega 晶片,但容 量較小,可用於簡單電路。

 硬體電路連接如下:

 軟體燒錄步驟說明如下:

1. File→Examples→ArduinoISP,先『燒錄』該程式,目的是將 Arduino 當成 ISP 的板子(勿先接) 2. 選擇 Tools→Board→ATMEGA8 或其他規格(此時須將左上圖電路連接)

3. Tools→Programmer→Arduino as ISP 4. Tools→Burn Bootloader(經過一段時間)

5. 看到右側訊息表示成功 ,若看到右側訊息表示失敗

(37)

泰山高中電子科陳致中老師 Arduino 上課範例 5 名稱:控制串列式全彩 LED (利用可變電阻調亮度)

/* 串列式全彩 LED 硬體接腳 Din、Vcc、GND(最長)、Dout

使用前先到 https://github.com/adafruit/Adafruit_NeoPixel

按右下的"DOWNLOAD ZIP"→下載後解壓縮→重新命名為"Adafruit_NeoPixel"→ 複製於 C:\Program Files (x86)\Arduino\libraries,方可使用 H 檔案 WS2812 系列串列式 RGB LED 連接在 Pin 2

*/

#include <Adafruit_NeoPixel.h> #define TOP_DOWN 0

#define DOWN_TOP 1

#define MEDIUMSPRINGGREEN 0x00FA9A #define INDIGO 0x4B0082

const int pot = A5; //宣告可調電阻分壓後連接在 A5 腳,以調整亮度

#define PIN 2

#define LED_CNT 42 //宣告多少顆 LED // 建構名為 leds 的 Adafruit_NeoPixel 類別

Adafruit_NeoPixel leds = Adafruit_NeoPixel(LED_CNT, PIN, NEO_GRB + NEO_KHZ800);

// 設定=================================================================== void setup() { leds.begin(); // 初始化 clearLEDs(); // 關閉所有 LED leds.show(); // 開啟所有 LED } // 主程式=================================================================== void loop(){ int x=analogRead(pot); leds.setBrightness(x/4); //宣告可調電阻分壓後連接在 A5 腳,以調整亮度 brightness(); //三原色逐字點亮

for (int i=0; i<LED_CNT; i++) { clearLEDs(); // 關閉所有 LED

for (int j=0; j<=i; j++) {

(38)

38 leds.setPixelColor(j, 255, 0, 0); // 綠色 } brightness(); // 調整亮度 leds.show(); // 開啟所有 LED delay(20); // 持續顯示 }

for (int i=0; i<LED_CNT; i++) { clearLEDs(); // 關閉所有 LED

for (int j=0; j<=i; j++) {

leds.setPixelColor(j, 0, 255, 0); // 紅色 } brightness(); // 調整亮度 leds.show(); // 開啟所有 LED delay(20); // 持續顯示 }

for (int i=0; i<LED_CNT; i++) { clearLEDs(); // 關閉所有 LED

for (int j=0; j<=i; j++) {

leds.setPixelColor(j, 0, 0, 255); // 藍色 } brightness(); // 調整亮度 leds.show(); // 開啟所有 LED delay(20); // 持續顯示 } //單字閃爍 clearLEDs(); // 關閉所有 LED

for (int i=0; i<47; i++) {

leds.setPixelColor(i, 255, 0, 0);} // 第 1 個字綠色

brightness(); // 調整亮度

leds.show(); // 開啟所有 LED

delay(500); // 持續顯示

for (int i=47; i<47+28; i++) {

leds.setPixelColor(i, 0, 255, 0);} // 第 2 個字紅色

brightness(); // 調整亮度

leds.show(); // 開啟所有 LED

delay(500); // 持續顯示

for (int i=47+28; i<47+28+48; i++) {

leds.setPixelColor(i, 0, 0, 255);} // 第 3 個字藍色

brightness(); // 調整亮度

leds.show(); // 開啟所有 LED

delay(500); // 持續顯示

for (int i=47+28+48; i<155; i++) {

leds.setPixelColor(i, 128, 128, 128);} // 第 4 個字白色

brightness(); // 調整亮度

leds.show(); // 開啟所有 LED

delay(3000); // 持續顯示 // 漫步彩虹大道 (重複 10 週)

(39)

for (int i=0; i<LED_CNT*20; i++) { rainbow(i); // 執行彩虹顯示功能 delay(20); // 持續顯示 } // 靛藍龍捲風 (重複 10 週)

for (int i=0; i<6; i++) {

cyclone(INDIGO, 125); // 靛藍龍捲風眼 500

// 龍捲風函數:第一個引數為顏色,第二個引數為週期(時間)

}

// 春雨(執行由上而下瀑布 20 次)

for (int i=0; i<10; i++) {

cascade(MEDIUMSPRINGGREEN, TOP_DOWN, 50);

// 第一個引數為顏色, 第二個引數為方向, 第二個引數為掉落時間(ms)

} }

// 龍捲風函數=============================================================

void cyclone(unsigned long color, byte wait) {

// weight 為淡化外部眼顏色的亮

const byte weight = 4;

// 分離 24 位元格式為 8 位元 RGB 格式

byte red = (color & 0xFF0000) >> 16; byte green = (color & 0x00FF00) >> 8; byte blue = (color & 0x0000FF);

// 由最近的 LED 往內移

for (int i=0; i<=LED_CNT-1; i++) { clearLEDs(); // 關閉所有 LED

leds.setPixelColor(i, red, green, blue); // 設定亮的中間眼 Set the bright middle eye // 使兩個眼往兩側逐漸變暗

for (int j=1; j<3; j++) { if (i-j >= 0)

leds.setPixelColor(i-j, red/(weight*j), green/(weight*j), blue/(weight*j)); if (i-j <= LED_CNT)

leds.setPixelColor(i+j, red/(weight*j), green/(weight*j), blue/(weight*j)); }

brightness(); // 調整亮度

leds.show(); // Turn the LEDs on

delay(wait); // Delay for visibility

}

// 反向操作

for (int i=LED_CNT-2; i>=1; i--) { clearLEDs(); // 關閉所有 LED

leds.setPixelColor(i, red, green, blue); for (int j=1; j<3; j++) {

if (i-j >= 0)

leds.setPixelColor(i-j, red/(weight*j), green/(weight*j), blue/(weight*j)); if (i-j <= LED_CNT)

(40)

40

leds.setPixelColor(i+j, red/(weight*j), green/(weight*j), blue/(weight*j)); } brightness(); // 調整亮度 leds.show(); // 開啟所有 LED delay(wait); // 持續顯示 wait 時間 } } // 瀑布函數===============================================================

void cascade(unsigned long color, byte direction, byte wait) {

if (direction == TOP_DOWN) {

// 由上而下

for (int i=0; i<LED_CNT; i++) {

clearLEDs(); // 關閉所有 LED

leds.setPixelColor(i, color); // 設定此 LED 的顏色

brightness(); // 調整亮度 leds.show(); // 開啟所有 LED delay(wait); // 持續顯示 wait 時間 } } else { // 由下而上

for (int i=LED_CNT-1; i>=0; i--) { clearLEDs(); // 關閉所有 LED

leds.setPixelColor(i, color); // 設定此 LED 的顏色

brightness(); // 調整亮度 leds.show(); // 開啟所有 LED delay(wait); // 持續顯示 wait 時間 } } } // 關閉所有 LED 函數========================================================== // 設定顏色為黑色,再呼叫 show()函數,即可關閉 LED void clearLEDs() {

for (int i=0; i<LED_CNT; i++) { leds.setPixelColor(i, 0); }

}

// 彩虹函數================================================================

void rainbow(byte startPosition) {

int rainbowScale = 192 / LED_CNT; // 指定彩虹的刻度

for (int i=0; i<LED_CNT; i++) { // 設定每個 LED 的顏色 // 0-191 總共 192 個顏色(紅=>橙=>黃=>綠=>…=>紫)

leds.setPixelColor(i, rainbowOrder((rainbowScale * (i + startPosition)) % 192)); }

(41)

brightness(); // 調整亮度 leds.show(); // 開啟 LED } // 產生彩虹色帶函數====================================================== // 輸入 0~191 以取得顏色值 // 顏色變化為紅=>黃=>綠=>淺綠=>藍=>粉紅=>紅...

uint32_t rainbowOrder(byte position) {

// 6 個顏色區域(每區 32 點)

if (position < 31) { // 紅=>黃 (Red = FF, blue = 0, Green = 00=>FF)

return leds.Color(0xFF, position * 8, 0); // 只遞增綠色成份

}

else if (position < 63) { //黃=>綠 (Red = FF=>00, Green = FF, blue = 0)

position -= 31; // 第 2 區

return leds.Color(0xFF - position * 8, 0xFF, 0); // 只遞減紅色成份

}

else if (position < 95) { //綠=>淺綠 (Red = 0, Green = FF, Blue = 00=>FF)

position -= 63; // 第 3 區

return leds.Color(0, 0xFF, position * 8); // 只遞增藍色成份

}

else if (position < 127) { //淺綠>藍 (Red = 0, Green = FF=>00, Blue = FF)

position -= 95; // 第 4 區

return leds.Color(0, 0xFF - position * 8, 0xFF); // 只遞減綠色成份

}

else if (position < 159) { //藍=>粉紅 (Red = 00=>FF, Green = 0, Blue = FF)

position -= 127; // 第 5 區

return leds.Color(position * 8, 0, 0xFF); // 只遞增紅色成份

}

else {//160 <position< 191 粉紅=>紅 (Red = FF, Green = 0, Blue = FF=>00)

position -= 159; // 第 6 區

return leds.Color(0xFF, 0x00, 0xFF - position * 8); // 只遞減藍色成份

} } void brightness() // 讀取 A5 分壓結果,以控制亮度 { int x=analogRead(pot); leds.setBrightness(x/4); }

(42)

42 泰山高中電子科陳致中老師 Arduino 上課範例 6 名稱:利用手機藍芽控制串列式全彩 LED 亮度、速度、顏色、動作 //實習名稱:利用手機藍芽控制串列式全彩 LED 特效 #include <Adafruit_NeoPixel.h> #define TOP_DOWN 0 #define DOWN_TOP 1

#define MEDIUMSPRINGGREEN 0x00FA9A

#define INDIGO 0x4B0082

#define PIN 2

#define LED_CNT 155 //泰*48 山*28 高*48 中*31=155 顆 LED

Adafruit_NeoPixel leds = Adafruit_NeoPixel(LED_CNT, PIN, NEO_GRB + NEO_KHZ800);

static int bright=60; //前面一定要加靜態 static,該變數才不會一直歸零

static float speed=2; static int r=100; static int g=100; static int b=100; char chr; // 讀取藍芽傳輸變數 // 設定=================================================================== void setup() { leds.begin(); // 初始化 clearLEDs(); // 關閉所有 LED brightness(); leds.show(); // 開啟所有 LED pinMode(3, INPUT);

Serial.begin(12800); //藍芽 Baud rate,石英晶體為 12MHz,若是 16MHz 則用 9600bps

} // 主程式=================================================================== void loop(){ if (Serial.available()) { //判斷藍芽是否有傳送資料 chr=Serial.read(); // 從串列埠緩衝區中讀取下一個有效的字元資料 brightness(); // 調整亮度 if (chr=='A'){ //三原色逐字點亮 for (int i=0; i<LED_CNT; i++) { clearLEDs(); // 關閉所有 LED

for (int j=0; j<=i; j++) { leds.setPixelColor(j, g, r, b); } brightness(); // 調整亮度

(43)

leds.show(); // 開啟所有 LED delay(50*speed); } // 持續顯示

}

if (chr=='B'){ //單字閃爍 clearLEDs(); // 關閉所有 LED

for (int i=0; i<48; i++) {leds.setPixelColor(i, 255, 0, 0);} // 第 1 個字綠色 brightness(); // 調整亮度

leds.show(); // 開啟所有 LED delay(500*speed); // 持續顯示

for (int i=48; i<48+28; i++) {leds.setPixelColor(i, 0, 255, 0);} // 第 2 個字紅色 brightness(); // 調整亮度

leds.show(); // 開啟所有 LED delay(500*speed); // 持續顯示

for (int i=48+28; i<48+28+48; i++) {leds.setPixelColor(i, 0, 0, 255);} // 第 3 個字藍色 brightness(); // 調整亮度

leds.show(); // 開啟所有 LED delay(500*speed); // 持續顯示

for (int i=48+28+48; i<155; i++) {leds.setPixelColor(i, 128, 128, 128);} // 第 4 個字白色 brightness(); // 調整亮度 leds.show(); // 開啟所有 LED delay(500*speed); // 持續顯示 for (int k=0; k<5; k++) { //閃爍 5 次 clearLEDs(); // 關閉所有 LED leds.show(); delay(300*speed); // 持續顯示

for (int i=0; i<48; i++) { leds.setPixelColor(i, 255, 0, 0);} // 第 1 個字綠色 for (int i=48; i<48+28; i++) {leds.setPixelColor(i, 0, 255, 0);} // 第 2 個字紅色

for (int i=48+28; i<48+28+48; i++) {leds.setPixelColor(i, 0, 0, 255);} // 第 3 個字藍色 for (int i=48+28+48; i<155; i++) {leds.setPixelColor(i, 128, 128, 128);} // 第 4 個字白色 brightness(); // 調整亮度 leds.show(); // 開啟所有 LED delay(300*speed); // 持續顯示 } } // if (chr=='B')結尾 if (chr=='C'){ // 漫步彩虹大道

for (int i=0; i<LED_CNT*5; i++) {

rainbow(i); // 執行彩虹顯示功能 delay(30*speed); } // 持續顯示 } } // if (Serial.available())結尾 } // void loop()結尾 // 關閉所有 LED 函數========================================================== // 設定顏色為黑色,再呼叫 show()函數,即可關閉 LED void clearLEDs() {

for (int i=0; i<LED_CNT; i++) { leds.setPixelColor(i, 0); } }

// 彩虹函數================================================================ void rainbow(byte startPosition) {

int rainbowScale = 192 / LED_CNT; // 指定彩虹的刻度

(44)

44

leds.setPixelColor(i, rainbowOrder((rainbowScale * (i + startPosition)) % 192)); } brightness(); // 調整亮度 leds.show(); // 開啟 LED } // 產生彩虹色帶函數====================================================== // 輸入 0~191 以取得顏色值,顏色變化為紅=>黃=>綠=>淺綠=>藍=>粉紅=>紅...

uint32_t rainbowOrder(byte position) { // 6 個顏色區域(每區 32 點)

if (position < 31) { // 紅=>黃 (Red = FF, blue = 0, Green = 00=>FF) return leds.Color(0xFF, position * 8, 0); // 只遞增綠色成份 }

else if (position < 63) { //黃=>綠 (Red = FF=>00, Green = FF, blue = 0) position -= 31; // 第 2 區

return leds.Color(0xFF - position * 8, 0xFF, 0); // 只遞減紅色成份 }

else if (position < 95) { //綠=>淺綠 (Red = 0, Green = FF, Blue = 00=>FF) position -= 63; // 第 3 區

return leds.Color(0, 0xFF, position * 8); // 只遞增藍色成份 }

else if (position < 127) { //淺綠>藍 (Red = 0, Green = FF=>00, Blue = FF) position -= 95; // 第 4 區

return leds.Color(0, 0xFF - position * 8, 0xFF); // 只遞減綠色成份 }

else if (position < 159) { //藍=>粉紅 (Red = 00=>FF, Green = 0, Blue = FF) position -= 127; // 第 5 區

return leds.Color(position * 8, 0, 0xFF); // 只遞增紅色成份 }

else { //160 <position< 191 粉紅=>紅 (Red = FF, Green = 0, Blue = FF=>00) position -= 159; // 第 6 區

return leds.Color(0xFF, 0x00, 0xFF - position * 8); // 只遞減藍色成份 }

}

void brightness() // 控制亮度 bright、速度 speed、RGB 顏色

{ if (Serial.available()) { chr=Serial.read();

if (chr=='9' && bright<255) {bright=bright+2; Serial.print("Now Bright =");Serial.println (bright);} if (chr=='8' && bright>10) {bright=bright-2; Serial.print("Now Bright =");Serial.println (bright);} if (chr=='7' && speed>0.2) {speed=speed-0.1; Serial.print("Duration =");Serial.println(speed);} if (chr=='p' ) {speed=speed+0.1; Serial.print("Duration =");Serial.println (speed);}

if (chr=='1' && r>=5 ) {r-=5; Serial.print("Color R="); Serial.print(r); Serial.print(" G="); Serial.print(g); Serial.print(" B=");Serial.println (b);}

if (chr=='4' && r <255) {r+=5; Serial.print("Color R="); Serial.print(r); Serial.print(" G="); Serial.print(g); Serial.print(" B=");Serial.println (b);}

if (chr=='2' && g>=5 ) {g-=5; Serial.print("Color R="); Serial.print(r); Serial.print(" G="); Serial.print(g); Serial.print(" B=");Serial.println (b);}

if (chr=='5' && g<255 ) {g+=5; Serial.print("Color R="); Serial.print(r); Serial.print(" G="); Serial.print(g); Serial.print(" B=");Serial.println (b);}

if (chr=='3' && b>=5 ) {b-=5; Serial.print("Color R="); Serial.print(r); Serial.print(" G="); Serial.print(g); Serial.print(" B=");Serial.println (b);}

if (chr=='6' && b<255 ) {b+=5; Serial.print("Color R="); Serial.print(r); Serial.print(" G="); Serial.print(g); Serial.print(" B=");Serial.println (b);}

leds.setBrightness(bright); }

(45)

補充資料 1:利用免安裝Fritzing.exe程式繪製電路圖,檔案→開啟範例→Arduino裡面有許多現成範例。

補充資料 2:視覺化設計環境 Ardublock (利用拼圖直覺式寫程式) 下載 http://sourceforge.net/projects/ardublock/files

(46)

46 需到 C:\Users\user\Documents\Arduino 目錄自行新增

tools/ArduBlockTool/tool』資料夾(名稱大小寫須完

全相同),再將下載的 xxx.jar 放到該資料夾,重新開啟 Arduino 主程式,即可在 tools 下拉式找到 ArduBlock, 圖形化程式編輯完後按『上傳』,即可變成對應的程式 碼,對於指令不孰悉或初學者是很不錯選擇,但是比 較複雜的程式,還是建議學習程式語言。

(47)

/*ARDUINO 電路實習 By:泰山高中電子科 陳致中 名稱:簡易型四則運算 LCD 計算機

功能說明:

1. 利用 ARDUINO UNO 當成燒錄器,使用 ATMEGA328 直接控制本電路 2. 使用 4X4 鍵盤當成數字輸入,並透過 LCD 模組顯示運算過程 3. 由於鍵盤需使用 4+4 接腳,而 LCD 至少需要 3+4(用半位元傳輸),所以需利用類比腳位當作鍵盤的輸 入信號 4. 英文鍵 A~D 分別代表加、減、乘、除 硬體接腳說明: LCD pin 1 接 GND LCD pin 2 接 Vcc LCD pin 3 接 10K 可調電阻中間,以便控制亮度(0V 最亮) LCD pin 4 接 ARDUINO 數位 pin12(即 ATMEGA 的 pin18) LCD pin 5 接 ARDUINO 數位 pin11(即 ATMEGA 的 pin17) LCD pin 6 接 ARDUINO 數位 pin10(即 ATMEGA 的 pin16) LCD pin 11 接 ARDUINO 數位 pin5(即 ATMEGA 的 pin11) LCD pin 12 接 ARDUINO 數位 pin4(即 ATMEGA 的 pin6) LCD pin 13 接 ARDUINO 數位 pin3(即 ATMEGA 的 pin5) LCD pin 14 接 ARDUINO 數位 pin2(即 ATMEGA 的 pin4)

鍵盤掃描輸出接 ARDUINO 數位 pin6(即 ATMEGA 的 pin12)、pin7(13)、pin8(14)、pin9(15) 鍵盤輸入接 ARDUINO 類比 A2(即 ATMEGA 的 pin25)、A3(pin26)、A4(pin27)、A5(pin28) */

#include <LiquidCrystal.h>

LiquidCrystal lcd(12, 11,10, 5, 4, 3, 2); //宣告 LCD 變數,僅利用 D4~7 傳送資料

byte heartChar[8]={B00000,B01010,B11111,B11111,B01110,B00100,B00000,B00000}; //自訂愛心圖形

const byte divisorSymbol=B11111101; //自訂除號字型 //底下為鍵盤掃描電路

static float n1=0,n2=0; String str1 = String(""); String str2,temp;

String op = String("+");

const int numCols=4; //總行數

const int numRows=4; //總列數

const int col[]={6,7,8,9}; //行的數位接腳,用來輸出掃描

const int row[]={2,3,4,5}; //利用類比輸入讀取鍵盤列的接腳

void setup() {

lcd.begin(16,2); //宣告使用 16 行*2 列的 LCD

lcd.createChar(0,heartChar);

lcd.noBlink(); //游標閃爍,閃爍是 lcd.blink(),不閃爍是 lcd.noBlink(),大小寫需相同 //底下為鍵盤掃描電路 for(int i=0;i<numCols;i++) { pinMode(col[i],OUTPUT); //設定鍵盤行接腳為輸出 } lcd.setCursor(0,0); //將游標移到 0,0 位置 lcd.clear(); //清除螢幕 lcd.print("Arduino "); lcd.write(byte(0)); //顯示愛心字元

(48)

48 lcd.setCursor(0,1);

//lcd.print("Input IntegerNum"); lcd.print("Design Wen Tsung"); } void loop() { //底下為鍵盤掃描電路 int n=-1; str2= String("q"); //判斷是否有按鍵技巧 digitalWrite(col[0],HIGH); //送出掃描輸出信號 digitalWrite(col[1],LOW); digitalWrite(col[2], LOW); digitalWrite(col[3], LOW); if(analogRead(row[3])>500) str2= String("*"); if(analogRead(row[2])>500) {str2= String("9"); n=9;} if(analogRead(row[1])>500) {str2= String("5"); n=5;} if(analogRead(row[0])>500) {str2= String("1"); n=1;} digitalWrite(col[0],LOW); digitalWrite(col[1],HIGH); //送出掃描輸出信號 digitalWrite(col[2], LOW); digitalWrite(col[3], LOW); if(analogRead(row[3])>500) str2= String("/"); if(analogRead(row[2])>500) {str2= String("0"); n=0;} if(analogRead(row[1])>500) {str2= String("6"); n=6;} if(analogRead(row[0])>500) {str2= String("2"); n=2;} digitalWrite(col[0],LOW); digitalWrite(col[1], LOW); digitalWrite(col[2] ,HIGH); //送出掃描輸出信號 digitalWrite(col[3], LOW); if(analogRead(row[3])>500) str2= String("="); if(analogRead(row[2])>500) str2= String("+"); if(analogRead(row[1])>500) {str2= String("7"); n=7;} if(analogRead(row[0])>500) {str2= String("3"); n=3;} digitalWrite(col[0],LOW); digitalWrite(col[1], LOW); digitalWrite(col[2], LOW); digitalWrite(col[3], HIGH); //送出掃描輸出信號 if(analogRead(row[3])>500) str2= String("F"); if(analogRead(row[2])>500) str2= String("-"); if(analogRead(row[1])>500) {str2= String("8"); n=8;} if(analogRead(row[0])>500) {str2= String("4"); n=4;} if (temp!=str2 && str2!= "q" && str2!= "F")

{

temp= String(str2); //避免按著不放而連續出現

str1=str1+str2; //字串連結

//計算過程,要先記錄 OP 運算子

if(n<=9 && n>=0) { n2=n2*10+n; }

if(str2=="+" && op=="+") { n1=n1+n2; n2=0; op = String("+"); goto display;} if(str2=="+" && op=="-") { n1=n1-n2; n2=0; op = String("+"); goto display;} if(str2=="+" && op=="*") { n1=n1*n2; n2=0; op = String("+"); goto display;} if(str2=="+" && op=="/") { n1=n1/n2; n2=0; op = String("+"); goto display;} if(str2=="-" && op=="+") { n1=n1+n2; n2=0; op = String("-"); goto display;} if(str2=="-" && op=="-") { n1=n1-n2; n2=0; op = String("-"); goto display;}

(49)

if(str2=="-" && op=="*") { n1=n1*n2; n2=0; op = String("-"); goto display;} if(str2=="-" && op=="/") { n1=n1/n2; n2=0; op = String("-"); goto display;} if(str2=="*" && op=="+") { n1=n1+n2; n2=0; op = String("*"); goto display;} if(str2=="*" && op=="-") { n1=n1-n2; n2=0; op = String("*"); goto display;} if(str2=="*" && op=="*") { n1=n1*n2; n2=0; op = String("*"); goto display;} if(str2=="*" && op=="/") { n1=n1/n2; n2=0; op = String("*"); goto display;} if(str2=="/" && op=="+") { n1=n1+n2; n2=0; op = String("/"); goto display;} if(str2=="/" && op=="-") { n1=n1-n2; n2=0; op = String("/"); goto display;} if(str2=="/" && op=="*") { n1=n1*n2; n2=0; op = String("/"); goto display;} if(str2=="/" && op=="/") { n1=n1/n2; n2=0; op = String("/"); goto display;}

if(str2=="=" && op=="+") { n1=n1+n2;} //concat 是用來將字串和數值連接 if(str2=="=" && op=="-") { n1=n1-n2;}

if(str2=="=" && op=="*") { n1=n1*n2;}

if(str2=="=" && op=="/") { n1=n1/n2; } display: //配合 GOTO 所需標籤 lcd.setCursor(0,0); //將游標移到 0,0 位置 lcd.clear(); //清除螢幕 lcd.print(str1); if(str2=="=") { lcd.print("?"); lcd.setCursor(0,1); lcd.print("Answer:"); lcd.print(n1); } delay(50); } if (str2== "q") temp= String("x"); if (str2!="q" && str2=="F") { str1 = String(""); lcd.setCursor(0,0); //將游標移到 0,0 位置 lcd.clear(); //清除螢幕 lcd.print("Arduino "); lcd.write(byte(0)); //顯示愛心字元 lcd.print(" LCD&KB"); lcd.setCursor(0,1); n1=0; n2=0; op = String("+"); //運算過程中所用到的暫存值都須重新設定 } } //程式撰寫心得:本程式剛開始撰寫最大問題是輕輕按一個鍵(利用 str2!= "q"判斷解決)或一直按著某鍵 不放(利用 temp!=str2 判斷解決)都會一下跑出許多字元,另外就是字串和字串或字串與非字串的連接。 //目前缺點是無法輸入小數點的值,以及計算過程是以整數運算(因為 concat 連接字串不允許 float 浮點格 式),同時無法先乘除後加減,這些都是程式需要再克服的地方。 //鍵盤掃描輸出 X1~X4 接 ARDUINO 數位 pin6(即 ATMEGA 的 pin12)、pin7(13)、pin8(14)、pin9(15) //鍵盤輸入 Y1~Y4 接 ARDUINO 類比 A2(即 pin25)、 A3(pin26)、A4(pin27)、A5(pin28),電阻均接地,平時 讀取為 0,當掃描信號送來 5V,若有按下,才會讀到 5V 高電位

參考文獻

相關文件

Rather than requiring a physical press of the reset button before an upload, the Arduino Uno is designed in a way that allows it to be reset by software running on a

一、訓練目標:充分了解在自動化 機械領域中應用 Arduino 控制,進 而能自行分析、設計與裝配各種控

阿吉老師將簡介 micro:bit 開發程式環境,並分享 micro:bit 內建感測器程式編寫、數位/類比信號讀取及寫入,並了解 如何用 micro:bit 連接電子模組編寫程式進行機電整合。.

手機會使用 eclipse 開發一套 Android 系統配合 arduino 三軸的 APP,其功能會 有連接 arduino 藍芽模組的按鈕,按下按鈕,將可與 arduino

SPCE061A 的開發是通過線上調試器 PROBE 實現的。它既

這次的實驗課也分成兩個禮拜完成,在實驗過程中我們幾乎都很順利完成了課堂上要達到的目標

2-1 化學實驗操作程序的認識 探究能力-問題解決 計劃與執行 2-2 化學實驗數據的解釋 探究能力-問題解決 分析與發現 2-3 化學實驗結果的推論與分析

• 在「心房」進行課堂或體驗 式學習活動後,學生能以表 情符號表達自己的情緒,令 學生能以多元化的途徑表達 情緒,以便老師深入了解學