一、結構
1.1 setup()
1.2 loop()
二、結構控制
2.1 if
2.2 if…else
2.3 for
2.4 switch case
2.5 while
2.6 do… while
2.7 break
2.8 continue
2.9 return
2.10 goto
三、擴展語法
3.1 ;(分號)
3.2 {}(花括號)
3.3 //(單行註釋)
3.4 /* */(多行註釋)
3.5 #define
3.6 #include
四、算數運算符
4.1 =(賦值運算符)
4.2 +(加)
4.3 -(減)
4.4 *(乘)
4.5 /(除)
4.6 %(模)
五、比較運算符
5.1 ==(等於)
5.2 !=(不等於)
5.3 <(小於)
5.4 >(大於)
5.5 <=(小於等於)
5.6 >=(大於等於)
六、布爾運算符
6.1 &&(與)
6.2 ||(或)
6.3 !(非)
七、指針運算符
7.1 * 取消引用運算符
7.2 & 引用運算符
八、位運算符
8.1 & (bitwise and)
8.2 | (bitwise or)
8.3 ^ (bitwise xor)
8.4 ~ (bitwise not)
8.5 << (bitshift left)
8.6 >> (bitshift right)
九、複合運算符
9.1 ++ (increment)
9.2 – (decrement)
9.3 += (compound addition)
9.4 -= (compound subtraction)
9.5 *= (compound multiplication)
9.6 /= (compound division)
9.6 &= (compound bitwise and)
9.8 |= (compound bitwise or)
一、結構
————————————————————————————————————————————
1.1 setup()
在Arduino中程序運行時將首先調用 setup() 函數。用於初始化變量、設置針腳的輸出\輸入類型、配置串口、引入類庫文件等等。每次 Arduino 上電或重啓後,setup 函數只運行一次。
示例
int buttonPin = 3;//定義一個變量buttonPin爲針腳3
void setup()
{
Serial.begin(9600);//定義初始串口波特率爲9600
pinMode(buttonPin, INPUT);//定義buttonPin也就是前面定義的針腳3爲input輸入針腳
}
void loop()
{
// …
}
1.2 loop()
在 setup() 函數中初始化和定義了變量,然後執行 loop() 函數。顧名思義,該函數在程序運行過程中不斷的循環,根據一些反饋,相應改變執行情況。通過該函數動態控制 Arduino 主控板。
示例
int buttonPin = 3; // setup 中初始化串口和按鍵針腳.
void setup()
{
beginSerial(9600);
pinMode(buttonPin, INPUT);
}
// loop 中每次都檢查按鈕,如果按鈕被按下,就發送信息到串口
void loop()
{
if (digitalRead(buttonPin) == HIGH)//通過eigitalRead讀取到針腳3的電平值是否爲高
serialWrite(‘H’);//是高就通過串口寫出H
else
serialWrite(‘L’);//如果不是就通過串口寫出L
delay(1000);//延時1000毫秒,也就是1秒
}
二、結構控制
————————————————————————————————————————————
2.1 if
if(條件判斷語句)和 ==、!=、<、>(比較運算符)
if 語句與比較運算符一起用於檢測某個條件是否達成,如某輸入值是否在特定值之上等。if 語句的語法是:
if (someVariable > 50)
{
// 執行某些語句
}
本程序測試 someVariable 變量的值是否大於 50。當大於 50 時,執行一些語句。換句話說,只要 if 後面括號裏的結果(稱之爲測試表達式)爲真,則執行大括號中的語句(稱之爲執行語句塊);若爲假,則跳過大括號中的語句。 if 語句後的大括號可以省略。若省略大括號,則只有一條語句(以分號結尾)成爲執行語句。
下面幾種寫法都是正確的:
第一種:
if (x > 120) digitalWrite(LEDpin, HIGH);//判斷x的值是不是大於120,是的話就讓LEDpin這個針腳的電平成爲高電平
第二種:
if (x > 120)
digitalWrite(LEDpin, HIGH);
第三種:
if (x > 120){ digitalWrite(LEDpin, HIGH); }
第四種:
if (x > 120){
digitalWrite(LEDpin1, HIGH);
digitalWrite(LEDpin2, HIGH);
}
在小括號裏求值的表達式,需要以下操作符:
比較運算操作符:
x == y(x 等於 y)注意這是等於,並不是賦值,賦值是=
x != y(x 不等於 y)
x < y(x 小於 y)
x > y(x 大於 y)
x <= y(x 小於等於 y)
x >= y(x 大於等於 y)
警告:
注意使用賦值運算符的情況(如 if (x = 10))。一個“=”表示的是賦值運算符,作用是將 x 的值設爲 10(將值 10 放入 x 變量的內存中)。兩個“=”表示的是比較運算符(如 if (x == 10)),用於測試 x 和 10 是否相等。後面這個語句只有 x 是 10 時才爲真,而前面賦值的那個語句則永遠爲真。
這是因爲 C 語言按以下規則進行運算 if (x=10):10 賦值給 x(只要非 0 的數賦值的語句,其賦值表達式的值永遠爲真),因此 x 現在值爲 10。此時 if 的測試表達式值爲 10,該值永遠爲真,因爲非 0 值永遠爲真。所以,if (x = 10) 將永遠爲真,這就不是我們運行 if 所期待的結果。另外,x 被賦值爲 10,這也不是我們所期待的結果。
if 的另外一種分支條件控制結構是 if…else 形式。
2.2 if…else
if/else是比if更爲高級的流程控制語句,它可以進行多次條件測試。比如,檢測模擬輸入的值,當它小於500時該執行哪些操作,大於或等於500時執行另外的操作。代碼如下:
if (pinFiveInput < 500)
{
// 執行A操作
}
else
{
// 執行B操作
}
else可以進行額外的if檢測,所以多個互斥的條件可以同時進行檢測。
測試將一個一個進行下去,直到某個測試結果爲真,此時該測試相關的執行語句塊將被運行,然後程序就跳過剩下的檢測,直接執行到if/else的下一條語句。當所有檢測都爲假時,若存在else語句塊,將執行默認的else語句塊。
注意else if語句塊可以沒有else語句塊。else if分支語句的數量無限制。
if (pinFiveInput < 500)
{
// 執行A操作
}
else if (pinFiveInput >= 1000)
{
// 執行B操作
}
else
{
// 執行C操作
}
另外一種進行多種條件分支判斷的語句是switch case語句。
2.3 for
for語句
描述
for語句用於重複執行一段在花括號之內的代碼。通常使用一個增量計數器計數並終止循環。for語句用於重複性的操作非常有效,通常與數組結合起來使用來操作數據、引腳。
for循環開頭有3個部分:
(初始化;條件;增量計數){
//語句
}
“初始化”只在循環開始執行一次。每次循環,都會檢測一次條件;如果條件爲真,則執行語句和“增量計數”,之後再檢測條件。當條件爲假時,循環終止。
例子
//用PWM引腳將LED變暗
int PWMpin = 10; //將一個LED與47Ω電阻串聯接在10號針腳
void setup()
{
//無需設置
}
void loop()
{
for (int i=0; i <= 255; i++)//定義一個變量i,並賦值爲0,當i小於等於255的時候i就加1,也可寫成i+=5,這樣每循環一次i就加5
{
analogWrite(PWMpin, i);//讓10號針腳的電平改變爲i
delay(10);//延時10毫秒
}
}
編程提示
C語言的for循環語句比BASIC和其他電腦編程語言的for語句更靈活。除了分號以外,其他3個元素都能省略。同時,初始化,條件,增量計算可以是任何包括無關變量的有效C語句,任何C數據類型包括float。這些不尋常的for語句可能會解決一些困難的編程問題。
例如,在增量計數中使用乘法可以得到一個等比數列:
for(int x = 2; x < 100; x = x * 1.5){//定義X爲2,當X小於100的時候X重新賦值爲它自己的1.5倍
println(x);//打印輸出x的值
}
生成:2,3,4,6,9,13,19,28,42,63,94
另一個例子,使用for循環使LED產生漸亮漸滅的效果:
int PWMpin = 10; //將一個LED與47Ω電阻串聯接在10號針腳
void setup()
{
//無需設置
}
void loop()
{
int x = 1; //定義一個整數變量x賦值爲1
for (int i = 0; i > -1; i = i + x) //定義i爲0當i小於負一的時候,i的值爲它自己加上X,也就是加上1,燈就依次變亮了
{
analogWrite(PWMpin, i); //讓PWMpin針腳的電平變爲i
if (i == 255) x = -1; // 當i等於最大值255的時候,把x改變爲負一,這樣再循環上去的時候i的值就會依次減一,就由亮變暗了
delay(10); //延時10毫秒,如果還想讓燈由暗變亮的話就再寫個判斷
if(i==0) x=1; //當i減小到0的時候又把x變成1,這樣i就又依次加1,燈由暗變亮了
delay(10);
}
}
2.4 switch case
switch / case語句
和if語句相同,switch…case通過程序員設定的在不同條件下執行的代碼控制程序的流程。特別地,switch語句將變量值和case語句中設定的值進行比較。當一個case語句中的設定值與變量值相同時,這條case語句將被執行。
關鍵字break可用於退出switch語句,通常每條case語句都以break結尾。如果沒有break語句,switch語句將會一直執行接下來的語句(一直向下)直到遇見一個break,或者直到switch語句結尾。
語法也是先switch然後跟括號()括號內寫上變量值,後面跟大括號,大括號裏寫上case分支
例子
switch (var) {
case 1: //case 1後面是冒號
//當var等於1時,執行一些語句
break;
case 2
//當var等於2時,執行一些語句
break;
default:
//如果沒有任何匹配,執行default
//default可有可不有
}
語法
switch (var) { //定義檢查var的值
case label1: //如果var的值是label1的就就執行下面的語句
// 程序語句
break;
case label2: //如果var的值是label2的就就執行下面的語句
//程序語句
break;
default: //如果var的值都不在上面的裏面的話就執行下面的語句
//程序語句
}
參數
var: 用於與下面的case中的標籤進行比較的變量值
label: 與變量進行比較的值
2.5 while
while循環
描述
while循環會無限的循環,直到括號內的判斷語句變爲假。必須要有能改變判斷語句的東西,要不然while循環將永遠不會結束。這在您的代碼表現爲一個遞增的變量,或一個外部條件,如傳感器的返回值。
語法
while(表達){
//語句
}
參數
表達:爲真或爲假的一個計算結果
例子
var = 0; //定義一個變量var賦值爲0
while(var < 200){ //當var的值小於200的時候執行下面的語句
var++ //var依次加1,加200次,直到var的值不小於200爲止
}
2.6 do…while
do…while循環與while循環運行的方式是相近的,不過它的條件判斷是在每個循環的最後,所以這個語句至少會被運行一次,然後才被結束。
do
{
//語句
}while(測試條件);
例子
do
{
delay(50); //延時50秒
X = readSensors(); //給X賦值
}while(X <100); //當x小於100時,繼續運行,當x不小於100的時候就不運行了
2.7 break
break用於退出do,for,while循環,能繞過一般的判斷條件。它也能夠用於退出switch語句。
例子
for (x = 0; x < 255; x ++)
{
digitalWrite(PWMpin, x);
sens = analogRead(sensorPin);
if (sens > threshold){
x = 0;
break; //這裏用break就打斷循環了,相當於在此結束了,程序就不再循環了
}
delay(50);
}
2.8 continue
continue語句跳過當前循環中剩餘的迭代部分( do,for 或 while )。它通過檢查循環條件表達式,並繼續進行任何後續迭代。
例子
for (x = 0; x < 255; x ++)
{
if (x > 40 && x < 120){
continue; // 當x在40與120之間時,跳過後面兩句,即迭代。
}
digitalWrite(PWMpin, x);
delay(50);
}
2.9 return
終止一個函數,如有返回值,將從此函數返回給調用函數。
語法
return;
return value; // 兩種形式均可
參數
value:任何變量或常量的類型
例子
一個比較傳感器輸入閾值的函數
int checkSensor(){ //這兒定義了一個整數形函數checkSensor
if (analogRead(0) > 400) { //如果讀取0針腳的數據大於400的話
return 1;} //返回1,相當於調用這個函數後得到的值是1
else{
return 0; //返回0,相當於調用這個函數後得到的值是0
}
}
return關鍵字可以很方便的測試一段代碼,而無需“comment out(註釋掉)” 大段的可能存在bug的代碼。
void loop(){
//寫入漂亮的代碼來測試這裏。
return;
//剩下的功能異常的程序
//return後的代碼永遠不會被執行
}
2.10 goto
程序將會從程序中已有的標記點開始運行,這個東西,少用
語法
label:
goto label; //從label處開始運行
提示
不要在C語言中使用goto編程,某些C編程作者認爲goto語句永遠是不必要的,但用得好,它可以簡化某些特定的程序。許多程序員不同意使用goto的原因是, 通過毫無節制地使用goto語句,很容易創建一個程序,這種程序擁有不確定的運行流程,因而無法進行調試。感覺就像你明明在1上一下就跳到了8上,並 不是從上而下的過程。
的確在有的實例中goto語句可以派上用場,並簡化代碼。例如在一定的條件用if語句來跳出高度嵌入的for循環。
例子
for(byte r = 0; r < 255; r++){
for(byte g = 255; g > -1; g–){
for(byte b = 0; b < 255; b++){
if (analogRead(0) > 250){
goto bailout; //這兒有一個goto語句所以程序會跳轉到下一個bailout
}
//更多的語句…
}
}
}
bailout: //goto語句跳轉到這兒繼續執行
三、擴展語法
————————————————————————————————————————————
3.1 ;(分號)
用於表示一句代碼的結束。
例子
int a = 13;
提示
在每一行忘記使用分號作爲結尾,將導致一個編譯錯誤。錯誤提示可能會清晰的指向缺少分號的那行,也可能不會。如果彈出一個令人費解或看似不合邏輯的編譯器錯誤,第一件事就是在錯誤附近檢查是否缺少分號。
3.2 {}(花括號也稱大括號)
大括號(也稱爲“括號”或“大括號”)是C編程語言中的一個重要組成部分。它們被用來區分幾個不同的結構,下面列出的,有時可能使初學者混亂。
左大括號“{”必須與一個右大括號“}”形成閉合。這是一個常常被稱爲括號平衡的條件。在Arduino IDE(集成開發環境)中有一個方便的功能來檢查大括號是否平衡。只需選擇一個括號,甚至單擊緊接括號的插入點,就能知道這個括號的“伴侶括號”。
目前此功能稍微有些錯誤,因爲IDE會經常會認爲在註釋中的括號是不正確的。
對於初學者,以及由BASIC語言轉向學習C語言的程序員,經常不清楚如何使用括號。畢竟,大括號還會在”return函數”、“endif條件句”以及“loop函數”中被使用到。
由於大括號被用在不同的地方,這有一種很好的編程習慣以避免錯誤:輸入一個大括號後,同時也輸入另一個大括號以達到平衡。然後在你的括號之間輸入回車,然後再插入語句。這樣一來,你的括號就不會變得不平衡了。
不平衡的括號常可導致許多錯誤,比如令人費解的編譯器錯誤,有時很難在一個程序找到這個錯誤。由於其不同的用法,括號也是一個程序中非常重要的語法,如果括號發生錯誤,往往會極大地影響了程序的意義。
大括號中的主要用途
功能 函數
void myfunction(datatype argument){
statements(s)
}
循環
while (boolean expression)
{
statement(s)
}
do
{
statement(s)
}
while (boolean expression);
for (initialisation; termination condition; incrementing expr)
{
statement(s)
}
條件語句
if (boolean expression)
{
statement(s)
}
else if (boolean expression)
{
statement(s)
}
else
{
statement(s)
}
3.3 //(單行註釋)
Comments(註釋)
註釋用於提醒自己或他人程序是如何工作的。它們會被編譯器忽略掉,也不會傳送給處理器,不會執行,所以它們在Atmega芯片上不佔用體積。 註釋的唯一作用就是使你自己理解或幫你回憶你的程序是怎麼工作的或提醒他人你的程序是如何工作的。編寫註釋有兩種寫法:
例子
x = 5; // 這是一條註釋斜槓後面本行內的所有東西是註釋
/* 這是多行註釋-用於註釋一段代碼
if (gwb == 0){ // 在多行註釋內可使用單行註釋
x = 3; /* 但不允許使用新的多行註釋-這是無效的
}
// 別忘了註釋的結尾符號-它們是成對出現的!
*/
小提示
當測試代碼的時候,註釋掉一段可能有問題的代碼是非常有效的方法。這能使這段代碼成爲註釋而保留在程序中,而編譯器能忽略它們。這個方法用於尋找問題代碼或當編譯器提示出錯或錯誤很隱蔽時很有效。
3.4 /* /(多行註釋)
Comments(註釋)
上面已經講過了跟單行同類型
例子
x = 5; // 這是一條註釋斜槓後面本行內的所有東西是註釋
/ 這是多行註釋-用於註釋一段代碼
if (gwb == 0){ // 在多行註釋內可使用單行註釋
x = 3; /* 但不允許使用新的多行註釋-這是無效的
}
// 別忘了註釋的結尾符號-它們是成對出現的!
*/
小提示
當測試代碼的時候,註釋掉一段可能有問題的代碼是非常有效的方法。這能使這段代碼成爲註釋而保留在程序中,而編譯器能忽略它們。這個方法用於尋找問題代碼或當編譯器提示出錯或錯誤很隱蔽時很有效。
3.5 #define
#define 是一個很有用的C語法,它允許程序員在程序編譯之前給常量命名。在Arduino中,定義的常量不會佔用芯片上的任何程序內存空間。在編譯時編譯器會用事先定義的值來取代這些常量。
然而這樣做會產生一些副作用,例如,一個已被定義的常量名已經包含在了其他常量名或者變量名中。在這種情況下,文本將被#defined 定義的數字或文本所取代。
通常情況下,優先考慮使用 const 關鍵字替代 #define 來定義常量。
Arduino 擁有和 C 相同的語法規範。
語法
#define 常量名 常量值 注意,#是必須的。
例子
#define ledPin 3
//在編譯時,編譯器將使用數值 3 取代任何用到 ledPin 的地方。
提示
在#define 聲明後不能有分號。如果存在分號,編譯器會拋出語義不明的錯誤,甚至關閉頁面。
#define ledPin 3; //這是一種錯誤寫法
類似的,在#define聲明中包含等號也會產生語義不明的編譯錯誤從而導致關閉頁面。
#define ledPin = 3 //這是一種錯誤寫法
不能包含等號只能用空格
3.6 #include
#include用於調用程序以外的庫。這使得程序能夠訪問大量標準C庫,也能訪問用於arduino的庫。 AVR C庫(Arduino基於AVR標準語法)語法手冊請點擊這裏。 注意#include和#define一樣,不能在結尾加分號,如果你加了分號編譯器將會報錯。
例子
此例包含了一個庫,用於將數據存放在flash空間內而不是ram內。這爲動態內存節約了空間,大型表格查表更容易實現。
#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};
四、算數運算符
————————————————————————————————————————————
4.1 =(賦值運算符)
= 賦值運算符(單等號) 注意:這個是賦值的=號並不是相比較的號
賦值運算符(單等號)
將等號右邊的數值賦值給等號左邊的變量
在C語言中,單等號被稱爲賦值運算符,它與數學上的等號含義不同,賦值運算符告訴單片機,將等號的右邊的數值或計算表達式的結果,存儲在等號左邊的變量中。
例子
int sensVal; //聲明一個名爲sensVal的整型變量
senVal = analogRead(0); //將模擬引腳0的輸入電壓存儲在SensVal變量中
編程技巧
要確保賦值運算符(=符號)左側的變量能夠儲存右邊的數值。如果沒有大到足以容納右邊的值,存儲在變量中的值將會發生錯誤。
比如你要把一個浮點型小數賦值給一個整數就不對
不要混淆賦值運算符[=](單等號)與比較運算符[](雙等號),認爲這兩個表達式是相等的。
4.2 +(加)
加,減,乘,除
描述
這些運算符返回兩個操作數的和,差,乘積,商。這些運算是根據操作數的數據類型來計算的,比如 9和4都是int類型,所以9 / 4 結果是 2.這也就代表如果運算結果比數據類型所能容納的範圍要大的話,就會出現溢出(例如. 1加上一個整數 int類型 32,767 結果變成-32,768)。如果操作數是不同類型的,結果是”更大”的那種數據類型。如果操作數中的其中一個是 float類型或者double類型, 就變成了浮點數運算。
例子
y = y + 3; //這裏的Y得是整數型 int 類型才行,如果y是2輸出結果爲5
y=y+“你好啊”; //這裏的y得是字符串類型 str 才行,如果y是“逗B”,輸出結果就是“逗B你好啊”
//加可以用來做字符串相加,減的話必須是主內容包含被減掉的內容纔可以。
x = x - 7;
i = j * 6;
r = r / 5;
result = value1 + value2;
result = value1 - value2;
result = value1 * value2;
result = value1 / value2;
value1: 任何常量或者變量,value2: 任何常量或者變量
但是要注意,互相做運算的變量或是常得是同一類型,不是的話先轉換成同一類型
編程小提示
整型常量的默認值是int類型,所以一些整型常量(定義中)的計算會導致溢出.(比如: 60 * 1000 會得到一個負數結果.那麼if(60*1000 > 0) ,if得到的是一個false值。
在選擇變量的數據類型時,一定要保證變量類型的範圍要足夠大,以至於能容納下你的運算結果。
要知道你的變量在哪個點會”翻身”,兩個方向上都得注意.如: (0 - 1) 或 (0 - - 32768)
一些數學上的分數處理,要用浮點數,但其缺點是:佔用字節長度大,運算速度慢。
使用類型轉換符,例如 (int)myFloat 將一個變量強制轉換爲int類型。
4.3 -(減)
詳見4.2 +(加)
4.4 *(乘)
詳見4.2 +(加)
4.5 /(除)
詳見4.2 +(加)
4.6 %(取模)
描述
一個整數除以另一個數,其餘數稱爲模。它有助於保持一個變量在一個特定的範圍(例如數組的大小)。
語法
結果=被除數%除數
參數
被除數:一個被除的數字
除數:一個數字用於除以其他數
返回
餘數(模)
舉例
X = 7%5; // X爲2,商爲1餘2
X = 9% 5;// X爲4商爲1餘4
X = 5% 5;// X爲0商爲1餘0
X = 4%5; // X爲4除不動就爲它本身4了
示例代碼
/通過循環計算1到10的模/
int values[10];
int i = 0;
void setup () {
}
void loop()
{
values [i] = analogRead(0); //所以讀取的值就是10以內的除以10之後的餘數
i =(i + 1)%10; //取模運算
}
提示
模運算符對浮點數不起作用。
五、比較運算符
————————————————————————————————————————————
5.1 ==(等於)比較是否等於
if(條件判斷語句)和 ==、!=、<、>(比較運算符)
複習一下if語句
if 語句與比較運算符一起用於檢測某個條件是否達成,如某輸入值是否在特定值之上等。if 語句的語法是:
if (someVariable > 50)
{
// 執行某些語句
}
本程序測試 someVariable 變量的值是否大於 50。當大於 50 時,執行一些語句。換句話說,只要 if 後面括號裏的結果(稱之爲測試表達式)爲真,則執行大括號中的語句(稱之爲執行語句塊);若爲假,則跳過大括號中的語句。 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);
} // 以上所有書寫方式都正確
在小括號裏求值的表達式,需要以下操作符:
比較運算操作符:
x == y(x 等於 y)
x != y(x 不等於 y)
x < y(x 小於 y)
x > y(x 大於 y)
x <= y(x 小於等於 y)
x >= y(x 大於等於 y)
警告
注意使用賦值運算符的情況(如 if (x = 10))。一個“=”表示的是賦值運算符,作用是將 x 的值設爲 10(將值 10 放入 x 變量的內存中)。兩個“=”表示的是比較運算符(如 if (x == 10)),用於測試 x 和 10 是否相等。後面這個語句只有 x 是 10 時才爲真,而前面賦值的那個語句則永遠爲真。
這是因爲 C 語言按以下規則進行運算 if (x=10):10 賦值給 x(只要非 0 的數賦值的語句,其賦值表達式的值永遠爲真),因此 x 現在值爲 10。此時 if 的測試表達式值爲 10,該值永遠爲真,因爲非 0 值永遠爲真。所以,if (x = 10) 將永遠爲真,這就不是我們運行 if 所期待的結果。另外,x 被賦值爲 10,這也不是我們所期待的結果。
if 的另外一種分支條件控制結構是 if…else 形式。
5.2 !=(不等於)
詳見5.1 ==(等於)
5.3 <(小於)
詳見5.1 ==(等於)
5.4 >(大於)
詳見5.1 ==(等於)
5.5 <=(小於等於)
詳見5.1 ==(等於)
5.6 >=(大於等於)
詳見5.1 ==(等於)
六、布爾運算符
————————————————————————————————————————————
6.1 &&(與)
布爾運算符
這些運算符可以用於if條件句中。不會打&沒關係英文輸入狀態按SHIFT+7
&&(邏輯與)就是同時的意思,小明買了一支筆&&買了一本書
只有兩個運算對象爲“真”,才爲“真”,如:
if (digitalRead(2) == HIGH && digitalRead(3) == HIGH) { // 讀取2號針腳和3號針腳的電平
}
如果當兩個輸入都爲高電平,則爲“真”。
||(邏輯或)
只要一個運算對象爲“真”,就爲“真”,如:
if (x > 0 || y > 0) {
//其中x大於0或是y大於0都可執行程序
}
如果x或y是大於0,則爲“真”。
!(邏輯非)
如果運算對象爲“假”,則爲“真”,例如
if (!x) {
// …
}
如果x爲“假”,則爲真(即如果x等於0)。
警告
千萬不要誤以爲,符號爲&(單符號)的位運算符”與”就是布爾運算符的“與”符號爲&&(雙符號)。他們是完全不同的符號。
同樣,不要混淆布爾運算符||(雙豎)與位運算符“或”符號爲| (單豎)。
位運算符〜(波浪號)看起來與布爾運算符not有很大的差別!(正如程序員說:“驚歎號”或“bang”),但你還是要確定哪一個運算符是你想要的。
舉例
if (a >= 10 && a <= 20){} // 如果a的值在10至20之間,則爲“真”
6.2 ||(或)
詳見6.1 &&(與)
6.3 !(非)
詳見6.1 &&(與)
七、指針運算符
————————————————————————————————————————————
7.1 * 取消引用運算符
指針運算符
& (取地址) 和 * (取地址所指的值)
指針對C語言初學者來說是一個比較複雜的內容,但是編寫大部分arduino代碼時可以不用涉及到指針。然而,操作某些數據結構時,使用指針能夠簡化代碼,但是指針的操作知識很難在工具書中找到,可以參考C語言相關工具書。
八、位運算符
————————————————————————————————————————————
8.1 & (按位與)
按位與(&)
按位操作符對變量進行位級別的計算。它們能解決很多常見的編程問題。下面的材料大多來自這個非常棒的按位運算指導。
說明和語法
下面是所有的運算符的說明和語法。進一步的詳細資料,可參考教程。
按位與(&)
位操作符與在C + +中是一個&符,用在兩個整型變量之間。按位與運算符對兩側的變量的每一位都進行運算,規則是:如果兩個運算元都是1,則結果爲1,否則輸出0.另一種表達方式:
0 0 1 1 運算元1
0 1 0 1 運算元2
————————
0 0 0 1(運算元1&運算元2)-返回結果
在Arduino中,int類型爲16位,所以在兩個int表達式之間使用&會進行16個並行按位與計算。代碼片段就像這樣:
int a = 92; //二進制: 0000000001011100
int b = 101; // 二進制: 0000000001100101
int c = a & b; // 結果: 0000000001000100, 或10進制的68
a和b的16位每位都進行按位與計算,計算結果存在c中,二進制結果是01000100,十進制結果是68.
按位與最常見的作用是從整型變量中選取特定的位,也就是屏蔽。見下方的例子。
按位或(|)
按位或操作符在C++中是|。和&操作符類似,|操作符對兩個變量的爲一位都進行運算,只是運算規則不同。按位或規則:只要兩個位有一個爲1則結果爲1,否則爲0。換句話說:
0 0 1 1 運算元1
0 1 0 1 運算元2
————————
0 1 1 1(運算元1 | 運算元2) - 返回的結果
這裏是一個按位或運算在C + +代碼片段:
int a = 92; // 二進制: 0000000001011100
int b = 101; //二進制: 0000000001100101
int c = a | b; // 結果: 0000000001111101, 或十進制的125
示例程序
按位與和按位或運算常用於端口的讀取-修改-寫入。在微控制器中,一個端口是一個8位數字,它用於表示引腳狀態。對端口進行寫入能同時操作所有引腳。
PORTD是一個內置的常數,是指0,1,2,3,4,5,6,7數字引腳的輸出狀態。如果某一位爲1,着對應管腳爲HIGH。(此引腳需要先用pinMode()命令設置爲輸出)因此如果我們這樣寫,PORTD=B00110001;則引腳2、3、7狀態爲HIGH。這裏有個小陷阱,我們可能同時更改了引腳0、1的狀態,引腳0、1是Arduino串行通信端口,因此我們可能會干擾通信。
我們的算法的程序是:
讀取PORT並用按位與清除我們想要控制的引腳
用按位或對PORTD和新的值進行運算
int i; // 計數器
int j;
void setup()
DDRD = DDRD | B11111100; //設置引腳2~7的方向,0、1腳不變(xx|00==xx)
//效果和pinMode(pin,OUTPUT)設置2~7腳爲輸出一樣
serial.begin(9600);
}
void loop () {
for (i=0; i<64; i++){
PORTD = PORTD & B00000011; // 清除2~7位,0、1保持不變(xx & 11 == xx)
j = (i << 2); //將變量左移爲·2~7腳,避免0、1腳
PORTD = PORTD | j; //將新狀態和原端口狀態結合以控制LED腳
Serial.println(PORTD, BIN); // 輸出掩蓋以便調試
delay(100);
}
}
按位異或(^)
C++中有一個不常見的操作符叫按位異或,也叫做XOR(通常讀作”eks-or“)。按位異或操作符用‘^'表示。此操作符和按位或(|)很相似,區別是如果兩個位都爲1則結果爲0:
0 0 1 1 運算元1
0 1 0 1 運算元2
————————
0 1 1 0(運算元1 ^運算元2) - 返回的結果
按位異或的另一種解釋是如果兩個位值相同則結果爲0,否則爲1。
下面是一個簡單的代碼示例:
int x = 12; // 二進制: 1100
int y = 10; // 二進制: 1010
int z = x ^ y; // 二進制: 0110, 或十進制 6
// Blink_Pin_5
//演示“異或”
void setup(){
DDRD = DDRD | B00100000; / /設置數字腳5設置爲輸出
serial.begin(9600);
}
void loop () {
PORTD = PORTD ^ B00100000; // 反轉第5位(數字腳5),其他保持不變
delay(100);
}
8.2 | (按位或)
詳見8.1 &(按位與)
8.3 ^ (按位異或)
詳見8.1 &(按位與)
8.4 ~ (按位非)
按位取反 (~)
按位取反在C+ +語言中是波浪號~。與&(按位與)和|(按位或)不同,按位取反使用在一個操作數的右側。按位取反將操作數改變爲它的“反面”:0變爲1,1變成0。例如:
0 1 operand1
———————
1 0 ~ operand1
int a = 103; // 二進制: 0000000001100111
int b = ~a; // 二進制: 1111111110011000 = -104
你可能會驚訝地看到結果爲像-104這樣的數字。這是因爲整數型變量的最高位,即所謂的符號位。如果最高位是1,這個數字將變爲負數。這個正數和負數的編碼被稱爲補。想了解更多信息,請參考Wikipedia文章two’s complement.
順便說一句,有趣的是,要注意對於任何整數型操作數X,〜X和-X-1是相同的。
有時,對帶有符號的整數型操作數進行位操作可以造成一些不必要的意外。
8.5 <<(左移位運算符)
bitshift left (<<), bitshift right (>>)
描述
出自Playground的 The Bitmath Tutorial 在C++語言中有兩個移位運算符:左移位運算符(«)和右移運算符(»)。這些操作符可使左運算元中的某些位移動右運算元中指定的位數。
語法
variable « number_of_bits variable » number_of_bits
參數
variable - (byte, int, long) number_of_bits integer ⇐ 32
例子
int a = 5; // 二進制數: 0000000000000101
int b = a << 3; // 二進制數: 0000000000101000, 或十進制數:40
int c = b >> 3; // 二進制數: 0000000000000101, 或者說回到開始時的5
//當你將x左移y位時(x«y),x中最左邊的y位會逐個逐個的丟失:
int a = 5; // 二進制: 0000000000000101
int b = a << 14; // 二進制: 0100000000000000 - 101中最左邊的1被丟棄
如果你確定位移不會引起數據溢出,你可以簡單的把左移運算當做對左運算元進行2的右運算元次方的操作。例如,要產生2的次方,可使用下面的方式:
1 << 0 == 1
1 << 1 == 2
1 << 2 == 4
1 << 3 == 8
…
1 << 8 == 256
1 << 9 == 512
10 << 1 == 1024
…
當你將x右移y位(x»y),如果x最高位是1,位移結果將取決於x的數據類型。如果x是int類型,最高位爲符號位,確定是否x是負數或不是,正如我們上面的討論。如果x類型爲int,則最高位是符號位,正如我們以前討論過,符號位表示x是正還是負。在這種情況下,由於深奧的歷史原因,符號位被複制到較低位:
X = -16; //二進制:1111111111110000
Y = X >> 3 //二進制:1111111111111110
這種結果,被稱爲符號擴展,往往不是你想要的行爲。你可能希望左邊被移入的數是0。右移操作對無符號整型來說會有不同結果,你可以通過數據強制轉換改變從左邊移入的數據:
X = -16; //二進制:1111111111110000
int y = (unsigned int)x >> 3; // 二進制: 0001111111111110
如果你能小心的避免符號擴展問題,你可以將右移操作當做對數據除2運算。例如:
INT = 1000;
Y = X >> 3; 8 1000 //1000整除8,使y=125
8.6 >> (右移位運算符)
詳見 8.5 <<(左移位運算符)
九、複合運算符
————————————————————————————————————————————
9.1 ++ (遞增)
++ (遞增) / – (遞減)
描述
遞增或遞減一個變量
語法
x++; //x自增1返回x的舊值
++x; // x自增1返回x的新值
x–; // x自減1返回x的舊值
–x; //x自減1返回x的新值
參數
x: int或long(可能是unsigned)
返回
變量進行自增/自減操作後的原值或新值。
例子
x = 2;
y = ++x; // 現在x=3,y=3
y = x–; // 現在x=2,y還是3
9.2 – (遞減)
詳見 9.1 ++ (遞增)
9.3 += (複合加)
+= , -= , *= , /=
描述
執行常量或變量與另一個變量的數學運算。+= 等運算符是以下擴展語法的速記。
語法
X += Y; //相當於表達式X = X + Y;
X -= Y; //相當於表達式X = X - Y;
X *= Y; //相當於表達式X = X * Y;
X /= Y; //相當於表達式X = X / Y;
參數
X:任何變量類型
Y:任何變量類型或常數
例子
x = 2;
x += 4; // x 現在等於6
x -= 3; // x 現在等於3
x *= 10; // x 現在等於30
x /= 2; // x 現在等於15
9.4 -= (複合減)
詳見 9.3 += (複合加)
9.5 *= (複合乘)
詳見 9.3 += (複合加)
9.6 /= (複合除)
詳見 9.3 += (複合加)
9.7 &= (複合運算按位與)
描述
複合運算按位與運算符(&=)經常被用來將一個變量和常量進行運算使變量某些位變爲0。這通常被稱爲“清算”或“復位”位編程指南。
語法
x &= y; // 等價於 x = x & y;
參數
x:char,int或long類型變量
Y:char,int或long類型常量
例如
首先,回顧一下按位與(&)運算符
0 0 1 1 運算元1
0 1 0 1 運算元2
————————
0 0 0 1(運算元1&運算元2) - 返回的結果
任何位與0進行按位與操作後被清零,如果myBite是變量
myByte&B00000000 = 0;
因此,任何位與1進行“按位與運算”後保持不變
myByte B11111111 = myByte;
注意:因爲我們用位操作符來操作位,所以使用二進制的變量會很方便。如果這些數值是其他值將會得到同樣結果,只是不容易理解。同樣,B00000000是爲了標示清楚,0在任何進制中都是0(恩。。有些哲學的味道) 因此 - 清除(置零)變量的任意位0和1,而保持其餘的位不變,可與常量B11111100進行復合運算按位與(&=)
1 0 1 0 1 0 1 0變量
1 1 1 1 1 1 0 0 mask
——————————
1 0 1 0 1 0 0 0
變量不變 位清零
將變量替換爲x可得到同樣結果
X X X X X X X X變量
1 1 1 1 1 1 0 0 mask
——————————
X X X X X X 0 0
變量不變 位清零
同理
myByte = 10101010;
myByte&= B1111100 == B10101000;
9.8 |= (複合運算按位或)
描述
複合按位或操作符(| =)經常用於變量和常量“設置”(設置爲1),尤其是變量中的某一位。
語法
x |= y; //等價於 x = x | y;
參數
x: char,int或long類型
y:整數,int或long類型
例如
首先,回顧一下OR(|)運算符
0 0 1 1 運算元1
0 1 0 1 運算元2
————————
0 1 1 1(運算元1 | 運算元2) - 返回的結果
如果變量myByte中某一位與0經過按位或運算後不變。
myByte | B00000000 = myByte;
與1經過或運算的位將變爲1.
myByte | B11111111 B11111111;
因此 - 設置變量的某些位爲0和1,而變量的其他位不變,可與常量B00000011進行按位與運算(| =)
1 0 1 0 1 0 1 0變量
0 0 0 0 0 0 1 1
————————
1 0 1 0 1 0 1 1
變量保持不變 位設置
接下來的操作相同,只是將變量用x代替
X X X X X X X X變量
0 0 0 0 0 0 1 1 mask
——————————
X X X X X X 1 1
變量保持不變 位設置
同上:
myByte = B10101010;
myByte | = B00000011 == B10101011;