關於Arduino的歷史、定位、功能等等的介紹,維基百科已有很詳細的闡述,建議初學者都去看看,能對Arduino有更深入了解。本文基於Getting Started With Arduino(建議初學者購買),重點連載從零開始學習Arduino的基礎編程知識和詳細程序實現,只針對剛拿到Arduino但基本無編程經驗的同學,高手請繞行。
NO.1:點亮你的第一個LED燈
打開Arduino IDE,新建Sketch,參考以下代碼,重點請看注釋部分:
#define LED 13 //定義D13為LED正極口,將LED燈連接到板子上D12引腳void setup() //此函數代碼只會在程序剛開始時執行一次{ pinMode(LED, OUTPUT); //定義LED也就是D13引腳模式為輸出}void loop() //此程序在會Arduino通電後反覆執行{ digitalWrite(LED, HIGH); //輸出13引腳信號為HIGH即高電平,開 delay(1000); //持續1S digitalWrite(LED, LOW); //輸出13引腳信號為LOW即低電平,關 delay(1000); //持續1S}
將此代碼上傳至Arduino並連接好LED燈,你就可以看到LED在閃爍。
NO.2 添加開關來控制LED(GND端串聯10K歐姆電阻,+5V)
#define LED 13 //定義LED引腳為D13#define BUTTON 7 //定義開關BUTTON引腳為D7int val = 0; //變量val,並賦值0,用來存儲按鈕狀態void setup(){ pinMode(LED, OUTPUT); //LED引腳設置為輸出模式 pinMode(BUTTON, INPUT); //BUTTON引腳設置為輸入模式}void loop(){ val = digitalRead(BUTTON); //讀取BUTTON數值 if (val == HIGH)//當val為HIGH的情況下 { digitalWrite(LED,HIGH); //點亮LED }else{ digitalWrite(LED, LOW); //關閉LED }}
上傳看看效果。
NO.3:打開按鈕後LED常亮
#define LED 13 //定義LED引腳為D13#define BUTTON 7 //定義開關BUTTON引腳為D7int val = 0; //變量val,並賦值0,用來存儲按鈕狀態int state = 0; //變量state,定義0表示關閉,1表示打開void setup(){ pinMode(LED, OUTPUT); //LED引腳設置為輸出模式 pinMode(BUTTON, INPUT); //BUTTON引腳設置為輸入模式}void loop(){ val = digitalRead(BUTTON); //讀取BUTTON數值 if (val == HIGH) //當val為HIGH的情況下 { state = 1 - state; } if(state == 1) { digitalWrite(LED, HIGH); //打開LED }else{ digitalWrite(LED, LOW); //LED關閉狀態 }}
上傳看效果,你會發現會出現當你按開關LED燈關閉的問題,原因是程序中使用變量state儲存0或者1來記憶燈的狀態,當按下按鈕時,state已被賦值為1,所以當Arduino再去讀取開關狀態時,當開關狀態為HIGH,此時state被再次賦值為0,為關閉狀態。
這其實是程序設計缺陷,如果來解決?繼續往下:
#define LED 13 //定義LED引腳為D13#define BUTTON 7 //定義開關BUTTON引腳為D7int val = 0; //變量val,並賦值0,用來存儲按鈕狀態int old_val = 0; //存儲變量val的上一個值int state = 0; //變量state,定義0表示關閉,1表示打開void setup(){ pinMode(LED, OUTPUT); //LED引腳設置為輸出模式 pinMode(BUTTON, INPUT); //BUTTON引腳設置為輸入模式}void loop(){ val = digitalRead(BUTTON); //讀取BUTTON數值 if ((val == HIGH) &&(old_val == LOW)) //當val為HIGH並且old_val為LOW的情況下 { state = 1 - state; } old_val = val; //val此時已經是舊的了,讓數值賦給old_var if(state == 1) { digitalWrite(LED, HIGH); //打開LED }else{ digitalWrite(LED, LOW); //LED關閉狀態 }}
寫到此時,我已完全被LED燈閃瞎了眼。程序依然沒有正常工作!現在的問題是由於按鈕的機械構造造成的,按鈕由兩片金屬的接觸實現電路的導通,在現實中,金屬之間的接觸並不是完全密合,尤其是金屬尚未到底的瞬間和按鈕彈回的時候,會產生雜波。
當雜波出現的時候,Arduino會接受到一連串開關交錯的信號。要克服這個雜波,有幾種不通方式,對上邊的簡單程序來講,只需要在程序中加入10~50毫秒的延遲指令就可以改善。參考以下代碼:
#define LED 13 //定義LED引腳為D13#define BUTTON 7 //定義開關BUTTON引腳為D7int val = 0; //變量val,並賦值0,用來存儲按鈕狀態int old_val = 0; //存儲變量val的上一個值int state = 0; //變量state,定義0表示關閉,1表示打開void setup(){ pinMode(LED, OUTPUT); //LED引腳設置為輸出模式 pinMode(BUTTON, INPUT); //BUTTON引腳設置為輸入模式}void loop(){ val = digitalRead(BUTTON); //讀取BUTTON數值 if ((val == HIGH) &&(old_val == LOW)) //當val為HIGH並且old_val為LOW的情況下 { state = 1 - state; delay(50); } old_val = val; //val此時已經是舊的了,讓數值賦給old_var if(state == 1) { digitalWrite(LED, HIGH); //打開LED }else{ digitalWrite(LED, LOW); //LED關閉狀態 }}
NO.4:使用PWM的方式來控制LED燈亮度
PWM被成為脈衝寬度調製,如果我們改變延遲函數的數值,直到你看不出LED燈亮和滅的時間間隔為止,你會發現LED燈亮度只有原來的50%,如果繼續改變時間間隔,你會發現燈的亮度只有原來的25%。這就是PWM。
Arduino電路板上使用的處理器可以在處理其他事情的同時點亮3各LED使其閃爍,這部分PWM輸出接口為D9、D10、D11,這3個輸出接口可以由analogWrite()函數控制。analogwrite()指令中PWM參數的可設範圍為0~255,255代表最亮,0代表最暗,如果你使用analogwrite(9, 128)則代表D9引腳接的LED燈亮度為50%。
逐漸改變亮度的LED燈(使用LED等串聯一個470~1K歐姆的電阻,並接到D9引腳,負極接GND):
#define LED 9 //定義LED為D9引腳int i = 0; //定義變量i,用來從上到下計數void setup(){ pinMode(LED,OUTPUT); //LED為輸出}void loop(){ for(i = 0; i < 255 ; i++){ //循環255次,從小到大 analogWrite(LED, i); //PWM參數,亮度從小到大 delay(10); //延遲10毫秒,因為anaWrite()參數執行瞬間完成 } for(i = 255; i > 0; i--){ //循環255次,從大到小 analogWrite(LED, i); //PWM參數,兩大從大到小 delay(10); //延遲10毫秒 }}
上傳看看,是不是很神奇?
NO.5:按下松下按鈕開關LED,長按開關調節LED燈亮度(NO.2+NO.4兩個小電路積木結合)
#define LED 9 // 定義LED為D9引腳#define BUTTON 7 //定義按鈕為D7引腳int val = 0; //變量val存儲按鈕數值狀態int old_val = 0; //存儲val的上一個數值int state = 0; //0為關閉LED,1為打開LEDint brightness = 128; //存儲亮度值unsigned long startTime = 0; //存儲按下按鈕的開始時間void setup() { pinMode(LED, OUTPUT); //LED引腳為輸出 pinMode(BUTTON, INPUT); //BUTTON引腳為輸入}void loop() { val = digitalRead(BUTTON); //讀取按鈕數值並存儲到val變量 if ((val == HIGH) && (old_val == LOW)) { state = 1 - state; startTime = millis(); // millis()是Arduino的時鐘,存儲最後一次按下按鈕的時間,單位毫秒 delay(10); } if ((val == HIGH) && (old_val == HIGH)) { if (state == 1 && (millis() - startTime) > 500) { //如果按鈕被按了超過500毫秒 brightness++; // 亮度值遞增 delay(10); if (brightness > 255) { //如果亮度值超出255 brightness = 0; //重置亮度為0 } } }old_val = val; //執行了一次之後,val已變成舊值,存儲到old_valif (state == 1) { analogWrite(LED, brightness); //以當前亮度值打開LED }else{ analogWrite(LED, 0); //關閉LED }}
是不是很酷?當然,你可以嘗試把開關換成其他敏感元件,如光敏電阻、熱敏電阻等其他傳感器,來製作更有趣的場景。
以上我們進行的都是基於數字I/O引腳的試驗,接下來開始嘗試模擬I/O引腳(模擬引腳默認為輸入狀態)。模擬輸入引腳analog in不僅可以讀出是否有電壓輸入(數字引腳只能讀出有或無),還能讀出電壓值的大小。我們使用analogRead()函數來讀取輸入電壓值,該參數的返回值範圍為0~1023,分別對應0~5V間的電壓。如,在模擬口輸入2.5V電壓,analogRead()返回的值為512。以下開始模擬口的嘗試:
NO.6:根據模擬輸入值大小來設定LED閃爍頻率
硬體環境需要先使用光敏電阻串聯10K歐姆電阻,串聯電阻一端接GND,一端接5V引腳,同時,在10K歐姆電阻的並聯方向引出A0引腳接口。LED燈正極接D13,負極串聯1K歐姆電阻接GND。
#define LED 13 //定義D13引腳為LEDint val = 0; //變量val,存儲模擬口讀取的數值void setup(){ pinMode(LED,OUTPUT); //LED為輸出}void loop(){ val = analogRead(0); //讀取A0並賦值給val digitalWrite(LED,HIGH); //點亮LED delay(val); //延遲時間為val的數值 digitalWrite(LED,LOW); //關閉LED delay(val); //延遲時間為val的數值}
一閃一閃亮晶晶!
NO.7:根據模擬輸入值來調整LED燈亮度
#define LED 9 //定義D9引腳為LED,D9為PWM引腳int val = 0; //變量val,存儲模擬口讀取的數值void setup(){ pinMode(LED,OUTPUT); //LED為輸出}void loop(){ val = analogRead(0); //讀取A0並賦值給val analogWrite(LED, val/4); //PWM輸出最大值為255 delay(10); //延遲10毫秒}
有了上邊的編程基礎,你可以變換出任意的積木式組合、擴展性場景。
接下來看下Arduino的串口通信,通過串口通信,我們可以讓Arduino和計算機或其他控制機之間互相通信,讓Arduino把數據傳回計算機,並能接收來自計算機的指令。要實現這一功能,可以在Arduino程序中通過Serail()函數,此函數包含了串口通信所需的所有程序代碼。
NO.8:從計算機串口讀取Arduino模擬傳感器輸入數據
硬體環境依照NO.7的光敏電阻電路,程序如下:
#define SERSOR 0 //定義傳感器輸入口為A0int val = 0; //變量val來存儲讀取的數值void setup(){ Serial.begin(9600); //打開串口並設置通信波特率為9600}void loop(){ val = analogRead(0); //從A0讀取傳感器反饋值並賦值給val Serial.println(val); //串口監視窗口顯示傳感器的反饋值 delay(100); //每100毫秒發送一次數據}
上傳至Arduino,在Arduino工具菜單的串口監視窗口打開看看,你所看到的值可以通過0~5V換算成電壓,根據各傳感器的Datasheet,可以得出你想要的現實環境中的某項數值。