Arduino編程參考手冊
首頁
程序結(jié)構(gòu)
(本節(jié)直譯自Arduino官網(wǎng)最新Reference)
在Arduino中, 標準的程序入口main函數(shù)在內(nèi)部被定義, 用戶只需要關(guān)心以下兩個函數(shù):
setup()
當Arduino板起動時setup()函數(shù)會被調(diào)用。用它來初始化變量,引腳模式,開始使用某個庫,等等。該函數(shù)在Arduino板的每次上電和復位時只運行一次。
loop()
在創(chuàng)建setup函數(shù),該函數(shù)初始化和設(shè)置初始值,loop()函數(shù)所做事的正如其名,連續(xù)循環(huán),允許你的程序改變狀態(tài)和響應(yīng)事件。可以用它來實時控制arduino板。
示例:
int buttonPin = 3; void setup() { Serial.begin(9600); //初始化串口 pinMode(buttonPin, INPUT); //設(shè)置3號引腳為輸入模式 } void loop() { if (digitalRead(buttonPin) == HIGH) serialWrite('H'); else serialWrite('L'); delay(1000); }
控制語句
if
if,用于與比較運算符結(jié)合使用,測試是否已達到某些條件,例如一個輸入數(shù)據(jù)在某個范圍之外。使用格式如下:
if (value > 50) { // 這里加入你的代碼 }
該程序測試value是否大于50。如果是,程序?qū)?zhí)行特定的動作。換句話說,如果圓括號中的語句為真,大括號中的語句就會執(zhí)行。如果不是,程序?qū)⑻^這段代碼。大括號可以被省略,如果這么做,下一行(以分號結(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); } // 都是正確的
圓括號中要被計算的語句需要一個或多個操作符。
if...else
與基本的if語句相比,由于允許多個測試組合在一起,if/else可以使用更多的控制流。例如,可以測試一個模擬量輸入,如果輸入值小于500,則采取一個動作,而如果輸入值大于或等于500,則采取另一個動作。代碼看起來像是這樣:
if (pinFiveInput < 500) { // 動作A } else { // 動作B }
else中可以進行另一個if測試,這樣多個相互獨立的測試就可以同時進行。每一個測試一個接一個地執(zhí)行直到遇到一個測試為真為止。當發(fā)現(xiàn)一個測試條件為真時,與其關(guān)聯(lián)的代碼塊就會執(zhí)行,然后程序?qū)⑻酵暾膇f/else結(jié)構(gòu)的下一行。如果沒有一個測試被驗證為真。缺省的else語句塊,如果存在的話,將被設(shè)為默認行為,并執(zhí)行。
注意:一個else if語句塊可能有或者沒有終止else語句塊,同理。每個else if分支允許有無限多個。
if (pinFiveInput < 500) { // 執(zhí)行動作A } else if (pinFiveInput >= 1000) { // 執(zhí)行動作B } else { // 執(zhí)行動作C }
另外一種表達互斥分支測試的方式,是使用switch case語句。
for
for語句
描述
for語句用于重復執(zhí)行被花括號包圍的語句塊。一個增量計數(shù)器通常被用來遞增和終止循環(huán)。for語句對于任何需要重復的操作是非常有用的。常常用于與數(shù)組聯(lián)合使用以收集數(shù)據(jù)/引腳。for循環(huán)的頭部有三個部分:
for (初始化部分; 條件判斷部分; 數(shù)據(jù)遞增部分) { //語句塊 。。。 }
初始化部分被第一個執(zhí)行,且只執(zhí)行一次。每次通過這個循環(huán),條件判斷部分將被測試;如果為真,語句塊和數(shù)據(jù)遞增部分就會被執(zhí)行,然后條件判斷部分就會被再次測試,當條件測試為假時,結(jié)束循環(huán)。
示例:
//使用一個PWM引腳使LED燈閃爍 int PWMpin = 10; // LED在10號引腳串聯(lián)一個470歐姆的電阻 void setup() { //這里無需設(shè)置 } void loop() { for (int i=0; i <= 255; i++){ analogWrite(PWMpin, i); delay(10); } }
編碼提示:
C中的for循環(huán)比在其它計算機語言中發(fā)現(xiàn)的for循環(huán)要靈活的多,包括BASIC。三個頭元素中的任何一個或全部可能被省略,盡管分號是必須的。而且初始化部分、條件判斷部分和數(shù)據(jù)遞增部分可以是任何合法的使用任意變量的C語句。且可以使用任何數(shù)據(jù)類型包括floats。這些不常用的類型用于語句段也許可以為一些罕見的編程問題提供解決方案。
例如,在遞增部分中使用一個乘法將形成對數(shù)級增長:
for(int x = 2; x < 100; x = x * 1.5){ println(x); }
輸出: 2,3,4,6,9,13,19,28,42,63,94
另一個例子,在一個for循環(huán)中使一個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í)行的代碼來控制程序流。特別地,一個switch語句對一個變量的值與case語句中指定的值進行比較。當一個case語句被發(fā)現(xiàn)其值等于該變量的值。就會運行這個case語句下的代碼。
break關(guān)鍵字將中止并跳出switch語句段,常常用于每個case語句的最后面。如果沒有break語句,switch語句將繼續(xù)執(zhí)行下面的表達式(“持續(xù)下降”)直到遇到break,或者是到達switch語句的末尾。
示例:
switch (var) { case 1: //當var等于1執(zhí)行這里 break; case 2: //當var等于2執(zhí)行這里 break; default: // 如果沒有匹配項,將執(zhí)行此缺省段 // default段是可選的 }
語法
switch (var) { case label: // statements break; case label: // statements break; default: // statements }
參數(shù)
var: 與不同的case中的值進行比較的變量
label: 相應(yīng)的case的值
while
while循環(huán)
描述:
while循環(huán)將會連續(xù)地無限地循環(huán),直到圓括號()中的表達式變?yōu)榧?。被測試的變量必須被改變,否則while循環(huán)將永遠不會中止。這可以是你的代碼,比如一個遞增的變量,或者是一個外部條件,比如測試一個傳感器。
語法:
while(expression){ // statement(s) }
參數(shù):
expression - 一個(布爾型)C語句,被求值為真或假
示例:
var = 0; while(var < 200){ // 做兩百次重復的事情 var++; }
do...while
do循環(huán)
do循環(huán)與while循環(huán)使用相同方式工作,不同的是條件是在循環(huán)的末尾被測試的,所以do循環(huán)總是至少會運行一次。
do { // 語句塊 } while (測試條件);
示例:
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語句跳過一個循環(huán)的當前迭代的余下部分。(do,for,或while)。通過檢查循環(huán)測試條件它將繼續(xù)進行隨后的迭代。
示例:
for (x = 0; x < 255; x ++) { if (x > 40 && x < 120){ // create jump in values continue; } digitalWrite(PWMpin, x); delay(50); }
return
終止一個函數(shù),并向被調(diào)用函數(shù)并返回一個值,如果你想的話。
語法:
return; return value; // both forms are valid
參數(shù):
value: 任何類型的變量或常量
示例:
//一個函數(shù),用于對一個傳感器輸入與一個閾值進行比較 int checkSensor(){ if (analogRead(0) > 400) { return 1; else{ return 0; } }
return 關(guān)鍵字對測試一段代碼很方便,不需“注釋掉”大段的可能是錯誤的代碼。
void loop(){ //在此測試代碼是個好想法 return; // 這里是功能不正常的代碼 // 這里的代碼永遠也不會執(zhí)行 }
goto
在程序中轉(zhuǎn)移程序流到一個標記點
語法:
label: goto label; // sends program flow to the label
提示:
在C程序中不建議使用goto,而且一些C編程書的作者主張永遠不要使用goto語句,但是明智地使用它可以
簡化某些代碼。許多程序員不贊成使用goto的原因是,無節(jié)制地使用goto語句很容易產(chǎn)生執(zhí)行流混亂的很難被調(diào)試程序。
盡管如是說,仍然有很多使用goto語句而大大簡化編碼的實例。其中之一就是從一個很深的循環(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)語法
分號
用于一個語句的結(jié)束
示例
int a = 13;
提示
忘記在一行的末尾加一個分號將產(chǎn)生一個編譯器錯誤。該錯誤信息可能是明顯的,且會提及丟失分號,但也許不會。如果出現(xiàn)一個不可理喻的或看起來不合邏輯的錯誤,其中一個首先要做的事就是檢查分號丟失。編譯器會在前一行的附近發(fā)出抱怨。
大括號
大括號(又稱括弧或花括號)是C語言的主要組成部分。它們用在幾個不同的結(jié)構(gòu)中,大致如下,這可能會令初學者感到困惑。
一個左大括號必須有一個右大括號跟在后面。這是一個常被稱為平衡括號的條件。Arduino IDE(集成開發(fā)環(huán)境)包含一個方便的特性以檢驗平衡大括號。只需選擇一個大括號,甚至直接在一個大括號后面點擊插入點,然后它的邏輯上的同伴就會高亮顯示。
目前此功能有些許錯誤,因為IDE經(jīng)常在文本中(錯誤地)發(fā)現(xiàn)一個已經(jīng)被注釋掉的大括號。
初級程序員,和從BASIC轉(zhuǎn)到C的程序員常常發(fā)現(xiàn)使用大括號令人困惑或畏縮。畢竟,用同樣的大括號在子例程(函數(shù))中替換RETURN語句,在條件語句中替換ENDIF語句和在FOR循環(huán)中替換NEXT語句。
由于大括號的使用是如此的多樣,當插入一個需要大括號的結(jié)構(gòu)時,直接在打出開括號之后打出閉括號是個不錯的編程實踐。然后在大括號之間插入一些回車符,接著開始插入語句。你的大括號,還有你的態(tài)度,將永遠不會變得不平衡。
不平衡的大括號常常導致古怪的,難以理解的編譯器錯誤,有時在大型程序中很難查出。因為它們的多樣的使用,大括號對于程序的語法也是極其重要的,對一個大括號移動一行或兩行常常顯著地影響程序的意義。
大括號的主要用法
//函數(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) }
注釋
注釋是程序中的一些行,用于讓自己或他人了解程序的工作方式。他們會被編譯器忽略,而不會輸出到控制器,所以它們不會占用Atmega芯片上的任何空間。
注釋唯一的目的是幫助你理解(或記憶)你的程序是怎樣工作的,或者是告知其他人你的程序是怎樣工作的。標記一行為注釋只有兩種方式:
示例
x = 5; //這是一個單行注釋。此斜線后的任何內(nèi)容都是注釋 //直到該行的結(jié)尾 /* 這是多行注釋 - 用它來注釋掉整個代碼塊 if (gwb == 0){ //在多行注釋中使用單行注釋是沒有問題的 x = 3; /* 但是其中不可以使用另一個多行注釋 - 這是不合法的 */ } //別忘了加上“關(guān)閉”注釋符 - 它們必須是平衡的 */
提示
當實驗代碼時,“注釋掉”你的程序的一部分來移除可能是錯誤的行是一種方便的方法。這不是把這些行從程序中移除,而是把它們放到注釋中,所以編譯器就會忽略它們。這在定位問題時,或者當程序無法編譯通過且編譯錯誤信息很古怪或沒有幫助時特別有用。
define
#define 宏定義
宏定義是一個有用的C組件,它允許程序員在程序編譯前給常量取一個名字。在arduino中定義的常量不會在芯片中占用任何程序空間。編譯器在編譯時會將這些常量引用替換為定義的值。
這雖然可能有些有害的副作用,舉例來說,一個已被定義的常量名被包含在一些其它的常量或變量名中。那樣的話該文本將被替換成被定義的數(shù)字(或文本)。
通常,用const關(guān)鍵字定義常量是更受歡迎的且用來代替#define會很有用。
Arduino宏定義與C宏定義有同樣的語法
語法
#define constantName value
注意‘#’是必須的
示例:
#define ledPin 3 // 編譯器在編譯時會將任何提及l(fā)edPin的地方替換成數(shù)值3。
提示
#define語句的后面分號。如果你加了一個,編譯器將會在進一步的頁面引發(fā)奇怪的錯誤。
#define ledPin 3; // this is an error
類似地,包含一個等號通常也會在進一步的頁面引發(fā)奇怪的編譯錯誤。
#define ledPin = 3 // this is also an error
include
#include 包含
#include用于在你的sketch中包含外部的庫。這使程序員可以訪問一個巨大的標準C庫(預定義函數(shù)集合)的集合。
AVR C庫(AVR是Atmel芯片的一個基準,Arduino正是基于它)的主參考手冊頁在這里。
注意#include和#define相似,沒有分號終止符,且如果你加了,編譯器會產(chǎn)生奇怪的錯誤信息。
示例
該示例包含一個用于輸出數(shù)據(jù)到程序空間閃存的庫,而不是內(nèi)存。這會為動態(tài)內(nèi)存需求節(jié)省存儲空間且使需要創(chuàng)建巨大的查找表變得更實際。
#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ù)運算符
賦值
=賦值運算符(單個等號)
把等號右邊的值存儲到等號左邊的變量中。
在C語言中單個等號被稱為賦值運算符。它與在代數(shù)課中的意義不同,后者象征等式或相等。賦值運算符告訴微控制器求值等號右邊的變量或表達式,然后把結(jié)果存入等號左邊的變量中。
示例
int sensVal; //聲明一個名為sensVal的整型變量 senVal = analogRead(0); //存儲(數(shù)字的)0號模擬引腳的輸入電壓值到sensVal
編程技巧
賦值運算符(=號)左邊的變量需要能夠保存存儲在其中的值。如果它不足以大到容納一個值,那個存儲在該變量中的值將是錯誤的。
不要混淆賦值運算符[ = ](單個等號)和比較運算符[ == ](雙等號),后者求值兩個表達式是否相等。
加,減,乘,除
描述
這些運算符(分別)返回兩人運算對象的和,差,積,商。這些操作受運算對象的數(shù)據(jù)類型的影響。所以,例如,9 / 4結(jié)果是2,如果9和2是整型數(shù)。這也意味著運算會溢出,如果結(jié)果超出其在相應(yīng)的數(shù)據(jù)類型下所能表示的數(shù)。(例如,給整型數(shù)值32767加1結(jié)果是-32768)。如果運算對象是不同的類型,會用那個較大的類型進行計算。
如果其中一個數(shù)字(運算符)是float類型或double類型,將采用浮點數(shù)進行計算。
示例
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:任何變量或常量
編程技巧:
要知道整型常量默認為int型,因此一些常量計算可能會溢出(例如:60 * 1000將產(chǎn)生負的結(jié)果)
選擇一個大小足夠大的變量以容納你的最大的計算結(jié)果。
要知道你的變量在哪一點將會“翻轉(zhuǎn)”且要知道在另一個方向上會發(fā)生什么,例如:(0 - 1)或(0 - 32768)。
對于數(shù)學需要分數(shù),就使用浮點變量,但是要注意它們的缺點:占用空間大,計算速度慢。
使用強制類型轉(zhuǎn)換符例如:(int)myFloat以在運行中轉(zhuǎn)換一個變量到另一個類型。
取模
%(取模)
描述
計算一個數(shù)除以另一個數(shù)的余數(shù)。這對于保持一個變量在一個特定的范圍很有用(例如:數(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 }
提示:
取模運算符不能用于浮點型數(shù)。
比較運算符
if(條件) and ==, !=, <, > (比較運算符)
if,用于和比較運算符聯(lián)合使用,測試某一條件是否到達,例如一個輸入超出某一數(shù)值。if條件測試的格式:
if (someVariable > 50) { // do something here }
該程序測試someVariable是否大于50。如果是, 程序執(zhí)行特定的動作。換句話說,如果圓括號中的語句為真,花括號中的語句就會運行。否則,程序跳過該代碼。
if語句后的花括號可能被省略。如果這么做了,下一行(由分號定義的行)就會變成唯一的條件語句。
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
圓括號中被求值的語句需要使用一個或多個運算符:
比較運算符:
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)
警告:
小心偶然地使用單個等號(例如if(x = 10))。單個等號是賦值運算符,這里設(shè)置x為10(將值10存入變量x)。改用雙等號(例如if (x == 10)),這個是比較運算符,用于測試x是否等于10。后者只在x等于10時返回真,但是前者將總是為真。
這是因為C如下求值語句if(x=10):10分配給x(切記單個等號是賦值運算符),因此x現(xiàn)在為10。然后'if'條件求值10,其總是為真,由于任何非零數(shù)值都為真值。由此,if (x = 10)將總是求值為真,這不是使用if語句所期望的結(jié)果。另外,變量x將被設(shè)置為10,這也不是期望的操作。
if也可以是使用[if...else]的分支控制結(jié)構(gòu)的一部分。
布爾運算符
它們可用于if語句中的條件
&& (邏輯與)
只有在兩個操作數(shù)都為真時才返回真,例如:
if (digitalRead(2) == HIGH && digitalRead(3) == HIGH) { // read two switches // ... }
只在兩個輸入都為高時返回真
|| (邏輯或)
任意一個為真時返回真,例如:
if (x > 0 || y > 0) { // ... }
x或y任意一個大于0時返回真
! (非)
當操作數(shù)為假時返回真,例如:
if (!x) { // ... }
若x為假返回真(即如果x等于0)
警告
確保你沒有把布爾與運算符,&&(兩個與符號)錯認為按位與運算符&(單個與符號)。它們是完全不同的概念。
同樣,不要混淆布爾或運算符||(雙豎杠)與按位或運算符|(單豎杠)。
按位取反~(波浪號)看起來與布爾非!有很大不同(感嘆號或程序員口中的“棒”),但是你仍然必須確保在什么地方用哪一個。
例如
if (a >= 10 && a <= 20){} // true if a is between 10 and 20
指針運算符
&(引用)和 *(間接引用)
指針對于C初學者來說是更復雜的對象之一。并且可能寫大量的Arduino程序甚至都不會遇到指針。
無論如何,巧妙地控制特定的數(shù)據(jù)結(jié)構(gòu),使用指針可以簡化代碼,而且在自己工具箱中擁有熟練控制指針的知識是很方便的。
位運算
位與
按位與(&)
按位操作符在變量的位級執(zhí)行運算。它們幫助解決各種常見的編程問題。以下大部分資料來自一個有關(guān)位數(shù)學的優(yōu)秀教程,或許可以在這里找到。[1]
描述和語法
以下是所有這些運算符的描述和語法。更詳細的資料或許可以在參考指南中找到。
按位與(&)
在C++中按位與運算符是單個與符號,
用于其它兩個整型表達式之間使用。按位與運算獨立地在周圍的表達式的每一位上執(zhí)行操作。根據(jù)這一規(guī)則:如果兩個輸入位都是1,結(jié)果輸出1,否則輸出0。表達這一思想的另一個方法是:
0 0 1 1 operand1 0 1 0 1 operand2 ---------- 0 0 0 1 (operand1 & operand2) - returned result
在Arduino中,int型是16位的。所以在兩個整型表達式之間使用&將會導致16個與運算同時發(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中,以二進制存入的結(jié)果值01000100,即十進制的68。
按位與的其中一個最常用的用途是從一個整型數(shù)中選擇特定的位,常被稱為掩碼屏蔽??慈缦率纠?br />
位或
按位或(|)
在C++中按位或運算符是垂直的條桿符號,|。就像&運算符,|獨立地計算它周圍的兩個整型表達式的每一位。(當然)它所做的是不同的(操作)。兩個輸入位其中一個或都是1按位或?qū)⒌玫?,否則為0。換句話說:
0 0 1 1 operand1 0 1 0 1 operand2 ---------- 0 1 1 1 (operand1 | operand2) - returned result
這是一個使用一小斷C++代碼描述的按位或(運算)的例子:
int a = 92; // in binary: 0000000001011100 int b = 101; // in binary: 0000000001100101 int c = a | b; // result: 0000000001111101, or 125 in decimal.
按位與和按位或的一個共同的工作是在端口上進行程序員稱之為讀-改-寫的操作。在微控制器中,每個端口是一個8位數(shù)字,每一位表示一個引腳的狀態(tài)。寫一個端口可以同時控制所有的引腳。
PORTD是內(nèi)建的參照數(shù)字口0,1,2,3,4,5,6,7的輸出狀態(tài)的常量。如果一個比特位是1,那么該引腳置高。(引腳總是需要用pinMode()指令設(shè)置為輸出模式)。所以如果我們寫入PORTD = B00110001;我們就會讓引腳2,3和7輸出高。一個小小的問題是,我們同時也改變了某些引腳的0,1狀態(tài)。這用于Arduino與串口通訊,所以我們可能會干擾串口通訊。
我們的程序規(guī)則是:
僅僅獲取和清除我們想控制的與相應(yīng)引腳對應(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++中有一個有點不尋常的操作,它被稱為按位異或,或者XOR(在英語中,通常讀作“eks-or”)。按位異或運算符使用符號^。該運算符與按位或運算符“|”非常相似 ,唯一的不同是當輸入位都為1時它返回0。
0 0 1 1 operand1 0 1 0 1 operand2 ---------- 0 1 1 0 (operand1 ^ operand2) - returned result
看待XOR的另一個視角是,當輸入不同時結(jié)果為1,當輸入相同時結(jié)果為0。
這里是一個簡單的示例代碼:
int x = 12; // binary: 1100 int y = 10; // binary: 1010 int z = x ^ y; // binary: 0110, or decimal 6
“^”運算符常用于翻轉(zhuǎn)整數(shù)表達式的某些位(例如從0變?yōu)?,或從1變?yōu)?)。在一個按位異或操作中,如果相應(yīng)的掩碼位為1, 該位將翻轉(zhuǎn),如果為0,該位不變。以下是一個閃爍引腳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īng)用于其右側(cè)的單個操作數(shù)。按位取反操作會翻轉(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é)果為一個負數(shù):-104,你可能會感到驚訝,這是因為一個整型變量的最高位是所謂的符號位。如果最高位為1,該整數(shù)被解釋為負數(shù)。這里正數(shù)和負數(shù)的編碼被稱為二進制補碼。欲了解更多信息,請參閱維基百科條目:補碼。
順便說一句,值得注意的是,對于任何整數(shù)x, ~x 與 -x-1 相等。
有時候,符號位在有符號整數(shù)表達式中能引起一些不期的意外。
左移、右移
左移運算(<<),右移運算(>>)
描述
From The Bitmath Tutorial in The Playground
在C++中有兩個移位運算符:左移運算符<<和右移運算符>>。這些運算符將使左邊操作數(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
當把x左移y位(x << y),x中最左邊的y位將會丟失。
int a = 5; // binary: 0000000000000101 int b = a << 14; // binary: 0100000000000000 - 101中的第一個1被丟棄
如果您確信沒有值被移出,理解左移位運算符一個簡單的辦法是,把它的左操作數(shù)乘2將提高其冪值。例如,要生成2的乘方,可以使用以下表達式:
1 << 0 == 1 1 << 1 == 2 1 << 2 == 4 1 << 3 == 8 ... 1 << 8 == 256 1 << 9 == 512 1 << 10 == 1024 ...
當把x右移y位,x的最高位為1,該行為依賴于x的確切的數(shù)據(jù)類型。如果x的類型是int,最高位為符號位,決定x是不是負數(shù),正如我們在上面已經(jīng)討論過的。在這種情況下,符號位會復制到較低的位:
int x = -16; // binary: 1111111111110000 int y = x >> 3; // binary: 1111111111111110
該行為,被稱為符號擴展,常常不是你所期待的。反而,你可能希望移入左邊的是0。事實上右移規(guī)則對于無符合整型表達式是不同的。所以你可以使用強制類型轉(zhuǎn)換來避免左邊移入1。
int x = -16; // binary: 1111111111110000 int y = (unsigned int)x >> 3; // binary: 0001111111111110
如果你可以很小心地避免符號擴展,你可以使用右移位運算符>>,作為除以2的冪的一種方法。例如
int x = 1000; int y = x >> 3; // 1000除以8,得y = 125.
復合運算符
自加++ i++; //相當于 i = i + 1; 自減-- i--; //相當于 i = i - 1; 復合加+= i+=5; //相當于 i = i + 5; 復合減-= i-=5; //相當于 i = i - 5; 復合乘*= i*=5; //相當于 i = i * 5; 復合除/= i/=5; //相當于 i = i / 5; 復合與&= i&=5; //相當于 i = i & 5; 復合或|= i|=5; //相當于 i = i | 5;
變量
(本節(jié)轉(zhuǎn)自極客工坊)
常量
constants是在Arduino語言里預定義的變量。它們被用來使程序更易閱讀。我們按組將常量分類。
邏輯層定義,true與false(布爾Boolean常量)
在Arduino內(nèi)有兩個常量用來表示真和假:true和 false。
false
在這兩個常量中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
當讀?。╮ead)或?qū)懭耄╳rite)數(shù)字引腳時只有兩個可能的值: HIGH 和 LOW 。
HIGH
HIGH(參考引腳)的含義取決于引腳(pin)的設(shè)置,引腳定義為INPUT或OUTPUT時含義有所不同。當一個引腳通過pinMode被設(shè)置為INPUT,并通過digitalRead讀?。╮ead)時。如果當前引腳的電壓大于等于3V,微控制器將會返回為HIGH。 引腳也可以通過pinMode被設(shè)置為INPUT,并通過digitalWrite設(shè)置為HIGH。輸入引腳的值將被一個內(nèi)在的20K上拉電阻 控制 在HIGH上,除非一個外部電路將其拉低到LOW。 當一個引腳通過pinMode被設(shè)置為OUTPUT,并digitalWrite設(shè)置為HIGH時,引腳的電壓應(yīng)在5V。在這種狀態(tài)下,它可以 輸出電流 。例如,點亮一個通過一串電阻接地或設(shè)置為LOW的OUTPUT屬性引腳的LED。
LOW
LOW的含義同樣取決于引腳設(shè)置,引腳定義為INPUT或OUTPUT時含義有所不同。當一個引腳通過pinMode配置為INPUT,通過digitalRead設(shè)置為讀?。╮ead)時,如果當前引腳的電壓小于等于2V,微控制器將返回為LOW。 當一個引腳通過pinMode配置為OUTPUT,并通過digitalWrite設(shè)置為LOW時,引腳為0V。在這種狀態(tài)下,它可以 倒灌 電流。例如,點亮一個通過串聯(lián)電阻連接到+5V,或到另一個引腳配置為OUTPUT、HIGH的的LED。
數(shù)字引腳(Digital pins)定義,INPUT和OUTPUT
數(shù)字引腳當作 INPUT 或 OUTPUT都可以 。用pinMode()方法使一個數(shù)字引腳從INPUT到OUTPUT變化。
引腳(Pins)配置為輸入(Inputs)
Arduino(Atmega)引腳通過pinMode()配置為 輸入(INPUT) 即是將其配置在一個高阻抗的狀態(tài)。配置為INPUT的引腳可以理解為引腳取樣時對電路有極小的需求,即等效于在引腳前串聯(lián)一個100兆歐姆(Megohms)的電阻。這使得它們非常利于讀取傳感器,而不是為LED供電。
引腳(Pins)配置為輸出(Outputs)
引腳通過pinMode()配置為 輸出(OUTPUT) 即是將其配置在一個低阻抗的狀態(tài)。
這意味著它們可以為電路提供充足的電流。Atmega引腳可以向其他設(shè)備/電路提供(提供正電流positive current)或倒灌(提供負電流negative current)達40毫安(mA)的電流。這使得它們利于給LED供電,而不是讀取傳感器。輸出(OUTPUT)引腳被短路的接地或5V電路上會受到損壞甚至燒毀。Atmega引腳在為繼電器或電機供電時,由于電流不足,將需要一些外接電路來實現(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。默認情況下,這些數(shù)字被視為int,但你可以通過U和L修飾符進行更多的限制(見下文)。 通常情況下,整數(shù)常量默認為十進制,但可以加上特殊前綴表示為其他進制。
進制 例子 格式 備注 10(十進制) 123 無 2(二進制) B1111011 前綴'B' 只適用于8位的值(0到255)字符0-1有效 8(八進制) 0173 前綴”0” 字符0-7有效 16(十六進制) 0x7B 前綴”0x” 字符0-9,A-F,A-F有效
小數(shù)是十進制數(shù)。這是數(shù)學常識。如果一個數(shù)沒有特定的前綴,則默認為十進制。
二進制以2為基底,只有數(shù)字0和1是有效的。
示例:
101 //和十進制5等價 (1*2^2 + 0*2^1 + 1*2^0)
二進制格式只能是8位的,即只能表示0-255之間的數(shù)。如果輸入二進制數(shù)更方便的話,你可以用以下的方式:
myInt = (B11001100 * 256) + B10101010; // B11001100 作為高位。
八進制是以8為基底,只有0-7是有效的字符。前綴“0”(數(shù)字0)表示該值為八進制。
0101 // 等同于十進制數(shù)65 ((1 * 8^2) + (0 * 8^1) + 1)
警告:八進制數(shù)0前綴很可能無意產(chǎn)生很難發(fā)現(xiàn)的錯誤,因為你可能不小心在常量前加了個“0”,結(jié)果就悲劇了。
十六進制以16為基底,有效的字符為0-9和A-F。十六進制數(shù)用前綴“0x”(數(shù)字0,字母愛克斯)表示。請注意,A-F不區(qū)分大小寫,就是說你也可以用a-f。
示例:
0x101 // 等同于十進制257 ((1 * 16^2) + (0 * 16^1) + 1)
U & L 格式
默認情況下,整型常量被視作int型。要將整型常量轉(zhuǎn)換為其他類型時,請遵循以下規(guī)則:
- 'u' or 'U' 指定一個常量為無符號型。(只能表示正數(shù)和0) 例如: 33u
- 'l' or 'L' 指定一個常量為長整型。(表示數(shù)的范圍更廣) 例如: 100000L
- 'ul' or 'UL' 這個你懂的,就是上面兩種類型,稱作無符號長整型。 例如:32767ul
浮點數(shù)常量
浮點常量
和整型常量類似,浮點常量可以使得代碼更具可讀性。浮點常量在編譯時被轉(zhuǎn)換為其表達式所取的值。 例子
n = .005; 浮點數(shù)可以用科學記數(shù)法表示。'E'和'e'都可以作為有效的指數(shù)標志。
浮點數(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ù)將不會被返回任何數(shù)據(jù)到它被調(diào)用的函數(shù)中。
例子
//功能在“setup”和“l(fā)oop”被執(zhí)行 //但沒有數(shù)據(jù)被返回到高一級的程序中 void setup() { // ... } void loop() { // ... }
boolean
布爾
一個布爾變量擁有兩個值,true或false。(每個布爾變量占用一個字節(jié)的內(nèi)存。)
例子
int LEDpin = 5; // LED與引腳5相連 int switchPin = 13; // 開關(guān)的一個引腳連接引腳13,另一個引腳接地。 boolean running = false; void setup() { pinMode(LEDpin, OUTPUT); pinMode(switchPin, INPUT); digitalWrite(switchPin, HIGH); // 打開上拉電阻 } void loop() { if (digitalRead(switchPin) == LOW) { // 按下開關(guān) - 使引腳拉向高電勢 delay(100); // 通過延遲,以濾去開關(guān)抖動產(chǎn)生的雜波 running = !running; // 觸發(fā)running變量 digitalWrite(LEDpin, running) //點亮LED } }
char
char
描述
一個數(shù)據(jù)類型,占用1個字節(jié)的內(nèi)存存儲一個字符值。字符都寫在單引號,如'A'(多個字符(字符串)使用雙引號,如“ABC”)。
字符以編號的形式存儲。你可以在ASCII表中看到對應(yīng)的編碼。這意味著字符的ASCII值可以用來作數(shù)學計算。(例如'A'+ 1,因為大寫A的ASCII值是65,所以結(jié)果為66)。如何將字符轉(zhuǎn)換成數(shù)字參考serial.println命令。
char數(shù)據(jù)類型是有符號的類型,這意味著它的編碼為-128到127。對于一個無符號一個字節(jié)(8位)的數(shù)據(jù)類型,使用byte數(shù)據(jù)類型。
例如
char myChar = 'A'; char myChar = 65; // both are equivalent
unsigned char
無符號字符型
描述
一個無符號數(shù)據(jù)類型占用1個字節(jié)的內(nèi)存。與byte的數(shù)據(jù)類型相同。
無符號的char數(shù)據(jù)類型能編碼0到255的數(shù)字。
為了保持Arduino的編程風格的一致性,byte數(shù)據(jù)類型是首選。
例子
unsigned char myChar = 240;
byte
字節(jié)型
描述
一個字節(jié)存儲8位無符號數(shù),從0到255。
例子
byte b = B10010; // "B" 是二進制格式(B10010等于十進制18)
int
整型
簡介
整數(shù)是基本數(shù)據(jù)類型,占用2字節(jié)。整數(shù)的范圍為-32,768到32,767( -2^15 ~(2^15)-1)。
整數(shù)類型使用2的補碼方式存儲負數(shù)。最高位通常為符號位,表示數(shù)的正負。其余位被“取反加1”(此處請參考補碼相關(guān)資料,不再贅述)。
Arduino為您處理負數(shù)計算問題,所以數(shù)學計算對您是透明的(術(shù)語:實際存在,但不可操作。相當于“黑盒”)。但是,當處理右移位運算符(?)時,可能有未預期的編譯過程。
示例
int ledPin = 13;
語法
int var = val;
- var - 變量名
- val - 賦給變量的值
提示
當變量數(shù)值過大而超過整數(shù)類型所能表示的范圍時(-32,768到32,767),變量值會“回滾”(詳情見示例)。
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
無符號整型
描述
unsigned int(無符號整型)與整型數(shù)據(jù)同樣大小,占據(jù)2字節(jié)。它只能用于存儲正數(shù)而不能存儲負數(shù),范圍0~65,535 (2^16) - 1)。
無符號整型和整型最重要的區(qū)別是它們的最高位不同,既符號位。在Arduino整型類型中,如果最高位是1,則此數(shù)被認為是負數(shù),剩下的15位為按2的補碼計算所得值。
例子
unsigned int ledPin = 13;
語法
unsigned int var = val;
- var - 無符號變量名稱
- val - 給變量所賦予的值
編程提示
當變量的值超過它能表示的最大值時它會“滾回”最小值,反向也會出現(xiàn)這種現(xiàn)象。
unsigned int x x = 0; x = x - 1; //x現(xiàn)在等于65535--向負數(shù)方向滾回 x = x + 1; //x現(xiàn)在等于0--滾回
word
字
描述
一個存儲一個16位無符號數(shù)的字符,取值范圍從0到65535,與unsigned int相同。
例子
word w = 10000;
long
長整型
描述
長整數(shù)型變量是擴展的數(shù)字存儲變量,它可以存儲32位(4字節(jié))大小的變量,從-2,147,483,648到2,147,483,647。
例子
long speedOfLight = 186000L; //參見整數(shù)常量‘L’的說明
語法
long var = val;
- var - 長整型變量名
- var - 賦給變量的值
unsigned long
無符號長整型
描述
無符號長整型變量擴充了變量容量以存儲更大的數(shù)據(jù),它能存儲32位(4字節(jié))數(shù)據(jù)。與標準長整型不同無符號長整型無法存儲負數(shù),其范圍從0到4,294,967,295(2 ^ 32 - 1)。
例子
unsigned long time; void setup() { Serial.begin(9600); } void loop() { Serial.print("Time: "); time = millis(); //程序開始后一直打印時間 Serial.println(time); //等待一秒鐘,以免發(fā)送大量的數(shù)據(jù) delay(1000); }
語法
unsigned long var = val;
- var - 你所定義的變量名
- val - 給變量所賦的值
float
單精度浮點型
描述
float,浮點型數(shù)據(jù),就是有一個小數(shù)點的數(shù)字。浮點數(shù)經(jīng)常被用來近似的模擬連續(xù)值,因為他們比整數(shù)更大的精確度。浮點數(shù)的取值范圍在3.4028235 E+38 ~ -3.4028235E +38。它被存儲為32位(4字節(jié))的信息。
float只有6-7位有效數(shù)字。這指的是總位數(shù),而不是小數(shù)點右邊的數(shù)字。與其他平臺不同的是,在那里你可以使用double型得到更精確的結(jié)果(如15位),在Arduino上,double型與float型的大小相同。
浮點數(shù)字在有些情況下是不準確的,在數(shù)據(jù)大小比較時,可能會產(chǎn)生奇怪的結(jié)果。例如 6.0 / 3.0 可能不等于 2.0。你應(yīng)該使兩個數(shù)字之間的差額的絕對值小于一些小的數(shù)字,這樣就可以近似的得到這兩個數(shù)字相等這樣的結(jié)果。
浮點運算速度遠遠慢于執(zhí)行整??數(shù)運算,例如,如果這個循環(huán)有一個關(guān)鍵的計時功能,并需要以最快的速度運行,就應(yīng)該避免浮點運算。程序員經(jīng)常使用較長的程式把浮點運算轉(zhuǎn)換成整數(shù)運算來提高速度。
舉例
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,因為整數(shù)不能容納分數(shù) z = (float)x / 2.0; // Z為0.5(你必須使用2.0做除數(shù),而不是2)
double
雙清度浮點型
描述
雙精度浮點數(shù)。占用4個字節(jié)。
目前的arduino上的double實現(xiàn)和float相同,精度并未提高。
提示
如果你從其他地方得到的代碼中包含了double類變量,最好檢查一遍代碼以確認其中的變量的精確度能否在arduino上達到。
string
string(字符串)
描述
文本字符串可以有兩種表現(xiàn)形式。你可以使用字符串數(shù)據(jù)類型(這是0019版本的核心部分),或者你可以做一個字符串,由char類型的數(shù)組和空終止字符('\0')構(gòu)成。(求助,待潤色-Leo)本節(jié)描述了后一種方法。而字符串對象(String object)將讓你擁有更多的功能,同時也消耗更多的內(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中 聲明一個沒有初始化的字符數(shù)組
- 在Str2中 聲明一個字符數(shù)組(包括一個附加字符),編譯器會自動添加所需的空字符
- 在Str3中 明確加入空字符
- 在Str4中 用引號分隔初始化的字符串常數(shù),編譯器將調(diào)整數(shù)組的大小,以適應(yīng)字符串常量和終止空字符
- 在Str5中 初始化一個包括明確的尺寸和字符串常量的數(shù)組
- 在Str6中 初始化數(shù)組,預留額外的空間用于一個較大的字符串
空終止字符
一般來說,字符串的結(jié)尾有一個空終止字符(ASCII代碼0)。以此讓功能函數(shù)(例如Serial.pring())知道一個字符串的結(jié)束。否則,他們將從內(nèi)存繼續(xù)讀取后續(xù)字節(jié),而這些并不屬于所需字符串的一部分。
這意味著,你的字符串比你想要的文字包含更多的個字符空間。這就是為什么Str2和Str5需要八個字符,即使“Arduino”只有七個字符 - 最后一個位置會自動填充空字符。str4將自動調(diào)整為八個字符,包括一個額外的空。在Str3的,我們自己已經(jīng)明確地包含了空字符(寫入'\ 0')。
需要注意的是,字符串可能沒有一個最后的空字符(例如在Str2中您已定義字符長度為7,而不是8)。這會破壞大部分使用字符串的功能,所以不要故意而為之。如果你注意到一些奇怪的現(xiàn)象(在字符串中操作字符),基本就是這個原因?qū)е碌牧恕?br /> 單引號?還是雙引號?
定義字符串時使用雙引號(例如“ABC”),而定義一個單獨的字符時使用單引號(例如'A')
包裝長字符串
你可以像這樣打包長字符串: char myString[] = “This is the first line” ” this is the second line” ” etcetera”;
字符串數(shù)組
當你的應(yīng)用包含大量的文字,如帶有液晶顯示屏的一個項目,建立一個字符串數(shù)組是非常便利的。因為字符串本身就是數(shù)組,它實際上是一個兩維數(shù)組的典型。
在下面的代碼,”char*”在字符數(shù)據(jù)類型char后跟了一個星號'*'表示這是一個“指針”數(shù)組。所有的數(shù)組名實際上是指針,所以這需要一個數(shù)組的數(shù)組。指針對于C語言初學者而言是非常深奧的部分之一,但我們沒有必要了解詳細指針,就可以有效地應(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版的核心的一部分,允許你實現(xiàn)比運用字符數(shù)組更復雜的文字操作。你可以連接字符串,增加字符串,尋找和替換子字符串以及其他操作。它比使用一個簡單的字符數(shù)組需要更多的內(nèi)存,但它更方便。
僅供參考,字符串數(shù)組都用小寫的string表示而String類的實例通常用大寫的String表示。注意,在“雙引號”內(nèi)指定的字符常量通常被作為字符數(shù)組,并非String類實例。
函數(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語言的,因此這會變得很復雜,但使用簡單的數(shù)組是比較簡單的。
創(chuàng)建(聲明)一個數(shù)組
下面的方法都可以用來創(chuàng)建(聲明)數(shù)組。
myInts [6]; myPins [] = {2,4,8,3,6}; mySensVals [6] = {2,4,-8,3,2}; char message[6] = "hello";
你聲明一個未初始化數(shù)組,例如myPins。
在myPins中,我們聲明了一個沒有明確大小的數(shù)組。編譯器將會計算元素的大小,并創(chuàng)建一個適當大小的數(shù)組。
當然,你也可以初始化數(shù)組的大小,例如在mySensVals中。請注意,當聲明一個char類型的數(shù)組時,你初始化的大小必須大于元素的個數(shù),以容納所需的空字符。
訪問數(shù)組
數(shù)組是從零開始索引的,也就說,上面所提到的數(shù)組初始化,數(shù)組第一個元素是為索引0,因此:
mySensVals [0] == 2,mySensVals [1] == 4,
依此類推 。
這也意味著,在包含十個元素的數(shù)組中,索引九是最后一個元素。因此,
int myArray[10] = {9,3,2,4,3,2,7,8,9,11}; // myArray[9]的數(shù)值為11 // myArray[10],該索引是無效的,它將會是任意的隨機信息(內(nèi)存地址)
出于這個原因,你在訪問數(shù)組應(yīng)該小心。若訪問的數(shù)據(jù)超出數(shù)組的末尾(即索引數(shù)大于你聲明的數(shù)組的大小- 1),則將從其他內(nèi)存中讀取數(shù)據(jù)。從這些地方讀取的數(shù)據(jù),除了產(chǎn)生無效的數(shù)據(jù)外,沒有任何作用。向隨機存儲器中寫入數(shù)據(jù)絕對是一個壞主意,通常會導致不愉快的結(jié)果,如導致系統(tǒng)崩潰或程序故障。要排查這樣的錯誤是也是一件難事。 不同于Basic或JAVA,C語言編譯器不會檢查你訪問的數(shù)組是否大于你聲明的數(shù)組。
指定一個數(shù)組的值:
mySensVals [0] = 10;
從數(shù)組中訪問一個值:
X = mySensVals [4];
數(shù)組和循環(huán)
數(shù)組往往在for循環(huán)中進行操作,循環(huán)計數(shù)器可用于訪問每個數(shù)組元素。例如,將數(shù)組中的元素通過串口打印,你可以這樣做:
int i; for (i = 0; i < 5; i = i + 1) { Serial.println(myPins[i]); }
數(shù)據(jù)類型轉(zhuǎn)換
char()
描述
將一個變量的類型變?yōu)閏har。
語法
char(x)
參數(shù)
- x:任何類型的值
返回
- char
byte()
描述
將一個值轉(zhuǎn)換為字節(jié)型數(shù)值。
語法
byte(x)
參數(shù)
- X:任何類型的值
返回
- 字節(jié)
int()
簡介
將一個值轉(zhuǎn)換為int類型。
語法
int(x)
參數(shù)
- x:一個任何類型的值
返回值
- int類型的值
word()
描述
把一個值轉(zhuǎn)換為word數(shù)據(jù)類型的值,或由兩個字節(jié)創(chuàng)建一個字符。
語法
word(x) word(h, l)
參數(shù)
- X:任何類型的值
- H:高階(最左邊)字節(jié)
- L:低序(最右邊)字節(jié)
返回
- 字符
long()
描述
將一個值轉(zhuǎn)換為長整型數(shù)據(jù)類型。
語法
long(x)
參數(shù)
- x:任意類型的數(shù)值
返回
- 長整型數(shù)
float()
描述
將一個值轉(zhuǎn)換為float型數(shù)值。
語法
float(x)
參數(shù)
- X:任何類型的值
返回
- float型數(shù)
變量作用域&修飾符
變量作用域
變量的作用域
在Arduino使用的C編程語言的變量,有一個名為 作用域(scope) 的屬性 。這一點與類似BASIC的語言形成了對比,在BASIC語言中所有變量都是 全局(global) 變量。
在一個程序內(nèi)的全局變量是可以被所有函數(shù)所調(diào)用的。局部變量只在聲明它們的函數(shù)內(nèi)可見。在Arduino的環(huán)境中,任何在函數(shù)(例如,setup(),loop()等)外聲明的變量,都是全局變量。
當程序變得更大更復雜時,局部變量是一個有效確定每個函數(shù)只能訪問其自己變量的途徑。這可以防止,當一個函數(shù)無意中修改另一個函數(shù)使用的變量的程序錯誤。
有時在一個for循環(huán)內(nèi)聲明并初始化一個變量也是很方便的選擇。這將創(chuàng)建一個只能從for循環(huán)的括號內(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)括號內(nèi)訪問 } }
static (靜態(tài)變量)
static關(guān)鍵字用于創(chuàng)建只對某一函數(shù)可見的變量。然而,和局部變量不同的是,局部變量在每次調(diào)用函數(shù)時都會被創(chuàng)建和銷毀,靜態(tài)變量在函數(shù)調(diào)用后仍然保持著原來的數(shù)據(jù)。
靜態(tài)變量只會在函數(shù)第一次調(diào)用的時候被創(chuàng)建和初始化。
例子
/* RandomWalk * Paul Badger 2007 * RandomWalk函數(shù)在兩個終點間隨機的上下移動 * 在一個循環(huán)中最大的移動由參數(shù)“stepsize”決定 *一個靜態(tài)變量向上和向下移動一個隨機量 *這種技術(shù)也被叫做“粉紅噪聲”或“醉步” */ #define randomWalkLowRange -20 #define randomWalkHighRange 20 int stepsize; INT thisTime; int total; void setup() { Serial.begin(9600); } void loop() { // 測試randomWalk 函數(shù) stepsize = 5; thisTime = randomWalk(stepsize); serial.println(thisTime); delay(10); } int randomWalk(int moveSize){ static int place; // 在randomwalk中存儲變量 // 聲明為靜態(tài)因此它在函數(shù)調(diào)用之間能保持數(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)樨摲较?} return place; }
volatile (易變變量)
volatile關(guān)鍵字
volatile這個關(guān)鍵字是變量修飾符,常用在變量類型的前面,以告訴編譯器和接下來的程序怎么對待這個變量。
聲明一個volatile變量是編譯器的一個指令。編譯器是一個將你的C/C++代碼轉(zhuǎn)換成機器碼的軟件,機器碼是arduino上的Atmega芯片能識別的真正指令。
具體來說,它指示編譯器編譯器從RAM而非存儲寄存器中讀取變量,存儲寄存器是程序存儲和操作變量的一個臨時地方。在某些情況下,存儲在寄存器中的變量值可能是不準確的。
如果一個變量所在的代碼段可能會意外地導致變量值改變那此變量應(yīng)聲明為volatile,比如并行多線程等。在arduino中,唯一可能發(fā)生這種現(xiàn)象的地方就是和中斷有關(guān)的代碼段,成為中斷服務(wù)程序。
例子
//當中斷引腳改變狀態(tài)時,開閉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)鍵字代表常量。它是一個變量限定符,用于修改變量的性質(zhì),使其變?yōu)橹蛔x狀態(tài)。這意味著該變量,就像任何相同類型的其他變量一樣使用,但不能改變其值。如果嘗試為一個const變量賦值,編譯時將會報錯。
const關(guān)鍵字定義的常量,遵守 variable scoping 管轄的其他變量的規(guī)則。這一點加上使用 #define的缺陷 ,使 const 關(guān)鍵字成為定義常量的一個的首選方法。
例子
const float pi = 3.14; float x; // .... x = pi * 2; // 在數(shù)學表達式中使用常量不會報錯 pi = 7; // 錯誤的用法 - 你不能修改常量值,或給常量賦值。
#define 或 const
您可以使用 const 或 #define 創(chuàng)建數(shù)字或字符串常量。但 arrays, 你只能使用 const。 一般 const 相對 的#define是首選 的定義常量語法。
輔助工具
sizeof() (sizeof運算符)
描述
sizeof操作符返回一個變量類型的字節(jié)數(shù),或者該數(shù)在數(shù)組中占有的字節(jié)數(shù)。
語法
sizeof(variable)
參數(shù)
- variable: 任何變量類型或數(shù)組(如int,float,byte)
示例代碼
sizeof操作符用來處理數(shù)組非常有效,它能很方便的改變數(shù)組的大小而不用破壞程序的其他部分。
這個程序一次打印出一個字符串文本的字符。嘗試改變一下字符串。
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); } }
請注意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 引腳編號
- 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 }
注解:
- 模擬引腳也可以當作數(shù)字引腳使用, 編號為14(對應(yīng)模擬引腳0)到19(對應(yīng)模擬引腳5).
digitalWrite()
void digitalWrite (uint8_t pin, uint8_t value)
寫數(shù)字引腳
寫數(shù)字引腳, 對應(yīng)引腳的高低電平. 在寫引腳之前, 需要將引腳設(shè)置為OUTPUT模式.
參數(shù):
- pin 引腳編號
- 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); // 點亮LED delay(1000); // 等待1秒 digitalWrite(ledPin, LOW); // 關(guān) delay(1000); // waits for a second }
注解:
- 模擬引腳也可以當作數(shù)字引腳使用, 編號為14(對應(yīng)模擬引腳0)到19(對應(yīng)模擬引腳5).
digitalRead()
int digitalRead (uint8_t pin)
讀數(shù)字引腳
讀數(shù)字引腳, 返回引腳的高低電平. 在讀引腳之前, 需要將引腳設(shè)置為INPUT模式.
參數(shù):
- pin 引腳編號
返回:
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 }
注解:
如果引腳沒有鏈接到任何地方, 那么將隨機返回 HIGH 或 LOW.
模擬I/O
analogReference()
void analogReference (uint8_t type)
配置參考電壓
配置模式引腳的參考電壓. 函數(shù) analogRead 在讀取模擬值之后, 將根據(jù)參考電壓將 模擬值轉(zhuǎn)換到[0,1023]區(qū)間. 有以下類型:
DEFAULT : 默認5V.
INTERNAL: 低功耗模式. ATmega168和ATmega8對應(yīng)1.1V到2.56V.
EXTERNAL: 擴展模式. 通過AREF引腳獲取參考電壓.
參數(shù):
- type 參考類型(DEFAULT/INTERNAL/EXTERNAL)
analogRead()
int analogRead (uint8_t pin)
讀模擬引腳
讀模擬引腳, 返回[0-1023]之間的值. 每讀一次需要花1微妙的時間.
參數(shù):
- pin 引腳編號
返回:
- 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 引腳編號
- value 0到255之間的值, 0對應(yīng)off, 255對應(yīng)on
寫一個模擬值(PWM)到引腳. 可以用來控制LED的亮度, 或者控制電機的轉(zhuǎn)速. 在執(zhí)行該操作后, 應(yīng)該等待一定時間后才能對該引腳進行下一次的讀或?qū)懖僮? PWM的頻率大約為490Hz.
在一些基于ATmega168的新的Arduino控制板(如Mini 和BT)中, 該函數(shù)支持以下引腳: 3, 5, 6, 9, 10, 11. 在基于ATmega8的型號中支持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 }
高級I/O
shiftOut()
void shiftOut (uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder, byte val)
位移輸出函數(shù)
輸入value數(shù)據(jù)后Arduino會自動把數(shù)據(jù)移動分配到8個并行輸出端. 其中dataPin為連接DS的引腳號, clockPin為連接SH_CP的引腳號, bitOrder為設(shè)置數(shù)據(jù)位移順序, 分別為高位先入MSBFIRST或者低位先入LSBFIRST.
參數(shù):
- dataPin 數(shù)據(jù)引腳
- clockPin 時鐘引腳
- 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)楦唠娖? 然后 開始計時, 一直到變?yōu)榈碗娖綖橹? 返回脈沖持續(xù)的時間長短, 單位為毫秒. 如果超時還沒有 讀到的話, 將返回0.
參數(shù):
- pin 引腳編號
- state 脈沖狀態(tài)
- timeout 超時時間
下面的例子演示了統(tǒng)計高電平的繼續(xù)時間:
int pin = 7; unsigned long duration; void setup() { pinMode(pin, INPUT); } void loop() { duration = pulseIn(pin, HIGH); }
時間
millis()
unsigned long millis (void)
毫秒時間
獲取機器運行的時間長度, 單位毫秒. 系統(tǒng)最長的記錄時間為9小時22分, 如果超出時間將從0開始.
警告:
時間為 unsigned long類型, 如果用 int 保存時間將得到錯誤結(jié)果:
delay(ms)
void delay (unsigned long ms)
延時(毫秒)
延時, 單位毫秒(1秒有1000毫秒).
警告:
參數(shù)為unsigned long, 因此在延時參數(shù)超過32767(int型最大值)時, 需要用"UL"后綴表示為無符號 長整型, 例如: delay(60000UL);. 同樣在參數(shù)表達式, 切表達式中有int類型時, 需要強制轉(zhuǎn)換為 unsigned long類型, 例如: delay((unsigned long)tdelay * 100UL);.
一下例子設(shè)置13引腳對應(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)
延時(微秒)
延時, 單位為微妙(1毫秒有1000微妙). 如果延時的時間有幾千微妙, 那么建議使用 delay 函數(shù). 目前參數(shù)最大支持16383微妙(不過以后的版本中可能會變化).
以下代碼向第8號引腳發(fā)送脈沖, 每次脈沖持續(xù)50微妙的時間.
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ù)學庫
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))
求絕對值
constrain()
#define constrain(amt, low, high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt)))
調(diào)整到區(qū)間
如果值 amt 小于 low, 則返回 low; 如果 amt 大于 high, 則返回 high; 否則, 返回 amt . 一般可以用于將值歸一化到某個區(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ù)
隨機數(shù)
randomSeed()
void randomSeed ( unsigned int seed )
設(shè)置隨機種子
可以用當前時間作為隨機種子. 隨機種子的設(shè)置對產(chǎn)生的隨機序列有影響.
參數(shù):
- seed 隨機種子
random()
long random (long howbig)
生成隨機數(shù)
生成[0, howbig-1]范圍的隨機數(shù).
參數(shù):
- howbig 最大值
long random (long howsmall, long howbig)
生成隨機數(shù)
生成[howsmall, howbig-1]范圍的隨機數(shù).
參數(shù):
- howsmall 最小值
- howbig 最大值
位操作
位操作
#define lowByte(w) ((w) & 0xff) //取低字節(jié) #define highByte(w) ((w) >> 8) //取高字節(jié) #define bitRead(value, bit) (((value) >> (bit)) & 0x01) //讀一個bit #define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit)) //寫一個bit #define bitSet(value, bit) ((value) |= (1UL << (bit))) //設(shè)置一個bit #define bitClear(value, bit) ((value) &= ~(1UL << (bit))) //清空一個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兩種, 一般對應(yīng)2號和3號數(shù)字引腳.
參數(shù):
- interrupt 中斷類型, 0或1
- fun 對應(yīng)函數(shù)
- mode 觸發(fā)方式. 有以下幾種:
- LOW 低電平觸發(fā)中斷
- CHANGE 變化時觸發(fā)中斷
- RISING 低電平變?yōu)楦唠娖接|發(fā)中斷
- FALLING 高電平變?yōu)榈碗娖接|發(fā)中斷
注解:
在中斷函數(shù)中 delay 函數(shù)不能使用, millis 始終返回進入中斷前的值. 讀串口數(shù)據(jù)的話, 可能會丟失. 中斷函數(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)到達并存儲在接收緩存(共有64字節(jié))中。available()繼承自Stream實用類。
語法:
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實用類。
語法:
Serial.read()
Arduino Mega only: Serial1.read() Serial2.read() Serial3.read()
參數(shù):
無
返回值:
串口上第一個可讀取的字節(jié)(如果沒有可讀取的數(shù)據(jù)則返回-1)- int型。
示例:
int incomingByte = 0; // 用于存儲從串口讀到的數(shù)據(jù) void setup() { Serial.begin(9600); // 打開串呂,設(shè)置速率為9600 bps } void loop() { // 只在收到數(shù)據(jù)時發(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ā)送。浮點數(shù)同樣以ASCII碼形式發(fā)送,默認保留小數(shù)點后兩位。字節(jié)型數(shù)據(jù)將以單個字符形式發(fā)送。字符和字符串會以其相應(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."
可選的第二個參數(shù)用于指定數(shù)據(jù)的格式。允許的值為:BIN (binary二進制), OCT (octal八進制), DEC (decimal十進制), HEX (hexadecimal十六進制)。對于浮點數(shù),該參數(shù)指定小數(shù)點的位數(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存儲器。例如:
Serial.print(F(“Hello World”))
要發(fā)送單個字節(jié)數(shù)據(jù),請使用Serial.write()。
語法:
Serial.print(val) Serial.print(val, format)
參數(shù):
- val: 要發(fā)送的數(shù)據(jù)(任何數(shù)據(jù)類型)
- format: 指定數(shù)字的基數(shù)(用于整型數(shù))或者小數(shù)的位數(shù)(用于浮點數(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時,串口傳輸是異步的,Serial.print()會在數(shù)據(jù)發(fā)送完成前返回。
println()
往串口發(fā)數(shù)據(jù),類似Serial.print(),但有換行
write()
寫二進制數(shù)據(jù)到串口,數(shù)據(jù)是一個字節(jié)一個字節(jié)地發(fā)送的,若以字符形式發(fā)送數(shù)字請使用print()代替。
語法:
Serial.write(val) Serial.write(str) Serial.write(buf, len)
Arduino Mega也支持:Serial1, Serial2, Serial3(在Serial的位置)
參數(shù):
- val: 作為單個字節(jié)發(fā)送的數(shù)據(jù)
- str: 由一系列字節(jié)組成的字符串
- buf: 同一系列字節(jié)組成的數(shù)組
- len: 要發(fā)送的數(shù)組的長度
返回:
- byte
write()會返回發(fā)送的字節(jié)數(shù),所以讀取該返回值是可選的。
示例:
void setup(){ Serial.begin(9600); } void loop(){ Serial.write(45); //以二進制形式發(fā)送數(shù)字45 int bytesSent = Serial.write(“hello”); //發(fā)送字符串“hello” 并返回該字符串的長度。 }
peak()
描述:
返回收到的串口數(shù)據(jù)的下一個字節(jié)(字符),但是并不把該數(shù)據(jù)從串口數(shù)據(jù)緩存中清除。就是說,每次成功調(diào)用peak()將返回相同的字符。與read()一樣,peak()繼承自Stream實用類。
語法:
可參照Serail.read()
serialEvent()
描述:
當串口有數(shù)據(jù)到達時調(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可以是任何有效的語句。