Arduino編程參考手冊(cè)
首頁(yè)
程序結(jié)構(gòu)
(本節(jié)直譯自Arduino官網(wǎng)最新Reference)
在Arduino中, 標(biāo)準(zhǔn)的程序入口main函數(shù)在內(nèi)部被定義, 用戶只需要關(guān)心以下兩個(gè)函數(shù):
setup()
當(dāng)Arduino板起動(dòng)時(shí)setup()函數(shù)會(huì)被調(diào)用。用它來(lái)初始化變量,引腳模式,開始使用某個(gè)庫(kù),等等。該函數(shù)在Arduino板的每次上電和復(fù)位時(shí)只運(yùn)行一次。
loop()
在創(chuàng)建setup函數(shù),該函數(shù)初始化和設(shè)置初始值,loop()函數(shù)所做事的正如其名,連續(xù)循環(huán),允許你的程序改變狀態(tài)和響應(yīng)事件。可以用它來(lái)實(shí)時(shí)控制arduino板。
示例:
int buttonPin = 3; void setup() { Serial.begin(9600); //初始化串口 pinMode(buttonPin, INPUT); //設(shè)置3號(hào)引腳為輸入模式 } void loop() { if (digitalRead(buttonPin) == HIGH) serialWrite('H'); else serialWrite('L'); delay(1000); }
控制語(yǔ)句
if
if,用于與比較運(yùn)算符結(jié)合使用,測(cè)試是否已達(dá)到某些條件,例如一個(gè)輸入數(shù)據(jù)在某個(gè)范圍之外。使用格式如下:
if (value > 50) { // 這里加入你的代碼 }
該程序測(cè)試value是否大于50。如果是,程序?qū)?zhí)行特定的動(dòng)作。換句話說(shuō),如果圓括號(hào)中的語(yǔ)句為真,大括號(hào)中的語(yǔ)句就會(huì)執(zhí)行。如果不是,程序?qū)⑻^(guò)這段代碼。大括號(hào)可以被省略,如果這么做,下一行(以分號(hào)結(jié)尾)將成為唯一的條件語(yǔ)句。
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); } // 都是正確的
圓括號(hào)中要被計(jì)算的語(yǔ)句需要一個(gè)或多個(gè)操作符。
if...else
與基本的if語(yǔ)句相比,由于允許多個(gè)測(cè)試組合在一起,if/else可以使用更多的控制流。例如,可以測(cè)試一個(gè)模擬量輸入,如果輸入值小于500,則采取一個(gè)動(dòng)作,而如果輸入值大于或等于500,則采取另一個(gè)動(dòng)作。代碼看起來(lái)像是這樣:
if (pinFiveInput < 500) { // 動(dòng)作A } else { // 動(dòng)作B }
else中可以進(jìn)行另一個(gè)if測(cè)試,這樣多個(gè)相互獨(dú)立的測(cè)試就可以同時(shí)進(jìn)行。每一個(gè)測(cè)試一個(gè)接一個(gè)地執(zhí)行直到遇到一個(gè)測(cè)試為真為止。當(dāng)發(fā)現(xiàn)一個(gè)測(cè)試條件為真時(shí),與其關(guān)聯(lián)的代碼塊就會(huì)執(zhí)行,然后程序?qū)⑻酵暾膇f/else結(jié)構(gòu)的下一行。如果沒有一個(gè)測(cè)試被驗(yàn)證為真。缺省的else語(yǔ)句塊,如果存在的話,將被設(shè)為默認(rèn)行為,并執(zhí)行。
注意:一個(gè)else if語(yǔ)句塊可能有或者沒有終止else語(yǔ)句塊,同理。每個(gè)else if分支允許有無(wú)限多個(gè)。
if (pinFiveInput < 500) { // 執(zhí)行動(dòng)作A } else if (pinFiveInput >= 1000) { // 執(zhí)行動(dòng)作B } else { // 執(zhí)行動(dòng)作C }
另外一種表達(dá)互斥分支測(cè)試的方式,是使用switch case語(yǔ)句。
for
for語(yǔ)句
描述
for語(yǔ)句用于重復(fù)執(zhí)行被花括號(hào)包圍的語(yǔ)句塊。一個(gè)增量計(jì)數(shù)器通常被用來(lái)遞增和終止循環(huán)。for語(yǔ)句對(duì)于任何需要重復(fù)的操作是非常有用的。常常用于與數(shù)組聯(lián)合使用以收集數(shù)據(jù)/引腳。for循環(huán)的頭部有三個(gè)部分:
for (初始化部分; 條件判斷部分; 數(shù)據(jù)遞增部分) { //語(yǔ)句塊 。。。 }
初始化部分被第一個(gè)執(zhí)行,且只執(zhí)行一次。每次通過(guò)這個(gè)循環(huán),條件判斷部分將被測(cè)試;如果為真,語(yǔ)句塊和數(shù)據(jù)遞增部分就會(huì)被執(zhí)行,然后條件判斷部分就會(huì)被再次測(cè)試,當(dāng)條件測(cè)試為假時(shí),結(jié)束循環(huán)。
示例:
//使用一個(gè)PWM引腳使LED燈閃爍 int PWMpin = 10; // LED在10號(hào)引腳串聯(lián)一個(gè)470歐姆的電阻 void setup() { //這里無(wú)需設(shè)置 } void loop() { for (int i=0; i <= 255; i++){ analogWrite(PWMpin, i); delay(10); } }
編碼提示:
C中的for循環(huán)比在其它計(jì)算機(jī)語(yǔ)言中發(fā)現(xiàn)的for循環(huán)要靈活的多,包括BASIC。三個(gè)頭元素中的任何一個(gè)或全部可能被省略,盡管分號(hào)是必須的。而且初始化部分、條件判斷部分和數(shù)據(jù)遞增部分可以是任何合法的使用任意變量的C語(yǔ)句。且可以使用任何數(shù)據(jù)類型包括floats。這些不常用的類型用于語(yǔ)句段也許可以為一些罕見的編程問(wèn)題提供解決方案。
例如,在遞增部分中使用一個(gè)乘法將形成對(duì)數(shù)級(jí)增長(zhǎng):
for(int x = 2; x < 100; x = x * 1.5){ println(x); }
輸出: 2,3,4,6,9,13,19,28,42,63,94
另一個(gè)例子,在一個(gè)for循環(huán)中使一個(gè)LED燈漸漸地變亮和變暗:
void loop() { int x = 1; for (int i = 0; i > -1; i = i + x){ analogWrite(PWMpin, i); if (i == 255) x = -1; // 在峰值切換方向 delay(10); } }
switch case
switch case 語(yǔ)句
就像if語(yǔ)句,switch...case通過(guò)允許程序員根據(jù)不同的條件指定不同的應(yīng)被執(zhí)行的代碼來(lái)控制程序流。特別地,一個(gè)switch語(yǔ)句對(duì)一個(gè)變量的值與case語(yǔ)句中指定的值進(jìn)行比較。當(dāng)一個(gè)case語(yǔ)句被發(fā)現(xiàn)其值等于該變量的值。就會(huì)運(yùn)行這個(gè)case語(yǔ)句下的代碼。
break關(guān)鍵字將中止并跳出switch語(yǔ)句段,常常用于每個(gè)case語(yǔ)句的最后面。如果沒有break語(yǔ)句,switch語(yǔ)句將繼續(xù)執(zhí)行下面的表達(dá)式(“持續(xù)下降”)直到遇到break,或者是到達(dá)switch語(yǔ)句的末尾。
示例:
switch (var) { case 1: //當(dāng)var等于1執(zhí)行這里 break; case 2: //當(dāng)var等于2執(zhí)行這里 break; default: // 如果沒有匹配項(xiàng),將執(zhí)行此缺省段 // default段是可選的 }
語(yǔ)法
switch (var) { case label: // statements break; case label: // statements break; default: // statements }
參數(shù)
var: 與不同的case中的值進(jìn)行比較的變量
label: 相應(yīng)的case的值
while
while循環(huán)
描述:
while循環(huán)將會(huì)連續(xù)地?zé)o限地循環(huán),直到圓括號(hào)()中的表達(dá)式變?yōu)榧?。被測(cè)試的變量必須被改變,否則while循環(huán)將永遠(yuǎn)不會(huì)中止。這可以是你的代碼,比如一個(gè)遞增的變量,或者是一個(gè)外部條件,比如測(cè)試一個(gè)傳感器。
語(yǔ)法:
while(expression){ // statement(s) }
參數(shù):
expression - 一個(gè)(布爾型)C語(yǔ)句,被求值為真或假
示例:
var = 0; while(var < 200){ // 做兩百次重復(fù)的事情 var++; }
do...while
do循環(huán)
do循環(huán)與while循環(huán)使用相同方式工作,不同的是條件是在循環(huán)的末尾被測(cè)試的,所以do循環(huán)總是至少會(huì)運(yùn)行一次。
do { // 語(yǔ)句塊 } while (測(cè)試條件);
示例:
do { delay(50); // 等待傳感器穩(wěn)定 x = readSensors(); // 檢查傳感器的值 } while (x < 100);
break
break用于中止do,for,或while循環(huán),繞過(guò)正常的循環(huán)條件。它也用于中止switch語(yǔ)句。
示例:
for (x = 0; x < 255; x ++) { digitalWrite(PWMpin, x); sens = analogRead(sensorPin); if (sens > threshold){ // bail out on sensor detect x = 0; break; } delay(50); }
continue
continue語(yǔ)句跳過(guò)一個(gè)循環(huán)的當(dāng)前迭代的余下部分。(do,for,或while)。通過(guò)檢查循環(huán)測(cè)試條件它將繼續(xù)進(jìn)行隨后的迭代。
示例:
for (x = 0; x < 255; x ++) { if (x > 40 && x < 120){ // create jump in values continue; } digitalWrite(PWMpin, x); delay(50); }
return
終止一個(gè)函數(shù),并向被調(diào)用函數(shù)并返回一個(gè)值,如果你想的話。
語(yǔ)法:
return; return value; // both forms are valid
參數(shù):
value: 任何類型的變量或常量
示例:
//一個(gè)函數(shù),用于對(duì)一個(gè)傳感器輸入與一個(gè)閾值進(jìn)行比較 int checkSensor(){ if (analogRead(0) > 400) { return 1; else{ return 0; } }
return 關(guān)鍵字對(duì)測(cè)試一段代碼很方便,不需“注釋掉”大段的可能是錯(cuò)誤的代碼。
void loop(){ //在此測(cè)試代碼是個(gè)好想法 return; // 這里是功能不正常的代碼 // 這里的代碼永遠(yuǎn)也不會(huì)執(zhí)行 }
goto
在程序中轉(zhuǎn)移程序流到一個(gè)標(biāo)記點(diǎn)
語(yǔ)法:
label: goto label; // sends program flow to the label
提示:
在C程序中不建議使用goto,而且一些C編程書的作者主張永遠(yuǎn)不要使用goto語(yǔ)句,但是明智地使用它可以
簡(jiǎn)化某些代碼。許多程序員不贊成使用goto的原因是,無(wú)節(jié)制地使用goto語(yǔ)句很容易產(chǎn)生執(zhí)行流混亂的很難被調(diào)試程序。
盡管如是說(shuō),仍然有很多使用goto語(yǔ)句而大大簡(jiǎn)化編碼的實(shí)例。其中之一就是從一個(gè)很深的循環(huán)嵌套中跳出去,或者是if邏輯塊,在某人些條件下。
示例:
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;} // 其它語(yǔ)句。。。 } } } bailout:
相關(guān)語(yǔ)法
分號(hào)
用于一個(gè)語(yǔ)句的結(jié)束
示例
int a = 13;
提示
忘記在一行的末尾加一個(gè)分號(hào)將產(chǎn)生一個(gè)編譯器錯(cuò)誤。該錯(cuò)誤信息可能是明顯的,且會(huì)提及丟失分號(hào),但也許不會(huì)。如果出現(xiàn)一個(gè)不可理喻的或看起來(lái)不合邏輯的錯(cuò)誤,其中一個(gè)首先要做的事就是檢查分號(hào)丟失。編譯器會(huì)在前一行的附近發(fā)出抱怨。
大括號(hào)
大括號(hào)(又稱括弧或花括號(hào))是C語(yǔ)言的主要組成部分。它們用在幾個(gè)不同的結(jié)構(gòu)中,大致如下,這可能會(huì)令初學(xué)者感到困惑。
一個(gè)左大括號(hào)必須有一個(gè)右大括號(hào)跟在后面。這是一個(gè)常被稱為平衡括號(hào)的條件。Arduino IDE(集成開發(fā)環(huán)境)包含一個(gè)方便的特性以檢驗(yàn)平衡大括號(hào)。只需選擇一個(gè)大括號(hào),甚至直接在一個(gè)大括號(hào)后面點(diǎn)擊插入點(diǎn),然后它的邏輯上的同伴就會(huì)高亮顯示。
目前此功能有些許錯(cuò)誤,因?yàn)镮DE經(jīng)常在文本中(錯(cuò)誤地)發(fā)現(xiàn)一個(gè)已經(jīng)被注釋掉的大括號(hào)。
初級(jí)程序員,和從BASIC轉(zhuǎn)到C的程序員常常發(fā)現(xiàn)使用大括號(hào)令人困惑或畏縮。畢竟,用同樣的大括號(hào)在子例程(函數(shù))中替換RETURN語(yǔ)句,在條件語(yǔ)句中替換ENDIF語(yǔ)句和在FOR循環(huán)中替換NEXT語(yǔ)句。
由于大括號(hào)的使用是如此的多樣,當(dāng)插入一個(gè)需要大括號(hào)的結(jié)構(gòu)時(shí),直接在打出開括號(hào)之后打出閉括號(hào)是個(gè)不錯(cuò)的編程實(shí)踐。然后在大括號(hào)之間插入一些回車符,接著開始插入語(yǔ)句。你的大括號(hào),還有你的態(tài)度,將永遠(yuǎn)不會(huì)變得不平衡。
不平衡的大括號(hào)常常導(dǎo)致古怪的,難以理解的編譯器錯(cuò)誤,有時(shí)在大型程序中很難查出。因?yàn)樗鼈兊亩鄻拥氖褂?,大括?hào)對(duì)于程序的語(yǔ)法也是極其重要的,對(duì)一個(gè)大括號(hào)移動(dòng)一行或兩行常常顯著地影響程序的意義。
大括號(hào)的主要用法
//函數(shù) void myfunction(datatype argument){ statements(s) } //循環(huán) while (boolean expression) { statement(s) } do { statement(s) } while (boolean expression); for (initialisation; termination condition; incrementing expr) { statement(s) } //條件語(yǔ)句 if (boolean expression) { statement(s) } else if (boolean expression) { statement(s) } else { statement(s) }
注釋
注釋是程序中的一些行,用于讓自己或他人了解程序的工作方式。他們會(huì)被編譯器忽略,而不會(huì)輸出到控制器,所以它們不會(huì)占用Atmega芯片上的任何空間。
注釋唯一的目的是幫助你理解(或記憶)你的程序是怎樣工作的,或者是告知其他人你的程序是怎樣工作的。標(biāo)記一行為注釋只有兩種方式:
示例
x = 5; //這是一個(gè)單行注釋。此斜線后的任何內(nèi)容都是注釋 //直到該行的結(jié)尾 /* 這是多行注釋 - 用它來(lái)注釋掉整個(gè)代碼塊 if (gwb == 0){ //在多行注釋中使用單行注釋是沒有問(wèn)題的 x = 3; /* 但是其中不可以使用另一個(gè)多行注釋 - 這是不合法的 */ } //別忘了加上“關(guān)閉”注釋符 - 它們必須是平衡的 */
提示
當(dāng)實(shí)驗(yàn)代碼時(shí),“注釋掉”你的程序的一部分來(lái)移除可能是錯(cuò)誤的行是一種方便的方法。這不是把這些行從程序中移除,而是把它們放到注釋中,所以編譯器就會(huì)忽略它們。這在定位問(wèn)題時(shí),或者當(dāng)程序無(wú)法編譯通過(guò)且編譯錯(cuò)誤信息很古怪或沒有幫助時(shí)特別有用。
define
#define 宏定義
宏定義是一個(gè)有用的C組件,它允許程序員在程序編譯前給常量取一個(gè)名字。在arduino中定義的常量不會(huì)在芯片中占用任何程序空間。編譯器在編譯時(shí)會(huì)將這些常量引用替換為定義的值。
這雖然可能有些有害的副作用,舉例來(lái)說(shuō),一個(gè)已被定義的常量名被包含在一些其它的常量或變量名中。那樣的話該文本將被替換成被定義的數(shù)字(或文本)。
通常,用const關(guān)鍵字定義常量是更受歡迎的且用來(lái)代替#define會(huì)很有用。
Arduino宏定義與C宏定義有同樣的語(yǔ)法
語(yǔ)法
#define constantName value
注意‘#’是必須的
示例:
#define ledPin 3 // 編譯器在編譯時(shí)會(huì)將任何提及l(fā)edPin的地方替換成數(shù)值3。
提示
#define語(yǔ)句的后面分號(hào)。如果你加了一個(gè),編譯器將會(huì)在進(jìn)一步的頁(yè)面引發(fā)奇怪的錯(cuò)誤。
#define ledPin 3; // this is an error
類似地,包含一個(gè)等號(hào)通常也會(huì)在進(jìn)一步的頁(yè)面引發(fā)奇怪的編譯錯(cuò)誤。
#define ledPin = 3 // this is also an error
include
#include 包含
#include用于在你的sketch中包含外部的庫(kù)。這使程序員可以訪問(wèn)一個(gè)巨大的標(biāo)準(zhǔn)C庫(kù)(預(yù)定義函數(shù)集合)的集合。
AVR C庫(kù)(AVR是Atmel芯片的一個(gè)基準(zhǔn),Arduino正是基于它)的主參考手冊(cè)頁(yè)在這里。
注意#include和#define相似,沒有分號(hào)終止符,且如果你加了,編譯器會(huì)產(chǎn)生奇怪的錯(cuò)誤信息。
示例
該示例包含一個(gè)用于輸出數(shù)據(jù)到程序空間閃存的庫(kù),而不是內(nèi)存。這會(huì)為動(dòng)態(tài)內(nèi)存需求節(jié)省存儲(chǔ)空間且使需要?jiǎng)?chuàng)建巨大的查找表變得更實(shí)際。
#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};
算術(shù)運(yùn)算符
賦值
=賦值運(yùn)算符(單個(gè)等號(hào))
把等號(hào)右邊的值存儲(chǔ)到等號(hào)左邊的變量中。
在C語(yǔ)言中單個(gè)等號(hào)被稱為賦值運(yùn)算符。它與在代數(shù)課中的意義不同,后者象征等式或相等。賦值運(yùn)算符告訴微控制器求值等號(hào)右邊的變量或表達(dá)式,然后把結(jié)果存入等號(hào)左邊的變量中。
示例
int sensVal; //聲明一個(gè)名為sensVal的整型變量 senVal = analogRead(0); //存儲(chǔ)(數(shù)字的)0號(hào)模擬引腳的輸入電壓值到sensVal
編程技巧
賦值運(yùn)算符(=號(hào))左邊的變量需要能夠保存存儲(chǔ)在其中的值。如果它不足以大到容納一個(gè)值,那個(gè)存儲(chǔ)在該變量中的值將是錯(cuò)誤的。
不要混淆賦值運(yùn)算符[ = ](單個(gè)等號(hào))和比較運(yùn)算符[ == ](雙等號(hào)),后者求值兩個(gè)表達(dá)式是否相等。
加,減,乘,除
描述
這些運(yùn)算符(分別)返回兩人運(yùn)算對(duì)象的和,差,積,商。這些操作受運(yùn)算對(duì)象的數(shù)據(jù)類型的影響。所以,例如,9 / 4結(jié)果是2,如果9和2是整型數(shù)。這也意味著運(yùn)算會(huì)溢出,如果結(jié)果超出其在相應(yīng)的數(shù)據(jù)類型下所能表示的數(shù)。(例如,給整型數(shù)值32767加1結(jié)果是-32768)。如果運(yùn)算對(duì)象是不同的類型,會(huì)用那個(gè)較大的類型進(jìn)行計(jì)算。
如果其中一個(gè)數(shù)字(運(yùn)算符)是float類型或double類型,將采用浮點(diǎn)數(shù)進(jìn)行計(jì)算。
示例
y = y + 3; x = x - 7; i = j * 6; r = r / 5;
語(yǔ)法
result = value1 + value2; result = value1 - value2; result = value1 * value2; result = value1 / value2;
參數(shù):
value1:任何變量或常量
value2:任何變量或常量
編程技巧:
要知道整型常量默認(rèn)為int型,因此一些常量計(jì)算可能會(huì)溢出(例如:60 * 1000將產(chǎn)生負(fù)的結(jié)果)
選擇一個(gè)大小足夠大的變量以容納你的最大的計(jì)算結(jié)果。
要知道你的變量在哪一點(diǎn)將會(huì)“翻轉(zhuǎn)”且要知道在另一個(gè)方向上會(huì)發(fā)生什么,例如:(0 - 1)或(0 - 32768)。
對(duì)于數(shù)學(xué)需要分?jǐn)?shù),就使用浮點(diǎn)變量,但是要注意它們的缺點(diǎn):占用空間大,計(jì)算速度慢。
使用強(qiáng)制類型轉(zhuǎn)換符例如:(int)myFloat以在運(yùn)行中轉(zhuǎn)換一個(gè)變量到另一個(gè)類型。
取模
%(取模)
描述
計(jì)算一個(gè)數(shù)除以另一個(gè)數(shù)的余數(shù)。這對(duì)于保持一個(gè)變量在一個(gè)特定的范圍很有用(例如:數(shù)組的大?。?。
語(yǔ)法
result = dividend % divisor
參數(shù)
dividend: 被除數(shù)
divisor: 除數(shù)
結(jié)果:余數(shù)
示例
x = 7 % 5; // x now contains 2 x = 9 % 5; // x now contains 4 x = 5 % 5; // x now contains 0 x = 4 % 5; // x now contains 4
示例代碼
/* update one value in an array each time through a loop */ int values[10]; int i = 0; void setup() {} void loop() { values[i] = analogRead(0); i = (i + 1) % 10; // modulo operator rolls over variable }
提示:
取模運(yùn)算符不能用于浮點(diǎn)型數(shù)。
比較運(yùn)算符
if(條件) and ==, !=, <, > (比較運(yùn)算符)
if,用于和比較運(yùn)算符聯(lián)合使用,測(cè)試某一條件是否到達(dá),例如一個(gè)輸入超出某一數(shù)值。if條件測(cè)試的格式:
if (someVariable > 50) { // do something here }
該程序測(cè)試someVariable是否大于50。如果是, 程序執(zhí)行特定的動(dòng)作。換句話說(shuō),如果圓括號(hào)中的語(yǔ)句為真,花括號(hào)中的語(yǔ)句就會(huì)運(yùn)行。否則,程序跳過(guò)該代碼。
if語(yǔ)句后的花括號(hào)可能被省略。如果這么做了,下一行(由分號(hào)定義的行)就會(huì)變成唯一的條件語(yǔ)句。
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); } // all are correct
圓括號(hào)中被求值的語(yǔ)句需要使用一個(gè)或多個(gè)運(yùn)算符:
比較運(yùn)算符:
x == y (x is equal to y) x != y (x is not equal to y) x < y (x is less than y) x > y (x is greater than y) x <= y (x is less than or equal to y) x >= y (x is greater than or equal to y)
警告:
小心偶然地使用單個(gè)等號(hào)(例如if(x = 10))。單個(gè)等號(hào)是賦值運(yùn)算符,這里設(shè)置x為10(將值10存入變量x)。改用雙等號(hào)(例如if (x == 10)),這個(gè)是比較運(yùn)算符,用于測(cè)試x是否等于10。后者只在x等于10時(shí)返回真,但是前者將總是為真。
這是因?yàn)镃如下求值語(yǔ)句if(x=10):10分配給x(切記單個(gè)等號(hào)是賦值運(yùn)算符),因此x現(xiàn)在為10。然后'if'條件求值10,其總是為真,由于任何非零數(shù)值都為真值。由此,if (x = 10)將總是求值為真,這不是使用if語(yǔ)句所期望的結(jié)果。另外,變量x將被設(shè)置為10,這也不是期望的操作。
if也可以是使用[if...else]的分支控制結(jié)構(gòu)的一部分。
布爾運(yùn)算符
它們可用于if語(yǔ)句中的條件
&& (邏輯與)
只有在兩個(gè)操作數(shù)都為真時(shí)才返回真,例如:
if (digitalRead(2) == HIGH && digitalRead(3) == HIGH) { // read two switches // ... }
只在兩個(gè)輸入都為高時(shí)返回真
|| (邏輯或)
任意一個(gè)為真時(shí)返回真,例如:
if (x > 0 || y > 0) { // ... }
x或y任意一個(gè)大于0時(shí)返回真
! (非)
當(dāng)操作數(shù)為假時(shí)返回真,例如:
if (!x) { // ... }
若x為假返回真(即如果x等于0)
警告
確保你沒有把布爾與運(yùn)算符,&&(兩個(gè)與符號(hào))錯(cuò)認(rèn)為按位與運(yùn)算符&(單個(gè)與符號(hào))。它們是完全不同的概念。
同樣,不要混淆布爾或運(yùn)算符||(雙豎杠)與按位或運(yùn)算符|(單豎杠)。
按位取反~(波浪號(hào))看起來(lái)與布爾非!有很大不同(感嘆號(hào)或程序員口中的“棒”),但是你仍然必須確保在什么地方用哪一個(gè)。
例如
if (a >= 10 && a <= 20){} // true if a is between 10 and 20
指針運(yùn)算符
&(引用)和 *(間接引用)
指針對(duì)于C初學(xué)者來(lái)說(shuō)是更復(fù)雜的對(duì)象之一。并且可能寫大量的Arduino程序甚至都不會(huì)遇到指針。
無(wú)論如何,巧妙地控制特定的數(shù)據(jù)結(jié)構(gòu),使用指針可以簡(jiǎn)化代碼,而且在自己工具箱中擁有熟練控制指針的知識(shí)是很方便的。
位運(yùn)算
位與
按位與(&)
按位操作符在變量的位級(jí)執(zhí)行運(yùn)算。它們幫助解決各種常見的編程問(wèn)題。以下大部分資料來(lái)自一個(gè)有關(guān)位數(shù)學(xué)的優(yōu)秀教程,或許可以在這里找到。[1]
描述和語(yǔ)法
以下是所有這些運(yùn)算符的描述和語(yǔ)法。更詳細(xì)的資料或許可以在參考指南中找到。
按位與(&)
在C++中按位與運(yùn)算符是單個(gè)與符號(hào),
用于其它兩個(gè)整型表達(dá)式之間使用。按位與運(yùn)算獨(dú)立地在周圍的表達(dá)式的每一位上執(zhí)行操作。根據(jù)這一規(guī)則:如果兩個(gè)輸入位都是1,結(jié)果輸出1,否則輸出0。表達(dá)這一思想的另一個(gè)方法是:
0 0 1 1 operand1 0 1 0 1 operand2 ---------- 0 0 0 1 (operand1 & operand2) - returned result
在Arduino中,int型是16位的。所以在兩個(gè)整型表達(dá)式之間使用&將會(huì)導(dǎo)致16個(gè)與運(yùn)算同時(shí)發(fā)生。代碼片斷就像這樣:
int a = 92; // in binary: 0000000001011100 int b = 101; // in binary: 0000000001100101 int c = a & b; // result: 0000000001000100, or 68 in decimal.
在a和b的16位的每一位將使用按位與處理。且所有16位結(jié)果存入C中,以二進(jìn)制存入的結(jié)果值01000100,即十進(jìn)制的68。
按位與的其中一個(gè)最常用的用途是從一個(gè)整型數(shù)中選擇特定的位,常被稱為掩碼屏蔽??慈缦率纠?br />
位或
按位或(|)
在C++中按位或運(yùn)算符是垂直的條桿符號(hào),|。就像&運(yùn)算符,|獨(dú)立地計(jì)算它周圍的兩個(gè)整型表達(dá)式的每一位。(當(dāng)然)它所做的是不同的(操作)。兩個(gè)輸入位其中一個(gè)或都是1按位或?qū)⒌玫?,否則為0。換句話說(shuō):
0 0 1 1 operand1 0 1 0 1 operand2 ---------- 0 1 1 1 (operand1 | operand2) - returned result
這是一個(gè)使用一小斷C++代碼描述的按位或(運(yùn)算)的例子:
int a = 92; // in binary: 0000000001011100 int b = 101; // in binary: 0000000001100101 int c = a | b; // result: 0000000001111101, or 125 in decimal.
按位與和按位或的一個(gè)共同的工作是在端口上進(jìn)行程序員稱之為讀-改-寫的操作。在微控制器中,每個(gè)端口是一個(gè)8位數(shù)字,每一位表示一個(gè)引腳的狀態(tài)。寫一個(gè)端口可以同時(shí)控制所有的引腳。
PORTD是內(nèi)建的參照數(shù)字口0,1,2,3,4,5,6,7的輸出狀態(tài)的常量。如果一個(gè)比特位是1,那么該引腳置高。(引腳總是需要用pinMode()指令設(shè)置為輸出模式)。所以如果我們寫入PORTD = B00110001;我們就會(huì)讓引腳2,3和7輸出高。一個(gè)小小的問(wèn)題是,我們同時(shí)也改變了某些引腳的0,1狀態(tài)。這用于Arduino與串口通訊,所以我們可能會(huì)干擾串口通訊。
我們的程序規(guī)則是:
僅僅獲取和清除我們想控制的與相應(yīng)引腳對(duì)應(yīng)的位(使用按位與)。
合并要修改的PORTD值與所控制的引腳的新值(使用按位或)。
int i; // counter variable int j; void setup(){ DDRD = DDRD | B11111100; // set direction bits for pins 2 to 7, leave 0 and 1 untouched (xx | 00 == xx) // same as pinMode(pin, OUTPUT) for pins 2 to 7 Serial.begin(9600); } void loop(){ for (i=0; i<64; i++){ PORTD = PORTD & B00000011; // clear out bits 2 - 7, leave pins 0 and 1 untouched (xx & 11 == xx) j = (i << 2); // shift variable up to pins 2 - 7 - to avoid pins 0 and 1 PORTD = PORTD | j; // combine the port information with the new information for LED pins Serial.println(PORTD, BIN); // debug to show masking delay(100); } }
位異或
按位異或(^)
在C++中有一個(gè)有點(diǎn)不尋常的操作,它被稱為按位異或,或者XOR(在英語(yǔ)中,通常讀作“eks-or”)。按位異或運(yùn)算符使用符號(hào)^。該運(yùn)算符與按位或運(yùn)算符“|”非常相似 ,唯一的不同是當(dāng)輸入位都為1時(shí)它返回0。
0 0 1 1 operand1 0 1 0 1 operand2 ---------- 0 1 1 0 (operand1 ^ operand2) - returned result
看待XOR的另一個(gè)視角是,當(dāng)輸入不同時(shí)結(jié)果為1,當(dāng)輸入相同時(shí)結(jié)果為0。
這里是一個(gè)簡(jiǎn)單的示例代碼:
int x = 12; // binary: 1100 int y = 10; // binary: 1010 int z = x ^ y; // binary: 0110, or decimal 6
“^”運(yùn)算符常用于翻轉(zhuǎn)整數(shù)表達(dá)式的某些位(例如從0變?yōu)?,或從1變?yōu)?)。在一個(gè)按位異或操作中,如果相應(yīng)的掩碼位為1, 該位將翻轉(zhuǎn),如果為0,該位不變。以下是一個(gè)閃爍引腳5的程序.
// Blink_Pin_5 // demo for Exclusive OR void setup(){ DDRD = DDRD | B00100000; // set digital pin five as OUTPUT Serial.begin(9600); } void loop(){ PORTD = PORTD ^ B00100000; // invert bit 5 (digital pin 5), leave others untouched delay(100); }
位非
按位取反(~)
在C++中按位取反運(yùn)算符為波浪符“~”。不像“&”和“|”,按位取反運(yùn)算符應(yīng)用于其右側(cè)的單個(gè)操作數(shù)。按位取反操作會(huì)翻轉(zhuǎn)其每一位。0變?yōu)?,1變?yōu)?。例如:
0 1 operand1 ---------- 1 0 ~ operand1
int a = 103; // binary: 0000000001100111 int b = ~a; // binary: 1111111110011000 = -104
看到此操作的結(jié)果為一個(gè)負(fù)數(shù):-104,你可能會(huì)感到驚訝,這是因?yàn)橐粋€(gè)整型變量的最高位是所謂的符號(hào)位。如果最高位為1,該整數(shù)被解釋為負(fù)數(shù)。這里正數(shù)和負(fù)數(shù)的編碼被稱為二進(jìn)制補(bǔ)碼。欲了解更多信息,請(qǐng)參閱維基百科條目:補(bǔ)碼。
順便說(shuō)一句,值得注意的是,對(duì)于任何整數(shù)x, ~x 與 -x-1 相等。
有時(shí)候,符號(hào)位在有符號(hào)整數(shù)表達(dá)式中能引起一些不期的意外。
左移、右移
左移運(yùn)算(<<),右移運(yùn)算(>>)
描述
From The Bitmath Tutorial in The Playground
在C++中有兩個(gè)移位運(yùn)算符:左移運(yùn)算符<<和右移運(yùn)算符>>。這些運(yùn)算符將使左邊操作數(shù)的每一位左移或右移其右邊指定的位數(shù)。
語(yǔ)法
variable << number_of_bits variable >> number_of_bits 參數(shù)<br> *variable - (byte, int, long) number_of_bits integer <= 32 <br> 示例:<br> <pre style="color:green"> int a = 5; // binary: 0000000000000101 int b = a << 3; // binary: 0000000000101000, or 40 in decimal int c = b >> 3; // binary: 0000000000000101, or back to 5 like we started with
當(dāng)把x左移y位(x << y),x中最左邊的y位將會(huì)丟失。
int a = 5; // binary: 0000000000000101 int b = a << 14; // binary: 0100000000000000 - 101中的第一個(gè)1被丟棄
如果您確信沒有值被移出,理解左移位運(yùn)算符一個(gè)簡(jiǎn)單的辦法是,把它的左操作數(shù)乘2將提高其冪值。例如,要生成2的乘方,可以使用以下表達(dá)式:
1 << 0 == 1 1 << 1 == 2 1 << 2 == 4 1 << 3 == 8 ... 1 << 8 == 256 1 << 9 == 512 1 << 10 == 1024 ...
當(dāng)把x右移y位,x的最高位為1,該行為依賴于x的確切的數(shù)據(jù)類型。如果x的類型是int,最高位為符號(hào)位,決定x是不是負(fù)數(shù),正如我們?cè)谏厦嬉呀?jīng)討論過(guò)的。在這種情況下,符號(hào)位會(huì)復(fù)制到較低的位:
int x = -16; // binary: 1111111111110000 int y = x >> 3; // binary: 1111111111111110
該行為,被稱為符號(hào)擴(kuò)展,常常不是你所期待的。反而,你可能希望移入左邊的是0。事實(shí)上右移規(guī)則對(duì)于無(wú)符合整型表達(dá)式是不同的。所以你可以使用強(qiáng)制類型轉(zhuǎn)換來(lái)避免左邊移入1。
int x = -16; // binary: 1111111111110000 int y = (unsigned int)x >> 3; // binary: 0001111111111110
如果你可以很小心地避免符號(hào)擴(kuò)展,你可以使用右移位運(yùn)算符>>,作為除以2的冪的一種方法。例如
int x = 1000; int y = x >> 3; // 1000除以8,得y = 125.
復(fù)合運(yùn)算符
自加++ i++; //相當(dāng)于 i = i + 1; 自減-- i--; //相當(dāng)于 i = i - 1; 復(fù)合加+= i+=5; //相當(dāng)于 i = i + 5; 復(fù)合減-= i-=5; //相當(dāng)于 i = i - 5; 復(fù)合乘*= i*=5; //相當(dāng)于 i = i * 5; 復(fù)合除/= i/=5; //相當(dāng)于 i = i / 5; 復(fù)合與&= i&=5; //相當(dāng)于 i = i & 5; 復(fù)合或|= i|=5; //相當(dāng)于 i = i | 5;
變量
(本節(jié)轉(zhuǎn)自極客工坊)
常量
constants是在Arduino語(yǔ)言里預(yù)定義的變量。它們被用來(lái)使程序更易閱讀。我們按組將常量分類。
邏輯層定義,true與false(布爾Boolean常量)
在Arduino內(nèi)有兩個(gè)常量用來(lái)表示真和假:true和 false。
false
在這兩個(gè)常量中false更容易被定義。false被定義為0(零)。
true
true通常被定義為1,這是正確的,但true具有更廣泛的定義。在布爾含義(Boolean sense)里任何 非零 整數(shù) 為true。所以在布爾含義內(nèi)-1,2和-200都定義為ture。 需要注意的是true和false常量,不同于HIGH,LOW,INPUT和OUTPUT,需要全部小寫。
——這里引申一下題外話arduino是大小寫敏感語(yǔ)言(case sensitive)。
引腳電壓定義,HIGH和LOW
當(dāng)讀?。╮ead)或?qū)懭耄╳rite)數(shù)字引腳時(shí)只有兩個(gè)可能的值: HIGH 和 LOW 。
HIGH
HIGH(參考引腳)的含義取決于引腳(pin)的設(shè)置,引腳定義為INPUT或OUTPUT時(shí)含義有所不同。當(dāng)一個(gè)引腳通過(guò)pinMode被設(shè)置為INPUT,并通過(guò)digitalRead讀取(read)時(shí)。如果當(dāng)前引腳的電壓大于等于3V,微控制器將會(huì)返回為HIGH。 引腳也可以通過(guò)pinMode被設(shè)置為INPUT,并通過(guò)digitalWrite設(shè)置為HIGH。輸入引腳的值將被一個(gè)內(nèi)在的20K上拉電阻 控制 在HIGH上,除非一個(gè)外部電路將其拉低到LOW。 當(dāng)一個(gè)引腳通過(guò)pinMode被設(shè)置為OUTPUT,并digitalWrite設(shè)置為HIGH時(shí),引腳的電壓應(yīng)在5V。在這種狀態(tài)下,它可以 輸出電流 。例如,點(diǎn)亮一個(gè)通過(guò)一串電阻接地或設(shè)置為L(zhǎng)OW的OUTPUT屬性引腳的LED。
LOW
LOW的含義同樣取決于引腳設(shè)置,引腳定義為INPUT或OUTPUT時(shí)含義有所不同。當(dāng)一個(gè)引腳通過(guò)pinMode配置為INPUT,通過(guò)digitalRead設(shè)置為讀?。╮ead)時(shí),如果當(dāng)前引腳的電壓小于等于2V,微控制器將返回為L(zhǎng)OW。 當(dāng)一個(gè)引腳通過(guò)pinMode配置為OUTPUT,并通過(guò)digitalWrite設(shè)置為L(zhǎng)OW時(shí),引腳為0V。在這種狀態(tài)下,它可以 倒灌 電流。例如,點(diǎn)亮一個(gè)通過(guò)串聯(lián)電阻連接到+5V,或到另一個(gè)引腳配置為OUTPUT、HIGH的的LED。
數(shù)字引腳(Digital pins)定義,INPUT和OUTPUT
數(shù)字引腳當(dāng)作 INPUT 或 OUTPUT都可以 。用pinMode()方法使一個(gè)數(shù)字引腳從INPUT到OUTPUT變化。
引腳(Pins)配置為輸入(Inputs)
Arduino(Atmega)引腳通過(guò)pinMode()配置為 輸入(INPUT) 即是將其配置在一個(gè)高阻抗的狀態(tài)。配置為INPUT的引腳可以理解為引腳取樣時(shí)對(duì)電路有極小的需求,即等效于在引腳前串聯(lián)一個(gè)100兆歐姆(Megohms)的電阻。這使得它們非常利于讀取傳感器,而不是為L(zhǎng)ED供電。
引腳(Pins)配置為輸出(Outputs)
引腳通過(guò)pinMode()配置為 輸出(OUTPUT) 即是將其配置在一個(gè)低阻抗的狀態(tài)。
這意味著它們可以為電路提供充足的電流。Atmega引腳可以向其他設(shè)備/電路提供(提供正電流positive current)或倒灌(提供負(fù)電流negative current)達(dá)40毫安(mA)的電流。這使得它們利于給LED供電,而不是讀取傳感器。輸出(OUTPUT)引腳被短路的接地或5V電路上會(huì)受到損壞甚至燒毀。Atmega引腳在為繼電器或電機(jī)供電時(shí),由于電流不足,將需要一些外接電路來(lái)實(shí)現(xiàn)供電。
宏定義
#define HIGH 0x1 高電平 #define LOW 0x0 低電平 #define INPUT 0x0 輸入 #define OUTPUT 0x1 輸出 #define true 0x1 真 #define false 0x0 假 #define PI 3.14159265 PI. #define HALF_PI 1.57079 二分之一PI #define TWO_PI 6.283185 二倍PI #define DEG_TO_RAD 0.01745329 弧度轉(zhuǎn)角度 #define RAD_TO_DEG 57.2957786 角度轉(zhuǎn)弧度
整型常量
整數(shù)常量
整數(shù)常量是直接在程序中使用的數(shù)字,如123。默認(rèn)情況下,這些數(shù)字被視為int,但你可以通過(guò)U和L修飾符進(jìn)行更多的限制(見下文)。 通常情況下,整數(shù)常量默認(rèn)為十進(jìn)制,但可以加上特殊前綴表示為其他進(jìn)制。
進(jìn)制 例子 格式 備注 10(十進(jìn)制) 123 無(wú) 2(二進(jìn)制) B1111011 前綴'B' 只適用于8位的值(0到255)字符0-1有效 8(八進(jìn)制) 0173 前綴”0” 字符0-7有效 16(十六進(jìn)制) 0x7B 前綴”0x” 字符0-9,A-F,A-F有效
小數(shù)是十進(jìn)制數(shù)。這是數(shù)學(xué)常識(shí)。如果一個(gè)數(shù)沒有特定的前綴,則默認(rèn)為十進(jìn)制。
二進(jìn)制以2為基底,只有數(shù)字0和1是有效的。
示例:
101 //和十進(jìn)制5等價(jià) (1*2^2 + 0*2^1 + 1*2^0)
二進(jìn)制格式只能是8位的,即只能表示0-255之間的數(shù)。如果輸入二進(jìn)制數(shù)更方便的話,你可以用以下的方式:
myInt = (B11001100 * 256) + B10101010; // B11001100 作為高位。
八進(jìn)制是以8為基底,只有0-7是有效的字符。前綴“0”(數(shù)字0)表示該值為八進(jìn)制。
0101 // 等同于十進(jìn)制數(shù)65 ((1 * 8^2) + (0 * 8^1) + 1)
警告:八進(jìn)制數(shù)0前綴很可能無(wú)意產(chǎn)生很難發(fā)現(xiàn)的錯(cuò)誤,因?yàn)槟憧赡懿恍⌒脑诔A壳凹恿藗€(gè)“0”,結(jié)果就悲劇了。
十六進(jìn)制以16為基底,有效的字符為0-9和A-F。十六進(jìn)制數(shù)用前綴“0x”(數(shù)字0,字母愛克斯)表示。請(qǐng)注意,A-F不區(qū)分大小寫,就是說(shuō)你也可以用a-f。
示例:
0x101 // 等同于十進(jìn)制257 ((1 * 16^2) + (0 * 16^1) + 1)
U & L 格式
默認(rèn)情況下,整型常量被視作int型。要將整型常量轉(zhuǎn)換為其他類型時(shí),請(qǐng)遵循以下規(guī)則:
- 'u' or 'U' 指定一個(gè)常量為無(wú)符號(hào)型。(只能表示正數(shù)和0) 例如: 33u
- 'l' or 'L' 指定一個(gè)常量為長(zhǎng)整型。(表示數(shù)的范圍更廣) 例如: 100000L
- 'ul' or 'UL' 這個(gè)你懂的,就是上面兩種類型,稱作無(wú)符號(hào)長(zhǎng)整型。 例如:32767ul
浮點(diǎn)數(shù)常量
浮點(diǎn)常量
和整型常量類似,浮點(diǎn)常量可以使得代碼更具可讀性。浮點(diǎn)常量在編譯時(shí)被轉(zhuǎn)換為其表達(dá)式所取的值。 例子
n = .005; 浮點(diǎn)數(shù)可以用科學(xué)記數(shù)法表示。'E'和'e'都可以作為有效的指數(shù)標(biāo)志。
浮點(diǎn)數(shù) 被轉(zhuǎn)換為 被轉(zhuǎn)換為 10.0 10 2.34E5 2.34 * 10^5 234000 67E-12 67.0 * 10^-12 0.000000000067
數(shù)據(jù)類型
void
void只用在函數(shù)聲明中。它表示該函數(shù)將不會(huì)被返回任何數(shù)據(jù)到它被調(diào)用的函數(shù)中。
例子
//功能在“setup”和“l(fā)oop”被執(zhí)行 //但沒有數(shù)據(jù)被返回到高一級(jí)的程序中 void setup() { // ... } void loop() { // ... }
boolean
布爾
一個(gè)布爾變量擁有兩個(gè)值,true或false。(每個(gè)布爾變量占用一個(gè)字節(jié)的內(nèi)存。)
例子
int LEDpin = 5; // LED與引腳5相連 int switchPin = 13; // 開關(guān)的一個(gè)引腳連接引腳13,另一個(gè)引腳接地。 boolean running = false; void setup() { pinMode(LEDpin, OUTPUT); pinMode(switchPin, INPUT); digitalWrite(switchPin, HIGH); // 打開上拉電阻 } void loop() { if (digitalRead(switchPin) == LOW) { // 按下開關(guān) - 使引腳拉向高電勢(shì) delay(100); // 通過(guò)延遲,以濾去開關(guān)抖動(dòng)產(chǎn)生的雜波 running = !running; // 觸發(fā)running變量 digitalWrite(LEDpin, running) //點(diǎn)亮LED } }
char
char
描述
一個(gè)數(shù)據(jù)類型,占用1個(gè)字節(jié)的內(nèi)存存儲(chǔ)一個(gè)字符值。字符都寫在單引號(hào),如'A'(多個(gè)字符(字符串)使用雙引號(hào),如“ABC”)。
字符以編號(hào)的形式存儲(chǔ)。你可以在ASCII表中看到對(duì)應(yīng)的編碼。這意味著字符的ASCII值可以用來(lái)作數(shù)學(xué)計(jì)算。(例如'A'+ 1,因?yàn)榇髮慉的ASCII值是65,所以結(jié)果為66)。如何將字符轉(zhuǎn)換成數(shù)字參考serial.println命令。
char數(shù)據(jù)類型是有符號(hào)的類型,這意味著它的編碼為-128到127。對(duì)于一個(gè)無(wú)符號(hào)一個(gè)字節(jié)(8位)的數(shù)據(jù)類型,使用byte數(shù)據(jù)類型。
例如
char myChar = 'A'; char myChar = 65; // both are equivalent
unsigned char
無(wú)符號(hào)字符型
描述
一個(gè)無(wú)符號(hào)數(shù)據(jù)類型占用1個(gè)字節(jié)的內(nèi)存。與byte的數(shù)據(jù)類型相同。
無(wú)符號(hào)的char數(shù)據(jù)類型能編碼0到255的數(shù)字。
為了保持Arduino的編程風(fēng)格的一致性,byte數(shù)據(jù)類型是首選。
例子
unsigned char myChar = 240;
byte
字節(jié)型
描述
一個(gè)字節(jié)存儲(chǔ)8位無(wú)符號(hào)數(shù),從0到255。
例子
byte b = B10010; // "B" 是二進(jìn)制格式(B10010等于十進(jìn)制18)
int
整型
簡(jiǎn)介
整數(shù)是基本數(shù)據(jù)類型,占用2字節(jié)。整數(shù)的范圍為-32,768到32,767( -2^15 ~(2^15)-1)。
整數(shù)類型使用2的補(bǔ)碼方式存儲(chǔ)負(fù)數(shù)。最高位通常為符號(hào)位,表示數(shù)的正負(fù)。其余位被“取反加1”(此處請(qǐng)參考補(bǔ)碼相關(guān)資料,不再贅述)。
Arduino為您處理負(fù)數(shù)計(jì)算問(wèn)題,所以數(shù)學(xué)計(jì)算對(duì)您是透明的(術(shù)語(yǔ):實(shí)際存在,但不可操作。相當(dāng)于“黑盒”)。但是,當(dāng)處理右移位運(yùn)算符(?)時(shí),可能有未預(yù)期的編譯過(guò)程。
示例
int ledPin = 13;
語(yǔ)法
int var = val;
- var - 變量名
- val - 賦給變量的值
提示
當(dāng)變量數(shù)值過(guò)大而超過(guò)整數(shù)類型所能表示的范圍時(shí)(-32,768到32,767),變量值會(huì)“回滾”(詳情見示例)。
int x x = -32,768; x = x - 1; // x 現(xiàn)在是 32,767。 x = 32,767; x = x + 1; // x 現(xiàn)在是 -32,768。
unsigned int
無(wú)符號(hào)整型
描述
unsigned int(無(wú)符號(hào)整型)與整型數(shù)據(jù)同樣大小,占據(jù)2字節(jié)。它只能用于存儲(chǔ)正數(shù)而不能存儲(chǔ)負(fù)數(shù),范圍0~65,535 (2^16) - 1)。
無(wú)符號(hào)整型和整型最重要的區(qū)別是它們的最高位不同,既符號(hào)位。在Arduino整型類型中,如果最高位是1,則此數(shù)被認(rèn)為是負(fù)數(shù),剩下的15位為按2的補(bǔ)碼計(jì)算所得值。
例子
unsigned int ledPin = 13;
語(yǔ)法
unsigned int var = val;
- var - 無(wú)符號(hào)變量名稱
- val - 給變量所賦予的值
編程提示
當(dāng)變量的值超過(guò)它能表示的最大值時(shí)它會(huì)“滾回”最小值,反向也會(huì)出現(xiàn)這種現(xiàn)象。
unsigned int x x = 0; x = x - 1; //x現(xiàn)在等于65535--向負(fù)數(shù)方向滾回 x = x + 1; //x現(xiàn)在等于0--滾回
word
字
描述
一個(gè)存儲(chǔ)一個(gè)16位無(wú)符號(hào)數(shù)的字符,取值范圍從0到65535,與unsigned int相同。
例子
word w = 10000;
long
長(zhǎng)整型
描述
長(zhǎng)整數(shù)型變量是擴(kuò)展的數(shù)字存儲(chǔ)變量,它可以存儲(chǔ)32位(4字節(jié))大小的變量,從-2,147,483,648到2,147,483,647。
例子
long speedOfLight = 186000L; //參見整數(shù)常量‘L’的說(shuō)明
語(yǔ)法
long var = val;
- var - 長(zhǎng)整型變量名
- var - 賦給變量的值
unsigned long
無(wú)符號(hào)長(zhǎng)整型
描述
無(wú)符號(hào)長(zhǎng)整型變量擴(kuò)充了變量容量以存儲(chǔ)更大的數(shù)據(jù),它能存儲(chǔ)32位(4字節(jié))數(shù)據(jù)。與標(biāo)準(zhǔn)長(zhǎng)整型不同無(wú)符號(hào)長(zhǎng)整型無(wú)法存儲(chǔ)負(fù)數(shù),其范圍從0到4,294,967,295(2 ^ 32 - 1)。
例子
unsigned long time; void setup() { Serial.begin(9600); } void loop() { Serial.print("Time: "); time = millis(); //程序開始后一直打印時(shí)間 Serial.println(time); //等待一秒鐘,以免發(fā)送大量的數(shù)據(jù) delay(1000); }
語(yǔ)法
unsigned long var = val;
- var - 你所定義的變量名
- val - 給變量所賦的值
float
單精度浮點(diǎn)型
描述
float,浮點(diǎn)型數(shù)據(jù),就是有一個(gè)小數(shù)點(diǎn)的數(shù)字。浮點(diǎn)數(shù)經(jīng)常被用來(lái)近似的模擬連續(xù)值,因?yàn)樗麄儽日麛?shù)更大的精確度。浮點(diǎn)數(shù)的取值范圍在3.4028235 E+38 ~ -3.4028235E +38。它被存儲(chǔ)為32位(4字節(jié))的信息。
float只有6-7位有效數(shù)字。這指的是總位數(shù),而不是小數(shù)點(diǎn)右邊的數(shù)字。與其他平臺(tái)不同的是,在那里你可以使用double型得到更精確的結(jié)果(如15位),在Arduino上,double型與float型的大小相同。
浮點(diǎn)數(shù)字在有些情況下是不準(zhǔn)確的,在數(shù)據(jù)大小比較時(shí),可能會(huì)產(chǎn)生奇怪的結(jié)果。例如 6.0 / 3.0 可能不等于 2.0。你應(yīng)該使兩個(gè)數(shù)字之間的差額的絕對(duì)值小于一些小的數(shù)字,這樣就可以近似的得到這兩個(gè)數(shù)字相等這樣的結(jié)果。
浮點(diǎn)運(yùn)算速度遠(yuǎn)遠(yuǎn)慢于執(zhí)行整??數(shù)運(yùn)算,例如,如果這個(gè)循環(huán)有一個(gè)關(guān)鍵的計(jì)時(shí)功能,并需要以最快的速度運(yùn)行,就應(yīng)該避免浮點(diǎn)運(yùn)算。程序員經(jīng)常使用較長(zhǎng)的程式把浮點(diǎn)運(yùn)算轉(zhuǎn)換成整數(shù)運(yùn)算來(lái)提高速度。
舉例
float myfloat; float sensorCalbrate = 1.117;
語(yǔ)法
float var = val;
- var——您的float型變量名稱
- val——分配給該變量的值
示例代碼
int x; int y; float z; x = 1; y = x / 2; // Y為0,因?yàn)檎麛?shù)不能容納分?jǐn)?shù) z = (float)x / 2.0; // Z為0.5(你必須使用2.0做除數(shù),而不是2)
double
雙清度浮點(diǎn)型
描述
雙精度浮點(diǎn)數(shù)。占用4個(gè)字節(jié)。
目前的arduino上的double實(shí)現(xiàn)和float相同,精度并未提高。
提示
如果你從其他地方得到的代碼中包含了double類變量,最好檢查一遍代碼以確認(rèn)其中的變量的精確度能否在arduino上達(dá)到。
string
string(字符串)
描述
文本字符串可以有兩種表現(xiàn)形式。你可以使用字符串?dāng)?shù)據(jù)類型(這是0019版本的核心部分),或者你可以做一個(gè)字符串,由char類型的數(shù)組和空終止字符('\0')構(gòu)成。(求助,待潤(rùn)色-Leo)本節(jié)描述了后一種方法。而字符串對(duì)象(String object)將讓你擁有更多的功能,同時(shí)也消耗更多的內(nèi)存資源。
舉例
以下所有字符串都是有效的聲明。
char Str1[15]; char Str2[8] = {'a', 'r', 'd', 'u', 'i', 'n', 'o'}; char Str3[8] = {'a', 'r', 'd', 'u', 'i', 'n', 'o', '\0'}; char Str4[ ] = "arduino"; char Str5[8] = "arduino"; char Str6[15] = "arduino";
聲明字符串的解釋
- 在Str1中 聲明一個(gè)沒有初始化的字符數(shù)組
- 在Str2中 聲明一個(gè)字符數(shù)組(包括一個(gè)附加字符),編譯器會(huì)自動(dòng)添加所需的空字符
- 在Str3中 明確加入空字符
- 在Str4中 用引號(hào)分隔初始化的字符串常數(shù),編譯器將調(diào)整數(shù)組的大小,以適應(yīng)字符串常量和終止空字符
- 在Str5中 初始化一個(gè)包括明確的尺寸和字符串常量的數(shù)組
- 在Str6中 初始化數(shù)組,預(yù)留額外的空間用于一個(gè)較大的字符串
空終止字符
一般來(lái)說(shuō),字符串的結(jié)尾有一個(gè)空終止字符(ASCII代碼0)。以此讓功能函數(shù)(例如Serial.pring())知道一個(gè)字符串的結(jié)束。否則,他們將從內(nèi)存繼續(xù)讀取后續(xù)字節(jié),而這些并不屬于所需字符串的一部分。
這意味著,你的字符串比你想要的文字包含更多的個(gè)字符空間。這就是為什么Str2和Str5需要八個(gè)字符,即使“Arduino”只有七個(gè)字符 - 最后一個(gè)位置會(huì)自動(dòng)填充空字符。str4將自動(dòng)調(diào)整為八個(gè)字符,包括一個(gè)額外的空。在Str3的,我們自己已經(jīng)明確地包含了空字符(寫入'\ 0')。
需要注意的是,字符串可能沒有一個(gè)最后的空字符(例如在Str2中您已定義字符長(zhǎng)度為7,而不是8)。這會(huì)破壞大部分使用字符串的功能,所以不要故意而為之。如果你注意到一些奇怪的現(xiàn)象(在字符串中操作字符),基本就是這個(gè)原因?qū)е碌牧恕?br /> 單引號(hào)?還是雙引號(hào)?
定義字符串時(shí)使用雙引號(hào)(例如“ABC”),而定義一個(gè)單獨(dú)的字符時(shí)使用單引號(hào)(例如'A')
包裝長(zhǎng)字符串
你可以像這樣打包長(zhǎng)字符串: char myString[] = “This is the first line” ” this is the second line” ” etcetera”;
字符串?dāng)?shù)組
當(dāng)你的應(yīng)用包含大量的文字,如帶有液晶顯示屏的一個(gè)項(xiàng)目,建立一個(gè)字符串?dāng)?shù)組是非常便利的。因?yàn)樽址旧砭褪菙?shù)組,它實(shí)際上是一個(gè)兩維數(shù)組的典型。
在下面的代碼,”char*”在字符數(shù)據(jù)類型char后跟了一個(gè)星號(hào)'*'表示這是一個(gè)“指針”數(shù)組。所有的數(shù)組名實(shí)際上是指針,所以這需要一個(gè)數(shù)組的數(shù)組。指針對(duì)于C語(yǔ)言初學(xué)者而言是非常深?yuàn)W的部分之一,但我們沒有必要了解詳細(xì)指針,就可以有效地應(yīng)用它。
樣例
char* myStrings[]={ "This is string 1", "This is string 2", "This is string 3", "This is string 4", "This is string 5","This is string 6"}; void setup(){ Serial.begin(9600); } void loop(){ for (int i = 0; i < 6; i++){ Serial.println(myStrings[i]); delay(500); } }
String(c++)
描述
String類,是0019版的核心的一部分,允許你實(shí)現(xiàn)比運(yùn)用字符數(shù)組更復(fù)雜的文字操作。你可以連接字符串,增加字符串,尋找和替換子字符串以及其他操作。它比使用一個(gè)簡(jiǎn)單的字符數(shù)組需要更多的內(nèi)存,但它更方便。
僅供參考,字符串?dāng)?shù)組都用小寫的string表示而String類的實(shí)例通常用大寫的String表示。注意,在“雙引號(hào)”內(nèi)指定的字符常量通常被作為字符數(shù)組,并非String類實(shí)例。
函數(shù)
- String
- charAt()
- compareTo()
- concat()
- endsWith()
- equals()
- equalsIgnoreCase()
- GetBytes()
- indexOf()
- lastIndexOf
- length
- replace()
- setCharAt()
- startsWith()
- substring()
- toCharArray()
- toLowerCase()
- toUpperCase()
- trim()
操作符
- [](元素訪問(wèn))
- +(串連)
- ==(比較)
array
Arrays (數(shù)組)
數(shù)組是一種可訪問(wèn)的變量的集合。Arduino的數(shù)組是基于C語(yǔ)言的,因此這會(huì)變得很復(fù)雜,但使用簡(jiǎn)單的數(shù)組是比較簡(jiǎn)單的。
創(chuàng)建(聲明)一個(gè)數(shù)組
下面的方法都可以用來(lái)創(chuàng)建(聲明)數(shù)組。
myInts [6]; myPins [] = {2,4,8,3,6}; mySensVals [6] = {2,4,-8,3,2}; char message[6] = "hello";
你聲明一個(gè)未初始化數(shù)組,例如myPins。
在myPins中,我們聲明了一個(gè)沒有明確大小的數(shù)組。編譯器將會(huì)計(jì)算元素的大小,并創(chuàng)建一個(gè)適當(dāng)大小的數(shù)組。
當(dāng)然,你也可以初始化數(shù)組的大小,例如在mySensVals中。請(qǐng)注意,當(dāng)聲明一個(gè)char類型的數(shù)組時(shí),你初始化的大小必須大于元素的個(gè)數(shù),以容納所需的空字符。
訪問(wèn)數(shù)組
數(shù)組是從零開始索引的,也就說(shuō),上面所提到的數(shù)組初始化,數(shù)組第一個(gè)元素是為索引0,因此:
mySensVals [0] == 2,mySensVals [1] == 4,
依此類推 。
這也意味著,在包含十個(gè)元素的數(shù)組中,索引九是最后一個(gè)元素。因此,
int myArray[10] = {9,3,2,4,3,2,7,8,9,11}; // myArray[9]的數(shù)值為11 // myArray[10],該索引是無(wú)效的,它將會(huì)是任意的隨機(jī)信息(內(nèi)存地址)
出于這個(gè)原因,你在訪問(wèn)數(shù)組應(yīng)該小心。若訪問(wèn)的數(shù)據(jù)超出數(shù)組的末尾(即索引數(shù)大于你聲明的數(shù)組的大小- 1),則將從其他內(nèi)存中讀取數(shù)據(jù)。從這些地方讀取的數(shù)據(jù),除了產(chǎn)生無(wú)效的數(shù)據(jù)外,沒有任何作用。向隨機(jī)存儲(chǔ)器中寫入數(shù)據(jù)絕對(duì)是一個(gè)壞主意,通常會(huì)導(dǎo)致不愉快的結(jié)果,如導(dǎo)致系統(tǒng)崩潰或程序故障。要排查這樣的錯(cuò)誤是也是一件難事。 不同于Basic或JAVA,C語(yǔ)言編譯器不會(huì)檢查你訪問(wèn)的數(shù)組是否大于你聲明的數(shù)組。
指定一個(gè)數(shù)組的值:
mySensVals [0] = 10;
從數(shù)組中訪問(wèn)一個(gè)值:
X = mySensVals [4];
數(shù)組和循環(huán)
數(shù)組往往在for循環(huán)中進(jìn)行操作,循環(huán)計(jì)數(shù)器可用于訪問(wèn)每個(gè)數(shù)組元素。例如,將數(shù)組中的元素通過(guò)串口打印,你可以這樣做:
int i; for (i = 0; i < 5; i = i + 1) { Serial.println(myPins[i]); }
數(shù)據(jù)類型轉(zhuǎn)換
char()
描述
將一個(gè)變量的類型變?yōu)閏har。
語(yǔ)法
char(x)
參數(shù)
- x:任何類型的值
返回
- char
byte()
描述
將一個(gè)值轉(zhuǎn)換為字節(jié)型數(shù)值。
語(yǔ)法
byte(x)
參數(shù)
- X:任何類型的值
返回
- 字節(jié)
int()
簡(jiǎn)介
將一個(gè)值轉(zhuǎn)換為int類型。
語(yǔ)法
int(x)
參數(shù)
- x:一個(gè)任何類型的值
返回值
- int類型的值
word()
描述
把一個(gè)值轉(zhuǎn)換為word數(shù)據(jù)類型的值,或由兩個(gè)字節(jié)創(chuàng)建一個(gè)字符。
語(yǔ)法
word(x) word(h, l)
參數(shù)
- X:任何類型的值
- H:高階(最左邊)字節(jié)
- L:低序(最右邊)字節(jié)
返回
- 字符
long()
描述
將一個(gè)值轉(zhuǎn)換為長(zhǎng)整型數(shù)據(jù)類型。
語(yǔ)法
long(x)
參數(shù)
- x:任意類型的數(shù)值
返回
- 長(zhǎng)整型數(shù)
float()
描述
將一個(gè)值轉(zhuǎn)換為float型數(shù)值。
語(yǔ)法
float(x)
參數(shù)
- X:任何類型的值
返回
- float型數(shù)
變量作用域&修飾符
變量作用域
變量的作用域
在Arduino使用的C編程語(yǔ)言的變量,有一個(gè)名為 作用域(scope) 的屬性 。這一點(diǎn)與類似BASIC的語(yǔ)言形成了對(duì)比,在BASIC語(yǔ)言中所有變量都是 全局(global) 變量。
在一個(gè)程序內(nèi)的全局變量是可以被所有函數(shù)所調(diào)用的。局部變量只在聲明它們的函數(shù)內(nèi)可見。在Arduino的環(huán)境中,任何在函數(shù)(例如,setup(),loop()等)外聲明的變量,都是全局變量。
當(dāng)程序變得更大更復(fù)雜時(shí),局部變量是一個(gè)有效確定每個(gè)函數(shù)只能訪問(wèn)其自己變量的途徑。這可以防止,當(dāng)一個(gè)函數(shù)無(wú)意中修改另一個(gè)函數(shù)使用的變量的程序錯(cuò)誤。
有時(shí)在一個(gè)for循環(huán)內(nèi)聲明并初始化一個(gè)變量也是很方便的選擇。這將創(chuàng)建一個(gè)只能從for循環(huán)的括號(hào)內(nèi)訪問(wèn)的變量。
例子:
int gPWMval; // 任何函數(shù)都可以調(diào)用此變量 void setup() { // ... } void loop() { int i; // "i" 只在 "loop" 函數(shù)內(nèi)可用 float f; // "f" 只在 "loop" 函數(shù)內(nèi)可用 // ... for (int j = 0; j <100; j++){ //變量j只能在循環(huán)括號(hào)內(nèi)訪問(wèn) } }
static (靜態(tài)變量)
static關(guān)鍵字用于創(chuàng)建只對(duì)某一函數(shù)可見的變量。然而,和局部變量不同的是,局部變量在每次調(diào)用函數(shù)時(shí)都會(huì)被創(chuàng)建和銷毀,靜態(tài)變量在函數(shù)調(diào)用后仍然保持著原來(lái)的數(shù)據(jù)。
靜態(tài)變量只會(huì)在函數(shù)第一次調(diào)用的時(shí)候被創(chuàng)建和初始化。
例子
/* RandomWalk * Paul Badger 2007 * RandomWalk函數(shù)在兩個(gè)終點(diǎn)間隨機(jī)的上下移動(dòng) * 在一個(gè)循環(huán)中最大的移動(dòng)由參數(shù)“stepsize”決定 *一個(gè)靜態(tài)變量向上和向下移動(dòng)一個(gè)隨機(jī)量 *這種技術(shù)也被叫做“粉紅噪聲”或“醉步” */ #define randomWalkLowRange -20 #define randomWalkHighRange 20 int stepsize; INT thisTime; int total; void setup() { Serial.begin(9600); } void loop() { // 測(cè)試randomWalk 函數(shù) stepsize = 5; thisTime = randomWalk(stepsize); serial.println(thisTime); delay(10); } int randomWalk(int moveSize){ static int place; // 在randomwalk中存儲(chǔ)變量 // 聲明為靜態(tài)因此它在函數(shù)調(diào)用之間能保持?jǐn)?shù)據(jù),但其他函數(shù)無(wú)法改變它的值 place = place + (random(-moveSize, moveSize + 1)); if (place < randomWalkLowRange){ //檢查上下限 place = place + (randomWalkLowRange - place); // 將數(shù)字變?yōu)檎较?} else if(place > randomWalkHighRange){ place = place - (place - randomWalkHighRange); // 將數(shù)字變?yōu)樨?fù)方向 } return place; }
volatile (易變變量)
volatile關(guān)鍵字
volatile這個(gè)關(guān)鍵字是變量修飾符,常用在變量類型的前面,以告訴編譯器和接下來(lái)的程序怎么對(duì)待這個(gè)變量。
聲明一個(gè)volatile變量是編譯器的一個(gè)指令。編譯器是一個(gè)將你的C/C++代碼轉(zhuǎn)換成機(jī)器碼的軟件,機(jī)器碼是arduino上的Atmega芯片能識(shí)別的真正指令。
具體來(lái)說(shuō),它指示編譯器編譯器從RAM而非存儲(chǔ)寄存器中讀取變量,存儲(chǔ)寄存器是程序存儲(chǔ)和操作變量的一個(gè)臨時(shí)地方。在某些情況下,存儲(chǔ)在寄存器中的變量值可能是不準(zhǔn)確的。
如果一個(gè)變量所在的代碼段可能會(huì)意外地導(dǎo)致變量值改變那此變量應(yīng)聲明為volatile,比如并行多線程等。在arduino中,唯一可能發(fā)生這種現(xiàn)象的地方就是和中斷有關(guān)的代碼段,成為中斷服務(wù)程序。
例子
//當(dāng)中斷引腳改變狀態(tài)時(shí),開閉LED int pin = 13; volatile int state = LOW; void setup() { pinMode(pin, OUTPUT); attachInterrupt(0, blink, CHANGE); } void loop() { digitalWrite(pin, state); } void blink() { state = !state; }
const (不可改變變量)
const關(guān)鍵字
const關(guān)鍵字代表常量。它是一個(gè)變量限定符,用于修改變量的性質(zhì),使其變?yōu)橹蛔x狀態(tài)。這意味著該變量,就像任何相同類型的其他變量一樣使用,但不能改變其值。如果嘗試為一個(gè)const變量賦值,編譯時(shí)將會(huì)報(bào)錯(cuò)。
const關(guān)鍵字定義的常量,遵守 variable scoping 管轄的其他變量的規(guī)則。這一點(diǎn)加上使用 #define的缺陷 ,使 const 關(guān)鍵字成為定義常量的一個(gè)的首選方法。
例子
const float pi = 3.14; float x; // .... x = pi * 2; // 在數(shù)學(xué)表達(dá)式中使用常量不會(huì)報(bào)錯(cuò) pi = 7; // 錯(cuò)誤的用法 - 你不能修改常量值,或給常量賦值。
#define 或 const
您可以使用 const 或 #define 創(chuàng)建數(shù)字或字符串常量。但 arrays, 你只能使用 const。 一般 const 相對(duì) 的#define是首選 的定義常量語(yǔ)法。
輔助工具
sizeof() (sizeof運(yùn)算符)
描述
sizeof操作符返回一個(gè)變量類型的字節(jié)數(shù),或者該數(shù)在數(shù)組中占有的字節(jié)數(shù)。
語(yǔ)法
sizeof(variable)
參數(shù)
- variable: 任何變量類型或數(shù)組(如int,float,byte)
示例代碼
sizeof操作符用來(lái)處理數(shù)組非常有效,它能很方便的改變數(shù)組的大小而不用破壞程序的其他部分。
這個(gè)程序一次打印出一個(gè)字符串文本的字符。嘗試改變一下字符串。
char myStr[] = "this is a test"; int i; void setup(){ Serial.begin(9600); } {0}void{/0}{1} {/1}{2}loop{/2}{1}() {{/1} for (i = 0; i < sizeof(myStr) - 1; i++){ Serial.print(i, DEC); Serial.print(" = "); Serial.println(myStr[i], BYTE); } }
請(qǐng)注意sizeof返回字節(jié)數(shù)總數(shù)。因此,較大的變量類型,如整數(shù),for循環(huán)看起來(lái)應(yīng)該像這樣。
for (i = 0; i < (sizeof(myInts)/sizeof(int)) - 1; i++) { //用myInts[i]來(lái)做些事 }
ASCII碼表
代碼 字符 代碼 字符 代碼 字符 代碼 字符 0 32 [空格] 64 @ 96 ` 1 33 ! 65 A 97 a 2 34 " 66 B 98 b 3 35 # 67 C 99 c 4 36 $ 68 D 100 d 5 37 % 69 E 101 e 6 38 & 70 F 102 f 7 39 ' 71 G 103 g 8 40 ( 72 H 104 h 9 41 ) 73 I 105 i 10 42 * 74 J 106 j 11 43 + 75 K 107 k 12 44 , 76 L 108 l 13 45 - 77 M 109 m 14 46 . 78 N 110 n 15 47 / 79 O 111 o 16 48 0 80 P 112 p 17 49 1 81 Q 113 q 18 50 2 82 R 114 r 19 51 3 83 S 115 s 20 52 4 84 T 116 t 21 53 5 85 U 117 u 22 54 6 86 V 118 v 23 55 7 87 W 119 w 24 56 8 88 X 120 x 25 57 9 89 Y 121 y 26 58 : 90 Z 122 z 27 59 ; 91 [ 123 { 28 60 < 92 \ 124 | 29 61 = 93 ] 125 } 30 62 > 94 ^ 126 ~ 31 63 ? 95 _ 127
基本函數(shù)
(本節(jié)由柴樹杉[翻譯整理] (chaishushan@gmail.com))
數(shù)字I/O
pinMode()
void pinMode (uint8_t pin, uint8_t mode)
設(shè)置引腳模式
配置引腳為輸出或輸出模式.
參數(shù):
- pin 引腳編號(hào)
- mode: INPUT, OUTPUT, 或 INPUT_PULLUP.
例子:
int ledPin = 13; // LED connected to digital pin 13 void setup() { pinMode(ledPin, OUTPUT); // sets the digital pin as output } void loop() { digitalWrite(ledPin, HIGH); // sets the LED on delay(1000); // waits for a second digitalWrite(ledPin, LOW); // sets the LED off delay(1000); // waits for a second }
注解:
- 模擬引腳也可以當(dāng)作數(shù)字引腳使用, 編號(hào)為14(對(duì)應(yīng)模擬引腳0)到19(對(duì)應(yīng)模擬引腳5).
digitalWrite()
void digitalWrite (uint8_t pin, uint8_t value)
寫數(shù)字引腳
寫數(shù)字引腳, 對(duì)應(yīng)引腳的高低電平. 在寫引腳之前, 需要將引腳設(shè)置為OUTPUT模式.
參數(shù):
- pin 引腳編號(hào)
- value HIGH 或 LOW
用法:
int ledPin = 13; // LED connected to digital pin 13 void setup() { pinMode(ledPin, OUTPUT); // sets the digital pin as output } void loop() { digitalWrite(ledPin, HIGH); // 點(diǎn)亮LED delay(1000); // 等待1秒 digitalWrite(ledPin, LOW); // 關(guān) delay(1000); // waits for a second }
注解:
- 模擬引腳也可以當(dāng)作數(shù)字引腳使用, 編號(hào)為14(對(duì)應(yīng)模擬引腳0)到19(對(duì)應(yīng)模擬引腳5).
digitalRead()
int digitalRead (uint8_t pin)
讀數(shù)字引腳
讀數(shù)字引腳, 返回引腳的高低電平. 在讀引腳之前, 需要將引腳設(shè)置為INPUT模式.
參數(shù):
- pin 引腳編號(hào)
返回:
HIGH或LOW
int ledPin = 13; // LED connected to digital pin 13 int inPin = 7; // pushbutton connected to digital pin 7 int val = 0; // variable to store the read value void setup() { pinMode(ledPin, OUTPUT); // sets the digital pin 13 as output pinMode(inPin, INPUT); // sets the digital pin 7 as input } void loop() { val = digitalRead(inPin); // read the input pin digitalWrite(ledPin, val); // sets the LED to the button's value }
注解:
如果引腳沒有鏈接到任何地方, 那么將隨機(jī)返回 HIGH 或 LOW.
模擬I/O
analogReference()
void analogReference (uint8_t type)
配置參考電壓
配置模式引腳的參考電壓. 函數(shù) analogRead 在讀取模擬值之后, 將根據(jù)參考電壓將 模擬值轉(zhuǎn)換到[0,1023]區(qū)間. 有以下類型:
DEFAULT : 默認(rèn)5V.
INTERNAL: 低功耗模式. ATmega168和ATmega8對(duì)應(yīng)1.1V到2.56V.
EXTERNAL: 擴(kuò)展模式. 通過(guò)AREF引腳獲取參考電壓.
參數(shù):
- type 參考類型(DEFAULT/INTERNAL/EXTERNAL)
analogRead()
int analogRead (uint8_t pin)
讀模擬引腳
讀模擬引腳, 返回[0-1023]之間的值. 每讀一次需要花1微妙的時(shí)間.
參數(shù):
- pin 引腳編號(hào)
返回:
- 0到1023之間的值
例子:
int analogPin = 3; // potentiometer wiper (middle terminal) connected to analog pin 3 // outside leads to ground and +5V int val = 0; // variable to store the value read void setup() { Serial.begin(9600); // setup serial } void loop() { val = analogRead(analogPin); // read the input pin Serial.println(val); // debug value }
analogWrite()
void analogWrite (uint8_t pin, int value)
寫模擬引腳
參數(shù):
- pin 引腳編號(hào)
- value 0到255之間的值, 0對(duì)應(yīng)off, 255對(duì)應(yīng)on
寫一個(gè)模擬值(PWM)到引腳. 可以用來(lái)控制LED的亮度, 或者控制電機(jī)的轉(zhuǎn)速. 在執(zhí)行該操作后, 應(yīng)該等待一定時(shí)間后才能對(duì)該引腳進(jìn)行下一次的讀或?qū)懖僮? PWM的頻率大約為490Hz.
在一些基于ATmega168的新的Arduino控制板(如Mini 和BT)中, 該函數(shù)支持以下引腳: 3, 5, 6, 9, 10, 11. 在基于ATmega8的型號(hào)中支持9, 10, 11引腳.
例子:
int ledPin = 9; // LED connected to digital pin 9 int analogPin = 3; // potentiometer connected to analog pin 3 int val = 0; // variable to store the read value void setup() { pinMode(ledPin, OUTPUT); // sets the pin as output } void loop() { val = analogRead(analogPin); // read the input pin analogWrite(ledPin, val / 4); // analogRead values go from 0 to 1023, analogWrite values from 0 to 255 }
高級(jí)I/O
shiftOut()
void shiftOut (uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, byte val)
位移輸出函數(shù)
輸入value數(shù)據(jù)后Arduino會(huì)自動(dòng)把數(shù)據(jù)移動(dòng)分配到8個(gè)并行輸出端. 其中dataPin為連接DS的引腳號(hào), clockPin為連接SH_CP的引腳號(hào), bitOrder為設(shè)置數(shù)據(jù)位移順序, 分別為高位先入MSBFIRST或者低位先入LSBFIRST.
參數(shù):
- dataPin 數(shù)據(jù)引腳
- clockPin 時(shí)鐘引腳
- bitOrder 移位順序 ( MSBFIRST 或 LSBFIRST)
- val 數(shù)據(jù)
// Do this for MSBFIRST serial int data = 500; // shift out highbyte shiftOut(dataPin, clock, MSBFIRST, (data >> 8)); // shift out lowbyte shiftOut(dataPin, clock, MSBFIRST, data); // Or do this for LSBFIRST serial data = 500; // shift out lowbyte shiftOut(dataPin, clock, LSBFIRST, data); // shift out highbyte shiftOut(dataPin, clock, LSBFIRST, (data >> 8));
pulseIn()
unsigned long pulseIn (uint8_t pin, uint8_t state, unsigned long timeout)
讀脈沖
讀引腳的脈沖, 脈沖可以是 HIGH 或 LOW. 如果是 HIGH, 函數(shù)將先等引腳變?yōu)楦唠娖? 然后 開始計(jì)時(shí), 一直到變?yōu)榈碗娖綖橹? 返回脈沖持續(xù)的時(shí)間長(zhǎng)短, 單位為微秒. 如果超時(shí)還沒有 讀到的話, 將返回0.
參數(shù):
- pin 引腳編號(hào)
- state 脈沖狀態(tài)
- timeout 超時(shí)時(shí)間
下面的例子演示了統(tǒng)計(jì)高電平的繼續(xù)時(shí)間:
int pin = 7; unsigned long duration; void setup() { pinMode(pin, INPUT); } void loop() { duration = pulseIn(pin, HIGH); }
時(shí)間
millis()
unsigned long millis (void)
毫秒時(shí)間
獲取機(jī)器運(yùn)行的時(shí)間長(zhǎng)度, 單位毫秒. 系統(tǒng)最長(zhǎng)的記錄時(shí)間為9小時(shí)22分, 如果超出時(shí)間將從0開始.
警告:
時(shí)間為 unsigned long類型, 如果用 int 保存時(shí)間將得到錯(cuò)誤結(jié)果:
delay(ms)
void delay (unsigned long ms)
延時(shí)(毫秒)
延時(shí), 單位毫秒(1秒有1000毫秒).
警告:
參數(shù)為unsigned long, 因此在延時(shí)參數(shù)超過(guò)32767(int型最大值)時(shí), 需要用"UL"后綴表示為無(wú)符號(hào) 長(zhǎng)整型, 例如: delay(60000UL);. 同樣在參數(shù)表達(dá)式, 切表達(dá)式中有int類型時(shí), 需要強(qiáng)制轉(zhuǎn)換為 unsigned long類型, 例如: delay((unsigned long)tdelay * 100UL);.
一下例子設(shè)置13引腳對(duì)應(yīng)的LED等以1秒頻率閃爍:
int ledPin = 13; // LED connected to digital pin 13 void setup() { pinMode(ledPin, OUTPUT); // sets the digital pin as output } void loop() { digitalWrite(ledPin, HIGH); // sets the LED on delay(1000); // waits for a second digitalWrite(ledPin, LOW); // sets the LED off delay(1000); // waits for a second }
delayMicroseconds(us)
void delayMicroseconds (unsigned int us)
延時(shí)(微秒)
延時(shí), 單位為微妙(1毫秒有1000微妙). 如果延時(shí)的時(shí)間有幾千微妙, 那么建議使用 delay 函數(shù). 目前參數(shù)最大支持16383微妙(不過(guò)以后的版本中可能會(huì)變化).
以下代碼向第8號(hào)引腳發(fā)送脈沖, 每次脈沖持續(xù)50微妙的時(shí)間.
int outPin = 8; // digital pin 8 void setup() { pinMode(outPin, OUTPUT); // sets the digital pin as output } void loop() { digitalWrite(outPin, HIGH); // sets the pin on delayMicroseconds(50); // pauses for 50 microseconds digitalWrite(outPin, LOW); // sets the pin off delayMicroseconds(50); // pauses for 50 microseconds }
數(shù)學(xué)庫(kù)
min()
#define min(a, b) ((a)<(b)?(a):(b))
最小值
取兩者之間最小值. 例如:
sensVal = min(sensVal, 100); // assigns sensVal to the smaller of sensVal or 100 // ensuring that it never gets above 100.
max()
#define max(a, b) ((a)>(b)?(a):(b))
最大值
取兩者之間最大值. 例如:
sensVal = max(senVal, 20); // assigns sensVal to the larger of sensVal or 20 // (effectively ensuring that it is at least 20)
abs()
abs(x) ((x)>0?(x):-(x))
求絕對(duì)值
constrain()
#define constrain(amt, low, high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt)))
調(diào)整到區(qū)間
如果值 amt 小于 low, 則返回 low; 如果 amt 大于 high, 則返回 high; 否則, 返回 amt . 一般可以用于將值歸一化到某個(gè)區(qū)間.
例如:
sensVal = constrain(sensVal, 10, 150); // limits range of sensor values to between 10 and 150
map()
long map ( long x, long in_min, long in_max, long out_min, long out_max )
等比映射
將位于[in_min, in_max]之間的x映射到[out_min, out_max].
參數(shù):
- x 要映射的值
- in_min 映射前區(qū)間
- in_max 映射前區(qū)間
- out_min 映射后區(qū)間
- out_max 映射后區(qū)間
例如下面的代碼中用 map 將模擬量從[0,1023]映射到[0,255]區(qū)間:
// Map an analog value to 8 bits (0 to 255) void setup() {} void loop() { int val = analogRead(0); val = map(val, 0, 1023, 0, 255); analogWrite(9, val); } long map(long x, long in_min, long in_max, long out_min, long out_max) { return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; }
pow()
double pow (float base, float exponent) 指數(shù)函數(shù) <br>
sqrt()
double sqrt (double x) //開平方
三角函數(shù)
sin(),cos(),tan()
float sin (float rad) //正弦函數(shù) float cos (float rad) //余弦函數(shù) float tan (float rad) //正切函數(shù)
隨機(jī)數(shù)
randomSeed()
void randomSeed ( unsigned int seed )
設(shè)置隨機(jī)種子
可以用當(dāng)前時(shí)間作為隨機(jī)種子. 隨機(jī)種子的設(shè)置對(duì)產(chǎn)生的隨機(jī)序列有影響.
參數(shù):
- seed 隨機(jī)種子
random()
long random (long howbig)
生成隨機(jī)數(shù)
生成[0, howbig-1]范圍的隨機(jī)數(shù).
參數(shù):
- howbig 最大值
long random (long howsmall, long howbig)
生成隨機(jī)數(shù)
生成[howsmall, howbig-1]范圍的隨機(jī)數(shù).
參數(shù):
- howsmall 最小值
- howbig 最大值
位操作
位操作
#define lowByte(w) ((w) & 0xff) //取低字節(jié) #define highByte(w) ((w) >> 8) //取高字節(jié) #define bitRead(value, bit) (((value) >> (bit)) & 0x01) //讀一個(gè)bit #define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit)) //寫一個(gè)bit #define bitSet(value, bit) ((value) |= (1UL << (bit))) //設(shè)置一個(gè)bit #define bitClear(value, bit) ((value) &= ~(1UL << (bit))) //清空一個(gè)bit #define bit(b) (1 << (b)) //生成相應(yīng)bit
設(shè)置中斷函數(shù)
attachInterrupt()
void attachInterrupt (uint8_t interruptNum, void(*)(void)userFunc, int mode)
設(shè)置中斷
指定中斷函數(shù). 外部中斷有0和1兩種, 一般對(duì)應(yīng)2號(hào)和3號(hào)數(shù)字引腳.
參數(shù):
- interrupt 中斷類型, 0或1
- fun 對(duì)應(yīng)函數(shù)
- mode 觸發(fā)方式. 有以下幾種:
- LOW 低電平觸發(fā)中斷
- CHANGE 變化時(shí)觸發(fā)中斷
- RISING 低電平變?yōu)楦唠娖接|發(fā)中斷
- FALLING 高電平變?yōu)榈碗娖接|發(fā)中斷
注解:
在中斷函數(shù)中 delay 函數(shù)不能使用, millis 始終返回進(jìn)入中斷前的值. 讀串口數(shù)據(jù)的話, 可能會(huì)丟失. 中斷函數(shù)中使用的變量需要定義為 volatile 類型.
下面的例子如果通過(guò)外部引腳觸發(fā)中斷函數(shù), 然后控制LED的閃爍.
int pin = 13; volatile int state = LOW; void setup() { pinMode(pin, OUTPUT); attachInterrupt(0, blink, CHANGE); } void loop() { digitalWrite(pin, state); } void blink() { state = !state; }
detachInterrupt()
void detachInterrupt (uint8_t interruptNum)
取消中斷
取消指定類型的中斷.
參數(shù):
- interrupt 中斷的類型.
interrupts()
#define interrupts() sei()
開中斷
例子:
void setup() {} void loop() { noInterrupts(); // critical, time-sensitive code here interrupts(); // other code here }
noInterrupts()
#define noInterrupts() cli()
關(guān)中斷
例子:
void setup() {} void loop() { noInterrupts(); // critical, time-sensitive code here interrupts(); // other code here }
串口通訊
(該小節(jié)為最新翻譯)
void begin (long) 打開串口
uint8_t available (void) 有串口數(shù)據(jù)返回真
int read (void) //讀串口
void flush (void) //刷新串口數(shù)據(jù)
virtual void write (uint8_t) //寫串口 </pre>
begin()
void HardwareSerial::begin (long speed)
打開串口
參數(shù):
- speed 波特率
available()
獲取串口上可讀取的數(shù)據(jù)的字節(jié)數(shù)。該數(shù)據(jù)是指已經(jīng)到達(dá)并存儲(chǔ)在接收緩存(共有64字節(jié))中。available()繼承自Stream實(shí)用類。
語(yǔ)法:
Serial.available()
Arduino Mega only: Serial1.available() Serial2.available() Serial3.available()
參數(shù):
無(wú)
返回值:
- 返回可讀取的字節(jié)數(shù)
示例:
int incomingByte = 0; // for incoming serial data void setup() { Serial.begin(9600); // opens serial port, sets data rate to 9600 bps } void loop() { // send data only when you receive data: if (Serial.available() > 0) { // read the incoming byte: incomingByte = Serial.read(); // say what you got: Serial.print("I received: "); Serial.println(incomingByte, DEC); } }
Arduino Mega example:
void setup() { Serial.begin(9600); Serial1.begin(9600); } void loop() { // read from port 0, send to port 1: if (Serial.available()) { int inByte = Serial.read(); Serial1.print(inByte, BYTE); } // read from port 1, send to port 0: if (Serial1.available()) { int inByte = Serial1.read(); Serial.print(inByte, BYTE); } }
read()
讀串口數(shù)據(jù),read()繼承自Stream實(shí)用類。
語(yǔ)法:
Serial.read()
Arduino Mega only: Serial1.read() Serial2.read() Serial3.read()
參數(shù):
無(wú)
返回值:
串口上第一個(gè)可讀取的字節(jié)(如果沒有可讀取的數(shù)據(jù)則返回-1)- int型。
示例:
int incomingByte = 0; // 用于存儲(chǔ)從串口讀到的數(shù)據(jù) void setup() { Serial.begin(9600); // 打開串呂,設(shè)置速率為9600 bps } void loop() { // 只在收到數(shù)據(jù)時(shí)發(fā)送數(shù)據(jù) if (Serial.available() > 0) { // 讀取傳入的字節(jié) incomingByte = Serial.read(); // 指示你收到的數(shù)據(jù) Serial.print("I received: "); Serial.println(incomingByte, DEC); } }
flush()
刷新串口數(shù)據(jù)
print()
往串口發(fā)數(shù)據(jù),無(wú)換行
描述
以人類可讀的ASCII碼形式向串口發(fā)送數(shù)據(jù),該函數(shù)有多種格式。整數(shù)的每一數(shù)位將以ASCII碼形式發(fā)送。浮點(diǎn)數(shù)同樣以ASCII碼形式發(fā)送,默認(rèn)保留小數(shù)點(diǎn)后兩位。字節(jié)型數(shù)據(jù)將以單個(gè)字符形式發(fā)送。字符和字符串會(huì)以其相應(yīng)的形式發(fā)送。例如:
Serial.print(78) 發(fā)送 "78" Serial.print(1.23456) 發(fā)送 "1.23" Serial.print('N') 發(fā)送 "N" Serial.print("Hello world.") 發(fā)送 "Hello world."
可選的第二個(gè)參數(shù)用于指定數(shù)據(jù)的格式。允許的值為:BIN (binary二進(jìn)制), OCT (octal八進(jìn)制), DEC (decimal十進(jìn)制), HEX (hexadecimal十六進(jìn)制)。對(duì)于浮點(diǎn)數(shù),該參數(shù)指定小數(shù)點(diǎn)的位數(shù)。例如:
Serial.print(78, BIN) gives "1001110" Serial.print(78, OCT) gives "116" Serial.print(78, DEC) gives "78" Serial.print(78, HEX) gives "4E" Serial.println(1.23456, 0) gives "1" Serial.println(1.23456, 2) gives "1.23" Serial.println(1.23456, 4) gives "1.2346"
你可以用F()把待發(fā)送的字符串包裝到flash存儲(chǔ)器。例如:
Serial.print(F(“Hello World”))
要發(fā)送單個(gè)字節(jié)數(shù)據(jù),請(qǐng)使用Serial.write()。
語(yǔ)法:
Serial.print(val) Serial.print(val, format)
參數(shù):
- val: 要發(fā)送的數(shù)據(jù)(任何數(shù)據(jù)類型)
- format: 指定數(shù)字的基數(shù)(用于整型數(shù))或者小數(shù)的位數(shù)(用于浮點(diǎn)數(shù))。
返回值:<>
- size_t (long): print()返回發(fā)送的字節(jié)數(shù)(可丟棄該返回值)。
示例:
/* Uses a FOR loop for data and prints a number in various formats. */ int x = 0; // variable void setup() { Serial.begin(9600); // open the serial port at 9600 bps: } void loop() { // print labels Serial.print("NO FORMAT"); // prints a label Serial.print("\t"); // prints a tab Serial.print("DEC"); Serial.print("\t"); Serial.print("HEX"); Serial.print("\t"); Serial.print("OCT"); Serial.print("\t"); Serial.print("BIN"); Serial.print("\t"); for(x=0; x< 64; x++){ // only part of the ASCII chart, change to suit // print it out in many formats: Serial.print(x); // print as an ASCII-encoded decimal - same as "DEC" Serial.print("\t"); // prints a tab Serial.print(x, DEC); // print as an ASCII-encoded decimal Serial.print("\t"); // prints a tab Serial.print(x, HEX); // print as an ASCII-encoded hexadecimal Serial.print("\t"); // prints a tab Serial.print(x, OCT); // print as an ASCII-encoded octal Serial.print("\t"); // prints a tab Serial.println(x, BIN); // print as an ASCII-encoded binary // then adds the carriage return with "println" delay(200); // delay 200 milliseconds } Serial.println(""); // prints another carriage return }
編程技巧:
在版本1.0時(shí),串口傳輸是異步的,Serial.print()會(huì)在數(shù)據(jù)發(fā)送完成前返回。
println()
往串口發(fā)數(shù)據(jù),類似Serial.print(),但有換行
write()
寫二進(jìn)制數(shù)據(jù)到串口,數(shù)據(jù)是一個(gè)字節(jié)一個(gè)字節(jié)地發(fā)送的,若以字符形式發(fā)送數(shù)字請(qǐng)使用print()代替。
語(yǔ)法:
Serial.write(val) Serial.write(str) Serial.write(buf, len)
Arduino Mega也支持:Serial1, Serial2, Serial3(在Serial的位置)
參數(shù):
- val: 作為單個(gè)字節(jié)發(fā)送的數(shù)據(jù)
- str: 由一系列字節(jié)組成的字符串
- buf: 同一系列字節(jié)組成的數(shù)組
- len: 要發(fā)送的數(shù)組的長(zhǎng)度
返回:
- byte
write()會(huì)返回發(fā)送的字節(jié)數(shù),所以讀取該返回值是可選的。
示例:
void setup(){ Serial.begin(9600); } void loop(){ Serial.write(45); //以二進(jìn)制形式發(fā)送數(shù)字45 int bytesSent = Serial.write(“hello”); //發(fā)送字符串“hello” 并返回該字符串的長(zhǎng)度。 }
peak()
描述:
返回收到的串口數(shù)據(jù)的下一個(gè)字節(jié)(字符),但是并不把該數(shù)據(jù)從串口數(shù)據(jù)緩存中清除。就是說(shuō),每次成功調(diào)用peak()將返回相同的字符。與read()一樣,peak()繼承自Stream實(shí)用類。
語(yǔ)法:
可參照Serail.read()
serialEvent()
描述:
當(dāng)串口有數(shù)據(jù)到達(dá)時(shí)調(diào)用該函數(shù)(然后使用Serial.read()捕獲該數(shù)據(jù))。
注意:目前serialEvent()并不兼容于Esplora, Leonardo, 或 Micro。
語(yǔ)法:
void serialEvent(){ //statements } Arduino Mega only: void serialEvent1(){ //statements } void serialEvent2(){ //statements } void serialEvent3(){ //statements }
statements可以是任何有效的語(yǔ)句。