《超圖解Arduino 互動設計入門》第二版內容更新說明

《超圖解 Arduino 互動設計入門》第二版基本資料:

《超圖解Arduino 互動設計入門》第二版封面

作者:趙英傑
出版社:旗標出版股份有限公司
出版日期:2014.04.24
頁數:640頁,雙色印刷。
定價:NT$680

書本封面上的數字2,改自Arduino官方的社群圖標(Community Logo),該網頁提供SVG和EPS圖檔格式:

Arduino社群標誌

Arduino控制板有許多不同的版本,目前的主流是UNO,因此本書(第二版)的Arduino控制板插圖,全數改成UNO與Leonardo(李奧納多),第一章當中的Windows和Mac OS X驅動程式安裝和操作,也做了對應的更新(註:第一版的應用範例也全都和UNO板相容)。

第二版依照讀者的建議和指教,修正並補充內容,例如第二章關於電容器元件的介紹、電源短路、第四章的遞增(++)運算子、第八章的C語言指標語法…等,使用App Inventor開發Android App單元(附錄E),也根據2.0版徹底改寫。更新內容的PDF文件以及範例原始碼,請參閱:Windows版App Inventor 2.0離線版軟體(Ai2LiveComplete)安裝說明與基礎操作

此外,書末也附上依主題分類的關鍵字索引,方便讀者查閱,像是C程式語言的語法,可瀏覽「程式設計基礎」分類。第一版的索引,請參閱這篇PO文

第二版的更新內容列舉如下:

第 01 章 認識 Arduino

UNO板腳位補充說明

請參閱「Arduino UNO控制板簡介

Mac OS X系統上的UNO控制板基本操作

Mac OS X不必安裝Uno的驅動程式即可使用。將Uno板接上Mac的USB埠,將能從系統資訊視窗的USB類別,看到Arduino「通訊裝置」的資訊。

Mac OS X 系統資訊視窗

在Mac OS X系統中,請選擇工具→序列埠選單底下,以tty.usbmodem為首的選項(若您的板子不是Uno,請選擇以tty.usbserial為首的選項,詳細說明請參閱第五章或者下文):

「工具→序列埠」選單

第 02 章 認識電子零件與工具

直插式與表面黏著式元件補充說明

本書採用的電子零件都有長腳(導線),這種零件通稱「直插式」,方便手工組裝及焊接。Arduino板子上的電子零件多數沒有長腳,外觀也微小許多,而且電阻也沒有色環。這種微小、方便機器直接焊接在電路板表面的零件,通稱表面黏著元件(Surface Mount Device,簡稱SMD)。

SMD表面黏著元件

短路補充說明

按照字面上的意思,「短路」就是「最短的路徑」,相當於一般道路的捷徑,更貼切的說法是,「阻礙最少、最順暢的通路」。

短路

電流和水流一樣,會往最順暢的通路流動。電源電路一定要有負載(電阻),萬萬不可將正負電源用導線直接相連,將有大量電流通過導線,可能導致電池或導線過熱,引起火災(因為導線的電阻值趨近於0,參閱4-31頁的歐姆定律,電阻值越小,電流量越大;電流越大,消耗功率和發熱量也越大)。

電容補充說明

理想的直流電壓或訊號,應該像下圖一樣的平穩直線,但是受到外界環境或者相同電路上其他元件的干擾而出現波動(正常訊號以外的波動,稱為「雜訊」),這有可能導致某些元件開開關關,令整個電路無法如期運作。

直流與雜訊

就像蓄水池能抑制水位快速變化一樣,即使突然間湧入大量的電流,電容的輸出端仍能保持平穩地輸出。在積體電路和馬達的電源接腳,經常可以發現相當於小型蓄水池的電容(又稱為「旁路電容」),用來平穩管路間的水流波動。

馬達的濾波電容

第 03 章 Arduino 互動程式設計入門

組合語言補充說明

早期的8位元微電腦的運算能力與記憶體容量都比Arduino的微控器小很多,因此經常採用接近機械碼的組合語言(Assembly)來開發程式,程式設計師必須先徹底了解處理器的架構才有辦法用組合語言寫程式,它的執行效率高,程式碼也最精簡,但是不容易閱讀和維護。不同微處理器的指令不盡相同,將來若替換成不同的微處理器,程式碼幾乎要全部重寫。

組合語言與組譯器

由於微控器效能和C語言編譯器的改良,使得C語言程式僅比組合語言程式的執行效率低10%~20%;而且C語言的可讀性、可移植性、容易開發…等的優點,可大幅彌補執行效率的缺點,所以就連嵌入式系統開發,也是以C語言為主流。

第 04 章 開關電路與 LED 跑馬燈效果

歐姆定律公式圖表更新

為了幫助記憶,原第一版4-31頁的歐姆定律公式說明,改成這張圖說:

歐姆定律

第 05 章 序列埠通信

USB序列埠補充說明

早期的Arduino板子採用RS-232介面,後來改用USB;某些Arduino控制板採用序列通訊轉換晶片(如:FT232R)來轉換USB與TTL序列訊號,Uno板使用MEGA16U2微控器

轉換USB序列TTL訊號的MEGA16U2微控器

MEGA16U2微控器在此負責銜接USB介面和Arduino的數位0與1腳。如果有需要的話,我們還可以改寫它的程式,讓電腦將此控制板看待成滑鼠、鍵盤、電玩搖桿或MIDI數位音樂介面。只不過,Arduino工具本身並不提供燒錄此微控器程式的功能,要透過另一個叫做FLIP的燒錄程式。

Mac OS X與Linux的通訊埠補充說明

Windows系統使用COM(原意是COMmunication,通訊)代表通訊埠,Mac OS X(一種基於Unix的作業系統)和Linux則用TTY代表通訊埠。

TTY的原意是"teletypewriter"(電傳打字機,早期用來操作並和大型電腦連線的終端機)。OS X和Linux系統把每個裝置都看待成檔案,位於/dev路徑底下,因此在Mac的終端機視窗輸入底下的命令,將能列舉所有通訊埠:

列舉TTY裝置的Mac OS X指令

從ls命令的執行結果可看出,筆者的電腦連接三種通訊裝置,每個裝置都有唯一的名稱。

列舉TTY裝置

通訊埠裝置的名稱格式如下,Uno板被辨識成modem(數據機,一種通訊裝置),採用FT232序列轉換晶片的Arduino控制板,被視為序列裝置。

通訊埠裝置的名稱格式

因此如果你的控制板不是Uno,請在Arduino軟體的連接埠選項選擇以usbserial開頭的那一個。除了TTY,Mac和Linux上的通訊埠還有包含一個同名的CU,因此同一個序列埠在Arduino的序列埠選單,有兩個選項。

tty與cu裝置

TTY用於傳入訊息給裝置,CU代表call up,用於從裝置傳出訊息,兩者合作就像雙向道路,能同時收發訊息此舉稱為全雙工。在Arduino上,無論使用TTY還是CU,都能傳遞訊息,但一般大多選用TTY。

UART與USART補充說明

第一版5-9頁的註解補充:本文介紹的 RS-232 和 USB 序列線,不需要同步線,因為它們會在資料前後加上「 開始」和「 結束」訊息。這種傳送方式統稱通用非同步收發傳輸器(Universal Asynchronous Receiver/Transmitter,簡稱UART)

除了TxD和RxD這兩個非同步序列傳輸接腳,ATmega微控器還具備SPI, I2C這兩種同步式序列傳輸介面,分別在第八章和第十一章介紹。

像ATmega這種兼具同步和非同步傳輸介面的硬體,又稱為通用同步∕非同步收發傳輸器(Universal Synchronous/Asynchronous Receiver/Transmitter,簡稱 USART)

第 08 章 LED 矩陣與 SPI 介面控制

更新指標(pointer)語法說明

第二版更改指標(pointer)的語法說明,這樣比較容易理解第一版8-41頁的記憶體位址加2的敘述:*(msg+2)

透過「位址」存取變數,需要借助*(星號)和&符號,它們的意義如下:

指標操作符號

*和&經常合併使用,在底下的範例敘述中,"&LED"將取得LED變數所在的位址,然後存入pt變數,在程式用語中,*pt稱為「指向LED位址的指標(pointer)」。

指標操作敘述

以上3行程式,可以拆解成底下4行:

指標操作敘述

凡是儲存「記憶體位址」的變數,前面都要加上*號(註:下圖中的記憶體位址編號是虛構的):

指標操作敘述

第 10 章 變頻控制LED 燈光和馬達

第一版10-33頁的馬達控制板接線圖,提供新增下圖的接線版本(在第二版內文中稱作A型控制板),自行DIY馬達控制板或者市售的L298N控制板,大多是這種類型(外觀可能不太一樣):

L298N馬達控制器

底下是用於A型馬達控制板的超音波與馬達的參數,以及轉向控制函數程式(B型馬達控制板的程式,請參閱書附光碟的diy10_6B.ino檔):

const byte TrigPin = 13;	// 超音波模組的觸發腳
const int EchoPin = 12;	 	// 超音波模組的接收腳
const int dangerThresh = 580;   // 10cm × 58
const byte speed = 100;		// 馬達的PWM輸出值

long distance;  		// 暫存接收訊號的高電位持續時間

const byte ENA = 5;  	// 馬達A的致能接腳
const byte ENB = 6; 	// 馬達B的致能接腳
const byte IN1 = 10;	// 馬達A的正反轉接腳
const byte IN2 = 9;	// 馬達B的正反轉接腳
const byte IN3 = 8;	// 馬達A的正反轉接腳
const byte IN4 = 7;	// 馬達B的正反轉接腳

byte dir = 0;     // 記錄行進狀態,0代表「前進」,1代表「右轉」。

void stop() {	  // 馬達停止
 analogWrite(ENA, 0);	// 馬達A的PWM輸出
 analogWrite(ENB, 0); 	// 馬達B的PWM輸出
}

void forward() {	   // 馬達轉向:前進(兩個馬達都正轉)
 analogWrite(ENA, speed);  // 馬達A的PWM輸出
 digitalWrite(IN1, HIGH);  // 請參閱表10-5的設定
 digitalWrite(IN2, LOW);
 analogWrite(ENB, speed);  // 馬達B的PWM輸出
 digitalWrite(IN3, HIGH);  // 請參閱表10-5的設定
 digitalWrite(IN4, LOW);
}

void backward() {	   // 馬達轉向:後退(兩個馬達都反轉)
 analogWrite(ENA, speed);  // 馬達A的PWM輸出
 digitalWrite(IN1, LOW);   // 請參閱表10-5的設定
 digitalWrite(IN2, HIGH);
 analogWrite(ENB, speed);  // 馬達B的PWM輸出
 digitalWrite(IN3, LOW);   // 請參閱表10-5的設定
 digitalWrite(IN4, HIGH);
}

void turnLeft() {	   // 馬達轉向:左轉(馬達A反轉、馬達B正轉)
 analogWrite(ENA, speed);  // 馬達A的PWM輸出
 digitalWrite(IN1, LOW);   // 請參閱表10-5的設定
 digitalWrite(IN2, HIGH);
 analogWrite(ENB, speed);  // 馬達B的PWM輸出
 digitalWrite(IN3, HIGH);  // 請參閱表10-5的設定
 digitalWrite(IN4, LOW);
}

void turnRight() {	   // 馬達轉向:右轉(馬達A正轉、馬達B反轉)
 analogWrite(ENA, speed);  // 馬達A的PWM輸出
 digitalWrite(IN1, LOW);   // 請參閱表10-5的設定
 digitalWrite(IN2, HIGH);
 analogWrite(ENB, speed);  // 馬達B的PWM輸出
 digitalWrite(IN3, HIGH);  // 請參閱表10-5的設定
 digitalWrite(IN4, LOW);
}

long ping() {			// 超音波感測程式
  digitalWrite(TrigPin, HIGH);  // 觸發腳設定成高電位
  delayMicroseconds(5);		// 持續5微秒
  digitalWrite(TrigPin, LOW);	// 觸發腳設定成低電位
  
  return pulseIn(EchoPin, HIGH);  // 測量高電位的持續時間(µs)
}

底下是主程式碼,它將每隔一秒鐘檢查一次距離:

void setup(){
   pinMode(TrigPin, OUTPUT);  // 觸發腳設定成「輸出」
   pinMode(EchoPin, INPUT);   // 接收腳設定成「輸入」
   // 馬達控制板的接腳全都設定成「輸出」
   pinMode(IN1, OUTPUT); 
   pinMode(IN2, OUTPUT);
   pinMode(IN3, OUTPUT); 
   pinMode(IN4, OUTPUT);
}

void loop(){
   distance = ping();  		// 讀取障礙物的距離
   if (distance>dangerThresh) {	// 如果距離大於10cm…
      if (dir != 0) {		// 如果目前的行進狀態不是「前進」
  	 dir = 0;	        // 設定成「前進」
	 stop();		// 暫停馬達0.5秒
	 delay(500);
      }
      forward();		// 前進
   } else {
      if (dir != 1) {	// 如果目前的狀態不是「右轉」
	 dir = 1;	// 設定成「右轉」
	 stop();	// 暫停馬達0.5秒
	 delay(500);		
      }
      turnRight();	// 向右轉
   }
   delay(1000);		// 持續1秒
}
Posts created 467

119 thoughts on “《超圖解Arduino 互動設計入門》第二版內容更新說明

  1. 老師你好
    我想在是非問答遊戲中,加入答對會有音效播放的效果,答錯也會有音效,我該如何修改程式?

    1. 透過Flash ActionScript 3.0程式播放聲音,最簡單的方式:

      1. 把聲音檔(.mp3檔)存放在.swf影片的相同路徑。
      2. 在ActionScript程式開頭,透過程式匯入聲音檔並且建立Sound(聲音)類型的物件,語法如下:

      var 自訂的聲音物件名稱:Sound = new Sound(new URLRequest(“音效檔名.mp3”));

      底下的敘述將建立rightSnd和wrongSnd兩個聲音物件,分別存放right.mp3和wrong.mp3:

      var rightSnd:Sound = new Sound(new URLRequest("right.mp3"));
      var wrongSnd:Sound = new Sound(new URLRequest("wrong.mp3"));
      

      3. 在需要播放聲音的地方,加入底下的敘述:

      rightSnd.play();  // 播放right.mp3
      

      thanks,
      jeffrey

  2. 老師您好
    我是買第二版的書
    目前在研究第16章WEBDUINO程式庫的部分
    我已經將WEBDUINO會入到我的程式庫了
    我的問題在地16-6頁 要自行插入P(homePage) 以及 void defaultCmd
    要自行定義這一塊 像是
    void defaultCmd (WebServer &server, WebServer::ConnectionType type, char*,bool)
    {
    server.httpSuccess();
    if (type != WebServer::HEAD);
    {
    server.printP(homePage);
    }
    }
    一直在homePage這裡出問題
    請問要如何改善呢

    1. 請問出現什麼錯誤訊息,是程式編譯錯誤,或者在執行階段發生問題?還有,你採用哪個版本的IDE編譯Arduino程式?

      thanks,
      jeffrey

  3. 老師您好
    我出現的問題是
    error: ‘homePage’ was not declared in this scope
    server.printP(homePage);
    ^
    exit status 1
    ‘homePage’ was not declared in this scope
    那我知道的是我上面沒有定義homepage
    請問我的問題是在這裡嗎
    void defaultCmd (WebServer &server, WebServer::ConnectionType type, char*,bool)
    {
    server.httpSuccess();
    if (type != WebServer::HEAD);
    {
    server.printP(homePage);
    }
    }
    那請問我該如何宣告呢 謝謝
    以及 我的版本是1.6.11 謝謝老師

    1. 所以問題的答案很明確,就是未定義homePage變數,請參閱16-4頁說明,在自訂命令宣告之前,加入homePage變數宣告即可。

      thanks,
      jeffrey

  4. 老師你好
    我再使用 arduino uno時,設 2個串口通訊時(usb跟 設備模組)飽率都是115200,發生了 傳遞時會漏掉資料的問題。
    23 A5 51 12 90 1 0 BB 9A 20 20 10 9C AE 4 34 6A 52 FF,要有20組資料可是只有收到19組。是否 ardunio uno 不建議同時2個串列通訊?

    1. 我覺得問題不是出現在序列通訊設備,如果每次傳20組,都只有收到19組,那也不是雜訊干擾,應該是程式的問題。相較於SPI和I2C等序列埠,UART挺慢的,處理器不太可能漏接。

      thanks,
      jeffrey

  5. 老師你好
    我附上我的程式:
    #include
    #define SERIAL_BUFFER_SIZE 128
    SoftwareSerial mySerial(5, 6);// RX, TX 所接的設備模塊
    int i=0;
    byte data[20];
    void setup() {
    //设置波特率为 115200bps.
    Serial.begin(115200);
    mySerial.begin(115200);
    delay(1000);
    Serial.println(“Hello”);
    }

    void loop() {

    if(mySerial.available()>0){//等待RX接口的数值。
    for(i=0;i<=19;i++){
    data[i]=byte(mySerial.read());
    }
    for(i=0;i<=19;i++){
    Serial.println(data[i],HEX);
    }
    }
    }
    上述是我寫的程式,我用usb的 spi軟体看了一下 設備所傳出來的在數據是20組沒有錯,可是在 arduino 在傳給電腦顯示就不對了。
    usb spi的顯示:
    23 4A 42 23 00 AE 00 00 4D 2F 01 00 00 60 2E 00 00 47 0D 0A
    23 4A 42 23 00 AA 00 00 4E 2F 01 00 00 74 2E 00 00 36 0D 0A

    在 arduino的顯示:
    23 A5 51 12 D0 B 8 4 9B 40 20 20 B5 A2 2 51 86 85
    23 A5 51 12 90 1 0 9F 4D 20 20 90 8 57 2 52 35 9

  6. 老師如果要做一個用RFID感應卡,感應後用Syn6288發出聲音,要怎麼用個大概

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

Related Posts

Begin typing your search term above and press enter to search. Press ESC to cancel.

Back To Top