Arduino編程參考手冊(cè)
首頁
程序結(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)用。用它來初始化變量,引腳模式,開始使用某個(gè)庫,等等。該函數(shù)在Arduino板的每次上電和復(fù)位時(shí)只運(yùn)行一次。
loop()
在創(chuàng)建setup函數(shù),該函數(shù)初始化和設(shè)置初始值,loop()函數(shù)所做事的正如其名,連續(xù)循環(huán),允許你的程序改變狀態(tài)和響應(yīng)事件??梢杂盟鼇韺?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); }
控制語句
if
if,用于與比較運(yùn)算符結(jié)合使用,測(cè)試是否已達(dá)到某些條件,例如一個(gè)輸入數(shù)據(jù)在某個(gè)范圍之外。使用格式如下:
if (value > 50) { // 這里加入你的代碼 }
該程序測(cè)試value是否大于50。如果是,程序?qū)?zhí)行特定的動(dòng)作。換句話說,如果圓括號(hào)中的語句為真,大括號(hào)中的語句就會(huì)執(zhí)行。如果不是,程序?qū)⑻^這段代碼。大括號(hào)可以被省略,如果這么做,下一行(以分號(hào)結(jié)尾)將成為唯一的條件語句。
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ì)算的語句需要一個(gè)或多個(gè)操作符。
if...else
與基本的if語句相比,由于允許多個(gè)測(cè)試組合在一起,if/else可以使用更多的控制流。例如,可以測(cè)試一個(gè)模擬量輸入,如果輸入值小于500,則采取一個(gè)動(dòng)作,而如果輸入值大于或等于500,則采取另一個(gè)動(dòng)作。代碼看起來像是這樣:
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語句塊,如果存在的話,將被設(shè)為默認(rèn)行為,并執(zhí)行。
注意:一個(gè)else if語句塊可能有或者沒有終止else語句塊,同理。每個(gè)else if分支允許有無限多個(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語句。
for
for語句
描述
for語句用于重復(fù)執(zhí)行被花括號(hào)包圍的語句塊。一個(gè)增量計(jì)數(shù)器通常被用來遞增和終止循環(huán)。for語句對(duì)于任何需要重復(fù)的操作是非常有用的。常常用于與數(shù)組聯(lián)合使用以收集數(shù)據(jù)/引腳。for循環(huán)的頭部有三個(gè)部分:
for (初始化部分; 條件判斷部分; 數(shù)據(jù)遞增部分) { //語句塊 。。。 }
初始化部分被第一個(gè)執(zhí)行,且只執(zhí)行一次。每次通過這個(gè)循環(huán),條件判斷部分將被測(cè)試;如果為真,語句塊和數(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() { //這里無需設(shè)置 } void loop() { for (int i=0; i <= 255; i++){ analogWrite(PWMpin, i); delay(10); } }
編碼提示:
C中的for循環(huán)比在其它計(jì)算機(jī)語言中發(fā)現(xiàn)的for循環(huán)要靈活的多,包括BASIC。三個(gè)頭元素中的任何一個(gè)或全部可能被省略,盡管分號(hào)是必須的。而且初始化部分、條件判斷部分和數(shù)據(jù)遞增部分可以是任何合法的使用任意變量的C語句。且可以使用任何數(shù)據(jù)類型包括floats。這些不常用的類型用于語句段也許可以為一些罕見的編程問題提供解決方案。
例如,在遞增部分中使用一個(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 語句
就像if語句,switch...case通過允許程序員根據(jù)不同的條件指定不同的應(yīng)被執(zhí)行的代碼來控制程序流。特別地,一個(gè)switch語句對(duì)一個(gè)變量的值與case語句中指定的值進(jìn)行比較。當(dāng)一個(gè)case語句被發(fā)現(xiàn)其值等于該變量的值。就會(huì)運(yùn)行這個(gè)case語句下的代碼。
break關(guān)鍵字將中止并跳出switch語句段,常常用于每個(gè)case語句的最后面。如果沒有break語句,switch語句將繼續(xù)執(zhí)行下面的表達(dá)式(“持續(xù)下降”)直到遇到break,或者是到達(dá)switch語句的末尾。
示例:
switch (var) { case 1: //當(dāng)var等于1執(zhí)行這里 break; case 2: //當(dāng)var等于2執(zhí)行這里 break; default: // 如果沒有匹配項(xiàng),將執(zhí)行此缺省段 // default段是可選的 }
語法
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è)傳感器。
語法:
while(expression){ // statement(s) }
參數(shù):
expression - 一個(gè)(布爾型)C語句,被求值為真或假
示例:
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 { // 語句塊 } while (測(cè)試條件);
示例:
do { delay(50); // 等待傳感器穩(wěn)定 x = readSensors(); // 檢查傳感器的值 } while (x < 100);
break
break用于中止do,for,或while循環(huán),繞過正常的循環(huán)條件。它也用于中止switch語句。
示例:
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語句跳過一個(gè)循環(huán)的當(dāng)前迭代的余下部分。(do,for,或while)。通過檢查循環(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è)值,如果你想的話。
語法:
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)
語法:
label: goto label; // sends program flow to the label
提示:
在C程序中不建議使用goto,而且一些C編程書的作者主張永遠(yuǎn)不要使用goto語句,但是明智地使用它可以
簡(jiǎn)化某些代碼。許多程序員不贊成使用goto的原因是,無節(jié)制地使用goto語句很容易產(chǎn)生執(zhí)行流混亂的很難被調(diào)試程序。
盡管如是說,仍然有很多使用goto語句而大大簡(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;} // 其它語句。。。 } } } bailout:
相關(guān)語法
分號(hào)
用于一個(gè)語句的結(jié)束
示例
int a = 13;
提示
忘記在一行的末尾加一個(gè)分號(hào)將產(chǎn)生一個(gè)編譯器錯(cuò)誤。該錯(cuò)誤信息可能是明顯的,且會(huì)提及丟失分號(hào),但也許不會(huì)。如果出現(xiàn)一個(gè)不可理喻的或看起來不合邏輯的錯(cuò)誤,其中一個(gè)首先要做的事就是檢查分號(hào)丟失。編譯器會(huì)在前一行的附近發(fā)出抱怨。
大括號(hào)
大括號(hào)(又稱括弧或花括號(hào))是C語言的主要組成部分。它們用在幾個(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語句,在條件語句中替換ENDIF語句和在FOR循環(huán)中替換NEXT語句。
由于大括號(hào)的使用是如此的多樣,當(dāng)插入一個(gè)需要大括號(hào)的結(jié)構(gòu)時(shí),直接在打出開括號(hào)之后打出閉括號(hào)是個(gè)不錯(cuò)的編程實(shí)踐。然后在大括號(hào)之間插入一些回車符,接著開始插入語句。你的大括號(hào),還有你的態(tài)度,將永遠(yuǎn)不會(huì)變得不平衡。
不平衡的大括號(hào)常常導(dǎo)致古怪的,難以理解的編譯器錯(cuò)誤,有時(shí)在大型程序中很難查出。因?yàn)樗鼈兊亩鄻拥氖褂茫罄ㄌ?hào)對(duì)于程序的語法也是極其重要的,對(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) } //條件語句 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é)尾 /* 這是多行注釋 - 用它來注釋掉整個(gè)代碼塊 if (gwb == 0){ //在多行注釋中使用單行注釋是沒有問題的 x = 3; /* 但是其中不可以使用另一個(gè)多行注釋 - 這是不合法的 */ } //別忘了加上“關(guān)閉”注釋符 - 它們必須是平衡的 */
提示
當(dāng)實(shí)驗(yàn)代碼時(shí),“注釋掉”你的程序的一部分來移除可能是錯(cuò)誤的行是一種方便的方法。這不是把這些行從程序中移除,而是把它們放到注釋中,所以編譯器就會(huì)忽略它們。這在定位問題時(shí),或者當(dāng)程序無法編譯通過且編譯錯(cuò)誤信息很古怪或沒有幫助時(shí)特別有用。
define
#define 宏定義
宏定義是一個(gè)有用的C組件,它允許程序員在程序編譯前給常量取一個(gè)名字。在arduino中定義的常量不會(huì)在芯片中占用任何程序空間。編譯器在編譯時(shí)會(huì)將這些常量引用替換為定義的值。
這雖然可能有些有害的副作用,舉例來說,一個(gè)已被定義的常量名被包含在一些其它的常量或變量名中。那樣的話該文本將被替換成被定義的數(shù)字(或文本)。
通常,用const關(guān)鍵字定義常量是更受歡迎的且用來代替#define會(huì)很有用。
Arduino宏定義與C宏定義有同樣的語法
語法
#define constantName value
注意‘#’是必須的
示例:
#define ledPin 3 // 編譯器在編譯時(shí)會(huì)將任何提及l(fā)edPin的地方替換成數(shù)值3。
提示
#define語句的后面分號(hào)。如果你加了一個(gè),編譯器將會(huì)在進(jìn)一步的頁面引發(fā)奇怪的錯(cuò)誤。
#define ledPin 3; // this is an error
類似地,包含一個(gè)等號(hào)通常也會(huì)在進(jìn)一步的頁面引發(fā)奇怪的編譯錯(cuò)誤。
#define ledPin = 3 // this is also an error
include
#include 包含
#include用于在你的sketch中包含外部的庫。這使程序員可以訪問一個(gè)巨大的標(biāo)準(zhǔn)C庫(預(yù)定義函數(shù)集合)的集合。
AVR C庫(AVR是Atmel芯片的一個(gè)基準(zhǔn),Arduino正是基于它)的主參考手冊(cè)頁在這里。
注意#include和#define相似,沒有分號(hào)終止符,且如果你加了,編譯器會(huì)產(chǎn)生奇怪的錯(cuò)誤信息。
示例
該示例包含一個(gè)用于輸出數(shù)據(jù)到程序空間閃存的庫,而不是內(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語言中單個(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;
語法
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ù)組的大?。?。
語法
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)作。換句話說,如果圓括號(hào)中的語句為真,花括號(hào)中的語句就會(huì)運(yùn)行。否則,程序跳過該代碼。
if語句后的花括號(hào)可能被省略。如果這么做了,下一行(由分號(hào)定義的行)就會(huì)變成唯一的條件語句。
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)中被求值的語句需要使用一個(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)镃如下求值語句if(x=10):10分配給x(切記單個(gè)等號(hào)是賦值運(yùn)算符),因此x現(xiàn)在為10。然后'if'條件求值10,其總是為真,由于任何非零數(shù)值都為真值。由此,if (x = 10)將總是求值為真,這不是使用if語句所期望的結(jié)果。另外,變量x將被設(shè)置為10,這也不是期望的操作。
if也可以是使用[if...else]的分支控制結(jié)構(gòu)的一部分。
布爾運(yùn)算符
它們可用于if語句中的條件
&& (邏輯與)
只有在兩個(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))看起來與布爾非!有很大不同(感嘆號(hào)或程序員口中的“棒”),但是你仍然必須確保在什么地方用哪一個(gè)。
例如
if (a >= 10 && a <= 20){} // true if a is between 10 and 20
指針運(yùn)算符
&(引用)和 *(間接引用)
指針對(duì)于C初學(xué)者來說是更復(fù)雜的對(duì)象之一。并且可能寫大量的Arduino程序甚至都不會(huì)遇到指針。
無論如何,巧妙地控制特定的數(shù)據(jù)結(jié)構(gòu),使用指針可以簡(jiǎn)化代碼,而且在自己工具箱中擁有熟練控制指針的知識(shí)是很方便的。
位運(yùn)算
位與
按位與(&)
按位操作符在變量的位級(jí)執(zhí)行運(yùn)算。它們幫助解決各種常見的編程問題。以下大部分資料來自一個(gè)有關(guān)位數(shù)學(xué)的優(yōu)秀教程,或許可以在這里找到。[1]
描述和語法
以下是所有這些運(yùn)算符的描述和語法。更詳細(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。換句話說:
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è)小小的問題是,我們同時(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(在英語中,通常讀作“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ǔ)碼。
順便說一句,值得注意的是,對(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ù)。
語法
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)討論過的。在這種情況下,符號(hào)位會(huì)復(fù)制到較低的位:
int x = -16; // binary: 1111111111110000 int y = x >> 3; // binary: 1111111111111110
該行為,被稱為符號(hào)擴(kuò)展,常常不是你所期待的。反而,你可能希望移入左邊的是0。事實(shí)上右移規(guī)則對(duì)于無符合整型表達(dá)式是不同的。所以你可以使用強(qiáng)制類型轉(zhuǎn)換來避免左邊移入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ù)定義的變量。它們被用來使程序更易閱讀。我們按組將常量分類。
邏輯層定義,true與false(布爾Boolean常量)
在Arduino內(nèi)有兩個(gè)常量用來表示真和假: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是大小寫敏感語言(case sensitive)。
引腳電壓定義,HIGH和LOW
當(dāng)讀取(read)或?qū)懭耄╳rite)數(shù)字引腳時(shí)只有兩個(gè)可能的值: HIGH 和 LOW 。
HIGH
HIGH(參考引腳)的含義取決于引腳(pin)的設(shè)置,引腳定義為INPUT或OUTPUT時(shí)含義有所不同。當(dāng)一個(gè)引腳通過pinMode被設(shè)置為INPUT,并通過digitalRead讀取(read)時(shí)。如果當(dāng)前引腳的電壓大于等于3V,微控制器將會(huì)返回為HIGH。 引腳也可以通過pinMode被設(shè)置為INPUT,并通過digitalWrite設(shè)置為HIGH。輸入引腳的值將被一個(gè)內(nèi)在的20K上拉電阻 控制 在HIGH上,除非一個(gè)外部電路將其拉低到LOW。 當(dāng)一個(gè)引腳通過pinMode被設(shè)置為OUTPUT,并digitalWrite設(shè)置為HIGH時(shí),引腳的電壓應(yīng)在5V。在這種狀態(tài)下,它可以 輸出電流 。例如,點(diǎn)亮一個(gè)通過一串電阻接地或設(shè)置為L(zhǎng)OW的OUTPUT屬性引腳的LED。
LOW
LOW的含義同樣取決于引腳設(shè)置,引腳定義為INPUT或OUTPUT時(shí)含義有所不同。當(dāng)一個(gè)引腳通過pinMode配置為INPUT,通過digitalRead設(shè)置為讀?。╮ead)時(shí),如果當(dāng)前引腳的電壓小于等于2V,微控制器將返回為L(zhǎng)OW。 當(dāng)一個(gè)引腳通過pinMode配置為OUTPUT,并通過digitalWrite設(shè)置為L(zhǎng)OW時(shí),引腳為0V。在這種狀態(tài)下,它可以 倒灌 電流。例如,點(diǎn)亮一個(gè)通過串聯(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)引腳通過pinMode()配置為 輸入(INPUT) 即是將其配置在一個(gè)高阻抗的狀態(tài)。配置為INPUT的引腳可以理解為引腳取樣時(shí)對(duì)電路有極小的需求,即等效于在引腳前串聯(lián)一個(gè)100兆歐姆(Megohms)的電阻。這使得它們非常利于讀取傳感器,而不是為L(zhǎng)ED供電。
引腳(Pins)配置為輸出(Outputs)
引腳通過pinMode()配置為 輸出(OUTPUT) 即是將其配置在一個(gè)低阻抗的狀態(tài)。
這意味著它們可以為電路提供充足的電流。Atmega引腳可以向其他設(shè)備/電路提供(提供正電流positive current)或倒灌(提供負(fù)電流negative current)達(dá)40毫安(mA)的電流。這使得它們利于給LED供電,而不是讀取傳感器。輸出(OUTPUT)引腳被短路的接地或5V電路上會(huì)受到損壞甚至燒毀。Atmega引腳在為繼電器或電機(jī)供電時(shí),由于電流不足,將需要一些外接電路來實(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,但你可以通過U和L修飾符進(jìn)行更多的限制(見下文)。 通常情況下,整數(shù)常量默認(rèn)為十進(jìn)制,但可以加上特殊前綴表示為其他進(jìn)制。
進(jìn)制 例子 格式 備注 10(十進(jìn)制) 123 無 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前綴很可能無意產(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ū)分大小寫,就是說你也可以用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è)常量為無符號(hào)型。(只能表示正數(shù)和0) 例如: 33u
- 'l' or 'L' 指定一個(gè)常量為長(zhǎng)整型。(表示數(shù)的范圍更廣) 例如: 100000L
- 'ul' or 'UL' 這個(gè)你懂的,就是上面兩種類型,稱作無符號(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ā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值可以用來作數(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è)無符號(hào)一個(gè)字節(jié)(8位)的數(shù)據(jù)類型,使用byte數(shù)據(jù)類型。
例如
char myChar = 'A'; char myChar = 65; // both are equivalent
unsigned char
無符號(hào)字符型
描述
一個(gè)無符號(hào)數(shù)據(jù)類型占用1個(gè)字節(jié)的內(nèi)存。與byte的數(shù)據(jù)類型相同。
無符號(hào)的char數(shù)據(jù)類型能編碼0到255的數(shù)字。
為了保持Arduino的編程風(fēng)格的一致性,byte數(shù)據(jù)類型是首選。
例子
unsigned char myChar = 240;
byte
字節(jié)型
描述
一個(gè)字節(jié)存儲(chǔ)8位無符號(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ì)算問題,所以數(shù)學(xué)計(jì)算對(duì)您是透明的(術(shù)語:實(shí)際存在,但不可操作。相當(dāng)于“黑盒”)。但是,當(dāng)處理右移位運(yùn)算符(?)時(shí),可能有未預(yù)期的編譯過程。
示例
int ledPin = 13;
語法
int var = val;
- var - 變量名
- val - 賦給變量的值
提示
當(dāng)變量數(shù)值過大而超過整數(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
無符號(hào)整型
描述
unsigned int(無符號(hào)整型)與整型數(shù)據(jù)同樣大小,占據(jù)2字節(jié)。它只能用于存儲(chǔ)正數(shù)而不能存儲(chǔ)負(fù)數(shù),范圍0~65,535 (2^16) - 1)。
無符號(hào)整型和整型最重要的區(qū)別是它們的最高位不同,既符號(hào)位。在Arduino整型類型中,如果最高位是1,則此數(shù)被認(rèn)為是負(fù)數(shù),剩下的15位為按2的補(bǔ)碼計(jì)算所得值。
例子
unsigned int ledPin = 13;
語法
unsigned int var = val;
- var - 無符號(hào)變量名稱
- val - 給變量所賦予的值
編程提示
當(dāng)變量的值超過它能表示的最大值時(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位無符號(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’的說明
語法
long var = val;
- var - 長(zhǎng)整型變量名
- var - 賦給變量的值
unsigned long
無符號(hào)長(zhǎng)整型
描述
無符號(hào)長(zhǎng)整型變量擴(kuò)充了變量容量以存儲(chǔ)更大的數(shù)據(jù),它能存儲(chǔ)32位(4字節(jié))數(shù)據(jù)。與標(biāo)準(zhǔn)長(zhǎng)整型不同無符號(hào)長(zhǎng)整型無法存儲(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); }
語法
unsigned long var = val;
- var - 你所定義的變量名
- val - 給變量所賦的值
float
單精度浮點(diǎn)型
描述
float,浮點(diǎn)型數(shù)據(jù),就是有一個(gè)小數(shù)點(diǎn)的數(shù)字。浮點(diǎn)數(shù)經(jīng)常被用來近似的模擬連續(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)算來提高速度。
舉例
float myfloat; float sensorCalbrate = 1.117;
語法
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è)較大的字符串
空終止字符
一般來說,字符串的結(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語言初學(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()
操作符
- [](元素訪問)
- +(串連)
- ==(比較)
array
Arrays (數(shù)組)
數(shù)組是一種可訪問的變量的集合。Arduino的數(shù)組是基于C語言的,因此這會(huì)變得很復(fù)雜,但使用簡(jiǎn)單的數(shù)組是比較簡(jiǎn)單的。
創(chuàng)建(聲明)一個(gè)數(shù)組
下面的方法都可以用來創(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ù),以容納所需的空字符。
訪問數(shù)組
數(shù)組是從零開始索引的,也就說,上面所提到的數(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],該索引是無效的,它將會(huì)是任意的隨機(jī)信息(內(nèi)存地址)
出于這個(gè)原因,你在訪問數(shù)組應(yīng)該小心。若訪問的數(shù)據(jù)超出數(shù)組的末尾(即索引數(shù)大于你聲明的數(shù)組的大小- 1),則將從其他內(nèi)存中讀取數(shù)據(jù)。從這些地方讀取的數(shù)據(jù),除了產(chǎn)生無效的數(shù)據(jù)外,沒有任何作用。向隨機(jī)存儲(chǔ)器中寫入數(shù)據(jù)絕對(duì)是一個(gè)壞主意,通常會(huì)導(dǎo)致不愉快的結(jié)果,如導(dǎo)致系統(tǒng)崩潰或程序故障。要排查這樣的錯(cuò)誤是也是一件難事。 不同于Basic或JAVA,C語言編譯器不會(huì)檢查你訪問的數(shù)組是否大于你聲明的數(shù)組。
指定一個(gè)數(shù)組的值:
mySensVals [0] = 10;
從數(shù)組中訪問一個(gè)值:
X = mySensVals [4];
數(shù)組和循環(huán)
數(shù)組往往在for循環(huán)中進(jìn)行操作,循環(huán)計(jì)數(shù)器可用于訪問每個(gè)數(shù)組元素。例如,將數(shù)組中的元素通過串口打印,你可以這樣做:
int i; for (i = 0; i < 5; i = i + 1) { Serial.println(myPins[i]); }
數(shù)據(jù)類型轉(zhuǎn)換
char()
描述
將一個(gè)變量的類型變?yōu)閏har。
語法
char(x)
參數(shù)
- x:任何類型的值
返回
- char
byte()
描述
將一個(gè)值轉(zhuǎn)換為字節(jié)型數(shù)值。
語法
byte(x)
參數(shù)
- X:任何類型的值
返回
- 字節(jié)
int()
簡(jiǎn)介
將一個(gè)值轉(zhuǎn)換為int類型。
語法
int(x)
參數(shù)
- x:一個(gè)任何類型的值
返回值
- int類型的值
word()
描述
把一個(gè)值轉(zhuǎn)換為word數(shù)據(jù)類型的值,或由兩個(gè)字節(jié)創(chuàng)建一個(gè)字符。
語法
word(x) word(h, l)
參數(shù)
- X:任何類型的值
- H:高階(最左邊)字節(jié)
- L:低序(最右邊)字節(jié)
返回
- 字符
long()
描述
將一個(gè)值轉(zhuǎn)換為長(zhǎng)整型數(shù)據(jù)類型。
語法
long(x)
參數(shù)
- x:任意類型的數(shù)值
返回
- 長(zhǎng)整型數(shù)
float()
描述
將一個(gè)值轉(zhuǎn)換為float型數(shù)值。
語法
float(x)
參數(shù)
- X:任何類型的值
返回
- float型數(shù)
變量作用域&修飾符
變量作用域
變量的作用域
在Arduino使用的C編程語言的變量,有一個(gè)名為 作用域(scope) 的屬性 。這一點(diǎn)與類似BASIC的語言形成了對(duì)比,在BASIC語言中所有變量都是 全局(global) 變量。
在一個(gè)程序內(nèi)的全局變量是可以被所有函數(shù)所調(diào)用的。局部變量只在聲明它們的函數(shù)內(nèi)可見。在Arduino的環(huán)境中,任何在函數(shù)(例如,setup(),loop()等)外聲明的變量,都是全局變量。
當(dāng)程序變得更大更復(fù)雜時(shí),局部變量是一個(gè)有效確定每個(gè)函數(shù)只能訪問其自己變量的途徑。這可以防止,當(dāng)一個(gè)函數(shù)無意中修改另一個(gè)函數(shù)使用的變量的程序錯(cuò)誤。
有時(shí)在一個(gè)for循環(huán)內(nèi)聲明并初始化一個(gè)變量也是很方便的選擇。這將創(chuàng)建一個(gè)只能從for循環(huán)的括號(hào)內(nèi)訪問的變量。
例子:
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)訪問 } }
static (靜態(tài)變量)
static關(guān)鍵字用于創(chuàng)建只對(duì)某一函數(shù)可見的變量。然而,和局部變量不同的是,局部變量在每次調(diào)用函數(shù)時(shí)都會(huì)被創(chuàng)建和銷毀,靜態(tài)變量在函數(shù)調(diào)用后仍然保持著原來的數(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ù)無法改變它的值 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)鍵字是變量修飾符,常用在變量類型的前面,以告訴編譯器和接下來的程序怎么對(duì)待這個(gè)變量。
聲明一個(gè)volatile變量是編譯器的一個(gè)指令。編譯器是一個(gè)將你的C/C++代碼轉(zhuǎn)換成機(jī)器碼的軟件,機(jī)器碼是arduino上的Atmega芯片能識(shí)別的真正指令。
具體來說,它指示編譯器編譯器從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是首選 的定義常量語法。
輔助工具
sizeof() (sizeof運(yùn)算符)
描述
sizeof操作符返回一個(gè)變量類型的字節(jié)數(shù),或者該數(shù)在數(shù)組中占有的字節(jié)數(shù)。
語法
sizeof(variable)
參數(shù)
- variable: 任何變量類型或數(shù)組(如int,float,byte)
示例代碼
sizeof操作符用來處理數(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)看起來應(yīng)該像這樣。
for (i = 0; i < (sizeof(myInts)/sizeof(int)) - 1; i++) { //用myInts[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ò)展模式. 通過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)到引腳. 可以用來控制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ù)超過32767(int型最大值)時(shí), 需要用"UL"后綴表示為無符號(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微妙(不過以后的版本中可能會(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é)庫
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 類型.
下面的例子如果通過外部引腳觸發(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í)用類。
語法:
Serial.available()
Arduino Mega only: Serial1.available() Serial2.available() Serial3.available()
參數(shù):
無
返回值:
- 返回可讀取的字節(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í)用類。
語法:
Serial.read()
Arduino Mega only: Serial1.read() Serial2.read() Serial3.read()
參數(shù):
無
返回值:
串口上第一個(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ù),無換行
描述
以人類可讀的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()。
語法:
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()代替。
語法:
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ù)緩存中清除。就是說,每次成功調(diào)用peak()將返回相同的字符。與read()一樣,peak()繼承自Stream實(shí)用類。
語法:
可參照Serail.read()
serialEvent()
描述:
當(dāng)串口有數(shù)據(jù)到達(dá)時(shí)調(diào)用該函數(shù)(然后使用Serial.read()捕獲該數(shù)據(jù))。
注意:目前serialEvent()并不兼容于Esplora, Leonardo, 或 Micro。
語法:
void serialEvent(){ //statements } Arduino Mega only: void serialEvent1(){ //statements } void serialEvent2(){ //statements } void serialEvent3(){ //statements }
statements可以是任何有效的語句。