泰山高中電子科陳致中老師 Arduino 上課講義分享 1. 先到http://arduino.cc/ 下載免費的 Arduino1.0.5 工具程式(目前已到 1.6.1 版本)
※ 僅一個檔案約 53MB,因為學校下載很慢,第一次上課前先自行下載到隨身碟備用。 ※ 每次上課先複製 Arduino 執行檔案到硬碟再安裝,勿從隨身碟直接安裝,因為會很慢。
2
註 1:Arduino 軟體安裝完畢後,插入 Arduino 主板,驅動程式會自動安裝,但須到控制台→裝置管理員, 務必查看 Arduino 主板被設定在 COM?,因為每台電腦均不同。
註 2:若驅動程式無法正常安裝,則在 Arduino 桌面的捷徑按右鍵→內容→開啟檔案位置,到驅動程式 drivers 資料夾執行dpinst-x86.exe,若還是不行有可能是 USB 供電不穩,請同時插入 5V 電源即可。
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
註 3:第一次使用需要到Tools(工具)→Serial Port(串列埠)去設定硬體的COM 為?(每台電腦均不同,需
到裝置管理員查詢),以及 Arduino 主板的硬體類型,方可進行燒寫。若裝置管理員可以看到,但 Tools 卻偵測不到,需解除安裝再拔除,然後插入重安裝,實際測試有時要好幾次才會成功?
李奧納多
6
註 4:Arduino 的燒錄動作稱為Uploading(上傳中),設定完畢即可按下『→』鍵上傳(Upload)燒錄。
若 Arduino 功能正常(啟用約需 10 秒才開始),在電源指示燈上方的 LED 會每間隔 1 秒進行閃爍。
※ 內部 Pin13 已經直接連接到該 LED,所以可以直接測試 Arduino 主板。
※ 亦可再另外並接 LED 於 Pin13 與 GND 測試之間,然後再改用其他 Pin 腳測試。 ※ 腳位若有標示『~』,表示可做PWM(Pulse Width Modulation 脈波寬度調變)的運用。
Arduino 程式架構介紹,很像 C 語言,/*……..*/中間為註解或直接用//表示註解,每句指令結束需用『分 號;』,若有多行區塊,須利用大括號{..…},在 VB 程式碼是不分大小寫,但 Arduino 程式和 C 語言都是 有區分大小寫,例如:內建常數就一定要大寫方可。 ※ 若想查詢某一指令說明,可利用http://arduino.cc/en/Reference/HomePage。 ※ setup( ) -初始化函式,程式啟動時僅被呼叫一次。 loop( ) -主迴圈函式,會不斷被執行。 名稱定義(或直接輸入) 宣告腳位為輸出/入 主程式,利用無窮迴圈 每延遲 1 秒改變輸出值
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()
< (小於) 、 > (大於) <= (小於等於) 、 >= (大於等於) 布林運算子 && (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
實驗 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);
} }
12
實驗 4:練習同時控制多顆LED 與『讀取類比輸入值』。
File→Examples→07.Display→barGraph (※利用可變電阻分壓,LED 當電量%顯示)。
實驗 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
實驗 7:練習利用 PWM 控制 Servo (伺服電動機= servomotor)。
執行 Arduino 捷徑,File→Examples→Servo→Sweep(原為打掃涵義,實際測試為左右搖擺動作)。
硬體接線方式可到http://arduino.cc/ 下的Learning(學習)→Exapmles(範例),利用Ctrl+F尋找 Servo 關 鍵字,找到『Sweep』單字點擊即可查看相關資料,包括硬體接線方式。
#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 綜合實驗 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) { //當按鈕按下
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
綜合實驗 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); //停止發出聲音
} } }
實驗 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
建議先定義腳位名稱→定義pingecho 為輸入腳→讀取 pingecho 高準位訊號寬度。
※利用Notepad++免費軟體,方便查看(點擊 2 下)程式變數或副程式使用狀況
由於是利用 pin13 接收高準位訊號寬度,而 pin13 已經接 LED,所以透過查看 LED 閃爍速度即可測試超 音波感測器好壞,但距離是多少?可用右上角內部終端機查看,除了內建的終端機,XP 有內建,但 Windows7 卻沒有,可自行免費下載TeraTerm軟體安裝
(※執行 setup.exe 安裝,然後須設定串列埠 COM 是第幾個?)
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
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 泰山高中電子科陳致中老師 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 手機電池 溫度感測 量測電池 超音波
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 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);
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 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,進行下一位元的處理 } }
泰山高中電子科陳致中老師 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 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;
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 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
4. 手機 App 搜尋『藍芽串口助手』,操作與設定請參閱下圖 (※第一次藍芽配對會出現 Null)
→ → →
→ → →
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()); }
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
補充:若想用較便宜的 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. 看到右側訊息表示成功 ,若看到右側訊息表示失敗
泰山高中電子科陳致中老師 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 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 週)
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
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)); }
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 泰山高中電子科陳致中老師 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(); // 調整亮度
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
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); }
補充資料 1:利用免安裝Fritzing.exe程式繪製電路圖,檔案→開啟範例→Arduino裡面有許多現成範例。
補充資料 2:視覺化設計環境 Ardublock (利用拼圖直覺式寫程式) 下載 http://sourceforge.net/projects/ardublock/files
46 需到 C:\Users\user\Documents\Arduino 目錄自行新增
『tools/ArduBlockTool/tool』資料夾(名稱大小寫須完
全相同),再將下載的 xxx.jar 放到該資料夾,重新開啟 Arduino 主程式,即可在 tools 下拉式找到 ArduBlock, 圖形化程式編輯完後按『上傳』,即可變成對應的程式 碼,對於指令不孰悉或初學者是很不錯選擇,但是比 較複雜的程式,還是建議學習程式語言。
/*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 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;}
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 高電位