文章目錄
一、結構
1.1 setup()
在Arduino中程序運行時將首先調用 setup() 函數。用於(yu) 初始化變量、設置針腳的輸出\輸入類型、配置串口、引入類庫文件等等。每次 Arduino板子 上電或重啟後,setup 函數隻運行一次。
int buttonPin = 3; void setup() { Serial.begin(9600); pinMode(buttonPin, INPUT); } void loop() { // ... }
1.2 loop()
在 setup() 函數中初始化和定義(yi) 了變量,然後執行 loop() 函數。顧名思義(yi) ,該函數在程序運行過程中不斷的循環,根據一些反饋,相應改變執行情況。通過該函數動態控製 Arduino 主控板。
int buttonPin = 3; // setup 中初始化串口和按鍵針腳. void setup() { beginSerial(9600); pinMode(buttonPin, INPUT); } // loop 中每次都檢查按鈕,如果按鈕被按下,就發送信息到串口 void loop() { if (digitalRead(buttonPin) == HIGH) serialWrite('H'); else serialWrite('L'); delay(1000); }
二、結構控製
結構控製這一塊和C語言類似,就是控製程序執行流程的分支、循環、順序結構的一些特定語法。
熟悉C語言的話,這塊不用過一眼就好。
2.1 if
if(條件判斷語句)和 ==、!=、<、>(比較運算符)
if 語句與(yu) 比較運算符一起用於(yu) 檢測某個(ge) 條件是否達成,如某輸入值是否在特定值之上等。if 語句的語法是:
if (someVariable > 50) { // 執行某些語句 }
本程序測試 someVariable 變量的值是否大於(yu) 50。當大於(yu) 50 時,執行一些語句。換句話說,隻要 if 後麵括號裏的結果(稱之為(wei) 測試表達式)為(wei) 真,則執行大括號中的語句(稱之為(wei) 執行語句塊);若為(wei) 假,則跳過大括號中的語句。 if 語句後的大括號可以省略。若省略大括號,則隻有一條語句(以分號結尾)成為(wei) 執行語句。
if (x > 120) digitalWrite(LEDpin, HIGH); if (x > 120) digitalWrite(LEDpin, HIGH); if (x > 120){ digitalWrite(LEDpin, HIGH); } if (x > 120){ digitalWrite(LEDpin1, HIGH); digitalWrite(LEDpin2, HIGH); } // 以上所有書(shu) 寫(xie) 方式都正確
在小括號裏求值的表達式,需要以下操作符:
比較運算操作符:
x == y(x 等於(yu) y)
x != y(x 不等於(yu) y)
x < y(x 小於(yu) y)
x > y(x 大於(yu) y)
x <= y(x 小於(yu) 等於(yu) y)
x >= y(x 大於(yu) 等於(yu) y)
警告:
注意使用賦值運算符的情況(如 if (x = 10))。一個(ge) “=”表示的是賦值運算符,作用是將 x 的值設為(wei) 10(將值 10 放入 x 變量的內(nei) 存中)。兩(liang) 個(ge) “=”表示的是比較運算符(如 if (x == 10)),用於(yu) 測試 x 和 10 是否相等。後麵這個(ge) 語句隻有 x 是 10 時才為(wei) 真,而前麵賦值的那個(ge) 語句則永遠為(wei) 真。
這是因為(wei) C 語言按以下規則進行運算 if (x=10):10 賦值給 x(隻要非 0 的數賦值的語句,其賦值表達式的值永遠為(wei) 真),因此 x 現在值為(wei) 10。此時 if 的測試表達式值為(wei) 10,該值永遠為(wei) 真,因為(wei) 非 0 值永遠為(wei) 真。所以,if (x = 10) 將永遠為(wei) 真,這就不是我們(men) 運行 if 所期待的結果。另外,x 被賦值為(wei) 10,這也不是我們(men) 所期待的結果。
if 的另外一種分支條件控製結構是 if…else 形式。
2.2 if…else
if/else是比if更為(wei) 高級的流程控製語句,它可以進行多次條件測試。比如,檢測模擬輸入的值,當它小於(yu) 500時該執行哪些操作,大於(yu) 或等於(yu) 500時執行另外的操作。代碼如下:
if (pinFiveInput < 500) { // 執行A操作 } else { // 執行B操作 }
else可以進行額外的if檢測,所以多個(ge) 互斥的條件可以同時進行檢測。
測試將一個(ge) 一個(ge) 進行下去,直到某個(ge) 測試結果為(wei) 真,此時該測試相關(guan) 的執行語句塊將被運行,然後程序就跳過剩下的檢測,直接執行到if/else的下一條語句。當所有檢測都為(wei) 假時,若存在else語句塊,將執行默認的else語句塊。
注意else if語句塊可以沒有else語句塊。else if分支語句的數量無限製。
if (pinFiveInput < 500) { // 執行A操作 } else if (pinFiveInput >= 1000) { // 執行B操作 } else { // 執行C操作 }
另外一種進行多種條件分支判斷的語句是switch case語句。
2.3 switch case
switch / case語句
和if語句相同,switch…case通過程序員設定的在不同條件下執行的代碼控製程序的流程。特別地,switch語句將變量值和case語句中設定的值進行比較。當一個(ge) case語句中的設定值與(yu) 變量值相同時,這條case語句將被執行。
關(guan) 鍵字break可用於(yu) 退出switch語句,通常每條case語句都以break結尾。如果沒有break語句,switch語句將會(hui) 一直執行接下來的語句(一直向下)直到遇見一個(ge) break,或者直到switch語句結尾。
例子
switch (var) {case 1: //當var等於(yu) 1時,執行一些語句 break; case 2 //當var等於(yu) 2時,執行一些語句 break; default: //如果沒有任何匹配,執行default //default可有可不有 }
語法
switch (var) {case label: // 聲明 break; case label: // 聲明 break; default: // 聲明 }
參數
var: 用於(yu) 與(yu) 下麵的case中的標簽進行比較的變量值
label: 與(yu) 變量進行比較的值
2.4 for
for語句
描述
for語句用於(yu) 重複執行一段在花括號之內(nei) 的代碼。通常使用一個(ge) 增量計數器計數並終止循環。for語句用於(yu) 重複性的操作非常有效,通常與(yu) 數組結合起來使用來操作數據、引腳。
for循環開頭有3個(ge) 部分:
(初始化;條件;增量計數){
//語句
}
“初始化”隻在循環開始執行一次。每次循環,都會(hui) 檢測一次條件;如果條件為(wei) 真,則執行語句和“增量計數”,之後再檢測條件。當條件為(wei) 假時,循環終止。
例子
//用PWM引腳將LED變暗 int PWMpin = 10; //將一個(ge) LED與(yu) 47Ω電阻串聯接在10腳 void setup() {//無需設置 } void loop() { for (int i=0; i <= 255; i++) { analogWrite(PWMpin, i); delay(10); } }
編程提示
C語言的for循環語句比BASIC和其他電腦編程語言的for語句更靈活。除了分號以外,其他3個(ge) 元素都能省略。同時,初始化,條件,增量計算可以是任何包括無關(guan) 變量的有效C語句,任何C數據類型包括float。這些不尋常的for語句可能會(hui) 解決(jue) 一些困難的編程問題。
例如,在增量計數中使用乘法可以得到一個(ge) 等比數列:
for(int x = 2; x < 100; x = x * 1.5){ println(x); }
生成:2,3,4,6,9,13,19,28,42,63,94
另一個(ge) 例子,使用for循環使LED產(chan) 生漸亮漸滅的效果:
void loop() { int x = 1; for (int i = 0; i > -1; i = i + x) { analogWrite(PWMpin, i); if (i == 255) x = -1; // 在峰值轉變方向 delay(10); } }
2.5 while
while循環
描述
while循環會(hui) 無限的循環,直到括號內(nei) 的判斷語句變為(wei) 假。必須要有能改變判斷語句的東(dong) 西,要不然while循環將永遠不會(hui) 結束。這在您的代碼表現為(wei) 一個(ge) 遞增的變量,或一個(ge) 外部條件,如傳(chuan) 感器的返回值。
語法
while(表達){
//語句
}
參數
表達:為(wei) 真或為(wei) 假的一個(ge) 計算結果
例子
var = 0; while(var < 200){//重複一件事200遍 var++ }
2.6 do…while
do…while循環與(yu) while循環運行的方式是相近的,不過它的條件判斷是在每個(ge) 循環的最後,所以這個(ge) 語句至少會(hui) 被運行一次,然後才被結束。
do
{
//語句
}while(測試條件);
例子
do{ delay(50); //等待傳(chuan) 感器穩定 X = readSensors(); //檢查傳(chuan) 感器取值 }while(X <100); //當x小於(yu) 100時,繼續運行
2.7 break
break用於(yu) 退出do,for,while 循環,能繞過一般的判斷條件。它也能夠用於(yu) 退出 switch語句。
例子
for (x = 0; x < 255; x ++) { digitalWrite(PWMpin, x); sens = analogRead(sensorPin); if (sens > threshold){ // 超出探測範圍 x = 0; break; } delay(50); }
2.8 continue
continue語句跳過當前循環中剩餘(yu) 的迭代部分( do,for 或 while )。它通過檢查循環條件表達式,並繼續進行任何後續迭代。
例子
for (x = 0; x < 255; x ++) { if (x > 40 && x < 120){ // 當x在40與(yu) 120之間時,跳過後麵兩(liang) 句,即迭代。 continue; } digitalWrite(PWMpin, x); delay(50); }
2.9 return
終止一個(ge) 函數,如有返回值,將從(cong) 此函數返回給調用函數。
語法
return;
return value; // 兩(liang) 種形式均可
參數
value:任何變量或常量的類型
例子
一個(ge) 比較傳(chuan) 感器輸入閾值的函數
int checkSensor(){ if (analogRead(0) > 400) { return 1;} else{ return 0; } }
return關(guan) 鍵字可以很方便的測試一段代碼,而無需“comment out(注釋掉)” 大段的可能存在bug的代碼。
void loop(){ //寫(xie) 入漂亮的代碼來測試這裏。 return; //剩下的功能異常的程序 //return後的代碼永遠不會(hui) 被執行 }
2.10 goto
程序將會(hui) 從(cong) 程序中已有的標記點開始運行
語法
label:
goto label; //從(cong) label處開始運行
提示
不要在C語言中使用goto編程,某些C編程作者認為(wei) goto語句永遠是不必要的,但用得好,它可以簡化某些特定的程序。許多程序員不同意使用goto的原因是, 通過毫無節製地使用goto語句,很容易創建一個(ge) 程序,這種程序擁有不確定的運行流程,因而無法進行調試。
的確在有的實例中goto語句可以派上用場,並簡化代碼。例如在一定的條件用if語句來跳出高度嵌入的for循環。
例子
for(byte r = 0; r < 255; r++){ for(byte g = 255; g > -1; g--){ for(byte b = 0; b < 255; b++){ if (analogRead(0) > 250){ goto bailout; } //更多的語句... } } } bailout:
三、擴展語法
3.1 ;(分號)
用於(yu) 表示一句代碼的結束。
例子
int a = 13;
提示
在每一行忘記使用分號作為(wei) 結尾,將導致一個(ge) 編譯錯誤。錯誤提示可能會(hui) 清晰的指向缺少分號的那行,也可能不會(hui) 。如果彈出一個(ge) 令人費解或看似不合邏輯的編譯器錯誤,第一件事就是在錯誤附近檢查是否缺少分號。
3.2 {}(花括號)
大括號(也稱為(wei) “括號”或“大括號”)是C編程語言中的一個(ge) 重要組成部分。它們(men) 被用來區分幾個(ge) 不同的結構,下麵列出的,有時可能使初學者混亂(luan) 。
左大括號“{”必須與(yu) 一個(ge) 右大括號“}”形成閉合。這是一個(ge) 常常被稱為(wei) 括號平衡的條件。在Arduino IDE(集成開發環境)中有一個(ge) 方便的功能來檢查大括號是否平衡。隻需選擇一個(ge) 括號,甚至單擊緊接括號的插入點,就能知道這個(ge) 括號的“伴侶(lv) 括號”。
目前此功能稍微有些錯誤,因為(wei) IDE會(hui) 經常會(hui) 認為(wei) 在注釋中的括號是不正確的。
由於(yu) 大括號被用在不同的地方,這有一種很好的編程習(xi) 慣以避免錯誤:輸入一個(ge) 大括號後,同時也輸入另一個(ge) 大括號以達到平衡。然後在你的括號之間輸入回車,然後再插入語句。這樣一來,你的括號就不會(hui) 變得不平衡了。不平衡的括號常可導致許多錯誤,比如令人費解的編譯器錯誤,有時很難在一個(ge) 程序找到這個(ge) 錯誤。由於(yu) 其不同的用法,括號也是一個(ge) 程序中非常重要的語法,如果括號發生錯誤,往往會(hui) 極大地影響了程序的意義(yi) 。
大括號中的主要用途
功能
void myfunction(datatype argument){ statements(s) }
循環
while (boolean expression) { statement(s) } do { statement(s) } while (boolean expression); for (initialisation; termination condition; incrementing expr) { statement(s) }
條件語句
if (boolean expression) { statement(s) } else if (boolean expression) { statement(s) } else { statement(s) }
3.3 //(單行注釋)
Comments(注釋)
注釋用於(yu) 提醒自己或他人程序是如何工作的。它們(men) 會(hui) 被編譯器忽略掉,也不會(hui) 傳(chuan) 送給處理器,所以它們(men) 在Atmega芯片上不占用體(ti) 積。 注釋的唯一作用就是使你自己理解或幫你回憶你的程序是怎麽(me) 工作的或提醒他人你的程序是如何工作的。編寫(xie) 注釋有兩(liang) 種寫(xie) 法:
例子
x = 5; // 這是一條注釋斜杠後麵本行內(nei) 的所有東(dong) 西是注釋 /* 這是多行注釋-用於(yu) 注釋一段代碼 if (gwb == 0){ // 在多行注釋內(nei) 可使用單行注釋 x = 3; /* 但不允許使用新的多行注釋-這是無效的 } // 別忘了注釋的結尾符號-它們(men) 是成對出現的! */
小提示
當測試代碼的時候,注釋掉一段可能有問題的代碼是非常有效的方法。這能使這段代碼成為(wei) 注釋而保留在程序中,而編譯器能忽略它們(men) 。這個(ge) 方法用於(yu) 尋找問題代碼或當編譯器提示出錯或錯誤很隱蔽時很有效。
3.4 /* */(多行注釋)
3.5 #define
#define 是一個(ge) 很有用的C語法,它允許程序員在程序編譯之前給常量命名。在Arduino中,定義(yi) 的常量不會(hui) 占用芯片上的任何程序內(nei) 存空間。在編譯時編譯器會(hui) 用事先定義(yi) 的值來取代這些常量。
然而這樣做會(hui) 產(chan) 生一些副作用,例如,一個(ge) 已被定義(yi) 的常量名已經包含在了其他常量名或者變量名中。在這種情況下,文本將被#defined 定義(yi) 的數字或文本所取代。
通常情況下,優(you) 先考慮使用 const 關(guan) 鍵字替代 #define 來定義(yi) 常量。
Arduino 擁有和 C 相同的語法規範。
語法
#define 常量名 常量值 注意,#是必須的。
例子
#define ledPin 3 //在編譯時,編譯器將使用數值 3 取代任何用到 ledPin 的地方。 提示 在#define 聲明後不能有分號。如果存在分號,編譯器會(hui) 拋出語義(yi) 不明的錯誤,甚至關(guan) 閉頁麵。 #define ledPin 3; //這是一種錯誤寫(xie) 法 類似的,在#define聲明中包含等號也會(hui) 產(chan) 生語義(yi) 不明的編譯錯誤從(cong) 而導致關(guan) 閉頁麵。 #define ledPin = 3 //這是一種錯誤寫(xie) 法
3.6 #include
#include用於(yu) 調用程序以外的庫。這使得程序能夠訪問大量標準C庫,也能訪問用於(yu) arduino的庫。 AVR C庫(Arduino基於(yu) AVR標準語法)語法手冊(ce) 請點擊這裏。 注意#include和#define一樣,不能在結尾加分號,如果你加了分號編譯器將會(hui) 報錯。
例子
此例包含了一個(ge) 庫,用於(yu) 將數據存放在flash空間內(nei) 而不是ram內(nei) 。這為(wei) 動態內(nei) 存節約了空間,大型表格查表更容易實現。
#include <avr/pgmspace.h> prog_uint16_t myConstants[] PROGMEM = { 0, 21140, 702 , 9128, 0, 25764, 8456,0,0,0,0,0,0,0,0,29810,8968,29762,29762,4500};