SlideShare a Scribd company logo
1 of 564
Download to read offline
Arduino 原始碼讀書會 (I) : Overview
簡單複習 Arduino
Arduino 硬體配置
開啟 .ino 程式檔 
Arduino IDE 的使用
編輯程式
編譯
燒錄到 Arduino 上執行
複習完畢! 收工…(毆)
進入 Arduino 原始碼的世界
Q: 
Arduino 0023、1.0.5、1.5.2 原始碼, 要 推倒哪一個? 
A: 
我們將以 Arduino 1.0.5 為主要推倒對 象
原始碼住哪裡? 
https://github.com/arduino/Arduino
原始碼目錄介紹 
改過的 Processing IDE 原始碼 (Arduino 相關) 
Processing IDE 原始碼 
存放編譯結果的目錄 
Arduino Bootloader, Standard API 原始碼 
Arduino Library 原始碼
app → src → processing → app → debug 
處理 Arduino 韌體燒錄動作 
處理 Arduino 韌體燒錄動作 
處理 .ino 編譯動作 
今天不談這裡
hardware → arduino 
各種版本 bootloader 原始碼 
Standard API 原始碼(共用部分) 
各種周邊配套的處理器韌體 
Standard API 不共用部分 
定義 Board 選單及編譯參數 
定義 Programmers 選單及燒錄參數 
今天只談它
如何編譯 Arduino 原始碼? 
http://code.google.com/p/arduino/wiki/BuildingArduino
Windows 下編譯 Arduino 原始碼 
下載 JAVA JDK 並完成安裝 
下載 cygwin並完成安裝 
◦Linux-like environment for Windows 
◦安裝 cygwin 過程中, 選擇安裝下列套件 
git 
make, gcc-mingw, and g++ 
perl 
unzip, zip
Windows 下編譯 Arduino 原始碼 
下載 Apache Ant 程式 
◦JAVA base 編譯器 
設定 Apache Ant 和 JAVA JDK 的環境變 數 
執行 cygwin, 使用 git 指令下載 Arduino 最新原始碼
Windows 下編譯 Arduino 原始碼 
使用指令 ant/ant run 開始編譯 Arduino 原始碼
Windows 下編譯 Arduino 原始碼 
編譯完成的結果會存放在 (DIR) buildwindowswork 資料夾內
Linux、Mac 下編譯 Arduino 原始碼 
Orz… 
目前還沒時間試… (哭~~~)
.ino 程式的編譯原理概觀
.ino: 偽裝過的 C++ 
一切都是幻覺, 嚇不倒我滴!! 
◦Arduino 會先將 .ino 檔轉換為 .cpp 檔再進 行編譯 
◦可在 .ino 檔中使用 C++ 語法 (但不能使用 C++ standard library 內的某些物件或函式, 例如: cout, cin) 
◦可使用 avr-gcc 的所有語法
IDE 會將 .ino 轉換成 .cpp 
加入 include ” Arduino.h” 
加入所有.ino 內函式的原型宣告 
加入編譯指示詞#line, 重新定義與原始.ino 檔一致的 行號
.ino 的編譯流程概觀 
Arduino IDE 會先建立一個暫存目錄 
把 .ino 轉成 .cpp, 複製到暫存目錄下並 進行編譯 
掃描並編譯 .ino 所 include 到的每個 library, 編譯結果輸出到暫存目錄下 
所有編譯結果連結成一個 .hex 的韌體 燒錄檔 
若編譯過程出錯, 會直接停止編譯並 show 出錯誤訊息
進入 Arduino Standard API (樓還沒歪…無誤)
Standard API 概觀 
Digital I/O 
◦pinMode( ) 
◦degitalWrite( ) 
◦degitalRead( ) 
Analog I/O 
◦analogReference() 
◦analogRead() 
◦analogWrite()
Standard API 概觀 
Advanced I/O 
◦tone ( ) 
◦noTone ( ) 
◦shiftOut( ) 
◦shiftIn( ) 
◦pulseln( )
Standard API 概觀 
時間函式 
◦millis( ) 
◦micros( ) 
◦delay( ) 
◦delayMicroseconds( )
Standard API 概觀 
基本數學函式 
◦min( ) 
◦max( ) 
◦abs( ) 
◦constrain( ) 
◦map( ) 
◦pow( ) 
◦sqrt( )
Standard API 概觀 
三角函式 
◦sin( ) 
◦cos( ) 
◦tan( ) 
隨機數函式 
◦randomSeed( ) 
◦random( )
Standard API 概觀 
位元操作 
◦lowByte( ) 
◦highByte( ) 
◦bitRead( ) 
◦bitWrite( ) 
◦bitSet( ) 
◦bitClear( ) 
◦bit( )
Standard API 概觀 
中斷相關函式 
◦attachInterrupt( ) 
◦detachInterrupt( ) 
◦Interrupts( ) 
◦noInterrupts( )
Standard API 概觀 
串列通訊 
◦serial.begin( ) 
◦serial.available( ) 
◦serial.read( ) 
◦serial.write( )
從進入的觀點看 Standard API 
接著重新用嘿客的眼光來分類 Standard API 
直接來自 C/C++ standard library 的函式 
◦pow( ) 
◦sqrt( ) 
◦sin( ) 
◦cos( ) 
◦tan( )
從進入的觀點看 Standard API 
直接使用 C 語言巨集定義的函式 
◦min( ) 
◦max( ) 
◦constrain( ) 
◦abs( ) 
Arduino.h
從進入的觀點看 Standard API 
直接使用 C 語言巨集定義的函式 
◦lowByte( ) 
◦highByte( ) 
◦bitRead( ) 
◦bitWrite( ) 
◦bitSet( ) 
◦bitClear( ) 
◦bit( ) 
Arduino.h
從進入的觀點看 Standard API 
平台獨立函式 
◦randomSeed( ) 
◦random( ) 
◦map( ) 
WMath.cpp
從進入的觀點看 Standard API 
硬體相關函式 
◦pinMode( ) 
◦degitalWrite( ) 
◦degitalRead( ) 
◦analogReference() 
◦analogRead() 
◦analogWrite() 
◦tone ( ) 
◦noTone ( )
從進入的觀點看 Standard API 
硬體相關函式 
◦shiftOut( ) 
◦shiftIn( ) 
◦pulseln( ) 
◦millis( ) 
◦micros( ) 
◦delay( ) 
◦delayMicroseconds( )
從進入的觀點看 Standard API 
硬體相關函式 
◦attachInterrupt( ) 
◦detachInterrupt( ) 
◦Interrupts( ) 
◦noInterrupts( ) 
◦serial.begin( ) 
◦serial.available( ) 
◦serial.read( ) 
◦serial.write( )
硬體相關函式實作解析 
pinMode (pin, mode) 
◦函式功能: 
設定腳位為輸出或輸入模式 
◦函式實作內容: 
1. 由指定的 pin 編號來取得對應的 port 
2. 由 port 找到對應的暫存器 
3. 依照輸入的 mode, 修改暫存器設定
wiring_digital.c
硬體相關函式實作解析 
digitalWrite (pin, value) 
◦函式功能: 
設定腳位輸出電位為 HIGH/LOW 
◦函式實作內容: 
1. 由指定的 pin 編號來取得對應的 port 
2. 檢查指定 pin 上的硬體 PWM 是否正在被使用, 如果是則停止它 
3. 由 port 找到對應的暫存器 
4. 依照輸入的 value, 修改暫存器設定
wiring_digital.c
硬體相關函式實作解析 
digitalRead (pin) 
◦函式功能: 
讀取指定腳位的輸入電位, 回傳 HIGH/LOW 
◦函式實作內容: 
1. 由指定的 pin 編號來取得對應的 port 
2. 檢查指定 pin 的硬體 PWM 是否正在被使用, 如 果是則停止它 
3. 由 port 找到對應的暫存器, 讀取並判斷暫存器 值, 回傳 HIGH/LOW
wiring_digital.c
硬體相關函式實作解析 
analogReference (mode) 
◦函式功能: 
設定 A/D 的參考電壓 
◦函式實作內容: 
把指定的 mode 傳給內部宣告的變數 
wiring_analog.c
硬體相關函式實作解析 
analogRead (pin) 
◦函式功能: 
讀取 A/D 的電壓數值 
◦函式實作內容: 
1. 依照不同的 Arduino 版本, 由輸入的 pin 編號來 取得對應的 analog IN 腳位 
2. 設定 analog reference 和 PIN 
3. 開始做 A/D 轉換並等待完成 
4. 回傳轉換後的值
wiring_analog.c
wiring_analog.c
硬體相關函式實作解析 
analogWrite (pin, val) 
◦函式功能: 
使用 Arduino 的 PWM 硬體送出指定 duty 的 PWM 
◦函式實作內容: 
1. 先將指定 pin 切成 OUTPUT 
2. 再從指定 pin 編號, 找到相對應的 timer 
3. 把 val 設定到 timer 暫存器 (藉由 timer 和 PWM generator 的硬體行為輸出指定 duty 的 PWM)
wiring_analog.c
硬體相關函式實作解析 
tone (pin, frequency, duration) 
◦函式功能: 
從指定的 pin 送出 frequency 頻率的 pulse (duty 為 50%) 並持續一段 duration 時間 
◦函式實作內容: 
1. 依據輸入的 pin 編號, 初始化對應的 timer 
2. 計算輸入的 frequency 並將結果填入 timer 暫 存器 
3. 將 duration 與 frequency 換算成 timer counter 
4. 開啟 timer 中斷, 在 ISR 中進行/停止 pulse 輸出
Tone.cpp
… 
Tone.cpp
硬體相關函式實作解析 
noTone (pin) 
◦函式功能: 
停止指定 pin 的 pulse 輸出 
◦函式實作內容: 
1. 依據輸入的 pin 編號, 取得正在使用中的 timer 
2. 關閉 timer 中斷 
3. 將輸出 pin 的電位設定為 0
Tone.cpp
硬體相關函式實作解析 
shiftOut (datapin, clockpin, bitorder, val) 
◦函式功能: 
選用兩個 pin 作為 datapin 與 clockpin, 將 8-bit val 用指定的 bitorder 送出 
◦函式實作內容: 
1. 依照指定的 bitorder 將 val 從 datapin 輸出 
2. 改變 clockpin 電位, 使其 high、low 各一次
wiring_shift.c
硬體相關函式實作解析 
shiftIn (datapin, clockpin, bitorder) 
◦函式功能: 
選用兩個 pin 作為 datapin 與 clockpin, 用指定的 bitorder 讀取 8-bit 的 value 
◦函式實作內容: 
1. 設定 clockpin 電位為 high 
2. 用指定的 bitorder 從 datapin 讀取 1bit value 
3. 設定 clockpin 電位為 low 
4. 以上三個步驟重複 8 次
wiring_shift.c
硬體相關函式實作解析 
PulseIn (pin, state, timeout) 
◦函式功能: 
對指定的 pin 去計算輸入 state (high/low) 的持續時間 
◦函式實作內容: 
1. 由指定的 pin 編號來取得對應的 port 
2. 設定 state 的 timeout 時間 
3. 等待 pin 的電位變化到非指定的 state 
4. 等待 pin 的電位變化到指定的 state 並開始計時 
5. 等待 pin 的電位變化到非指定的 state 並停止計時 
6. 回傳指定 state 持續的總時間
wiring_pulse.c
硬體相關函式實作解析 
millis ( ) 
◦函式功能: 
回傳 Arduino 運行後所經過的時間, 單位是 millisencond, resolution 是 1ms 
◦函式實作內容: 
1. 關中斷 
2. 讀取目前的 timer0_millis 變數值 
3. 開中斷 
4. 回傳其值
wiring.c
硬體相關函式實作解析 
micros ( ) 
◦函式功能: 
回傳 Arduino 運行後所經過的時間, 單位是 microsencond, resolution 是 4us (for 16MHz) 
◦函式實作內容: 
1. 關中斷 
2. 先讀取 timer overflow 的次數 
3. 判斷此時 timer 是否 overflow, 若是則加一次 
4. 讀取目前的 timer counter 
5. 開中斷 
6. 計算 timer overflow 次數與 counter 值 
7. 將計算結果回傳
wiring.c
硬體相關函式實作解析 
delay (ms) 
◦函式功能: 
延長一段指定的時間, 單位是 ms, resolution 是 1ms 
◦函式實作內容: 
1. 調用 micros ( ) 得到目前的時間 count 值 
2. 每經過 1ms 後把指定的 ms 值減一, 直到 ms 等於 0 為止
wiring.c
硬體相關函式實作解析 
delayMicroseconds (us) 
◦函式功能: 
延長一段指定的時間, 單位是 us, resolution 是 1us 
◦函式實作內容: 
1. 依據 CPU 時脈與輸入的 us, 算出需要的 count 總數 
2. 將 count 減一, 直到 0 為止
wiring.c
硬體相關函式實作解析 
interrupts ( ) 
◦函式功能: 
打開 global 中斷 
◦函式實作內容: 
對 SREG 的第 7 bit (Global Interrupt Enable) 填 1 
Arduino.h 
interrupt.h
硬體相關函式實作解析 
nointerrupts ( ) 
◦函式功能: 
關閉 global 中斷 
◦函式實作內容: 
對 SREG 的第 7 bit (Global Interrupt Enable) 填 0 
Arduino.h 
interrupt.h
硬體相關函式實作解析 
attachInterrupt(intnum, userFunc, mode) 
◦函式功能: 
掛載使用者的 callback function, 並依據輸入 mode 決定觸發外部中斷的條件 
◦函式實作內容: 
1. 掛載 user function 
2. 設定觸發 mode 
3. 依據指定的 intnum, 啟用可作為外部觸發功能 的腳位
WInterrupts.c
硬體相關函式實作解析 
detachInterrupt(intnum) 
◦函式功能: 
卸載指定 intnum 的外部中斷功能 
◦函式實作內容: 
依據使用的 Arduino 版本, 關閉指定的外部中斷
WInterrupts.c
硬體相關函式實作解析 
Serial.begin (baud) 
◦函式功能: 
設定串列傳輸的 buadrate 
◦函式實作內容: 
依據使用的 Arduino 版本, 把指定的 baudrate 設 定到 baudrate 暫存器中 
啟用 RX、 TX、RX complete 中斷、Data Register Empty 中斷
HardwareSerial.cpp
硬體相關函式實作解析 
Serial.available ( ) 
◦函式功能: 
判斷 COM port 是否收到數據 
◦函式實作內容: 
回傳 rx buffer 中的 data 個數 
HardwareSerial.cpp
硬體相關函式實作解析 
Serial.read ( ) 
◦函式功能: 
讀取 COM port 讀到的數據 
◦函式實作內容: 
判斷 rx buffer 是否為空, 如果是則回傳 -1, 如果 不是則讀取一個 data, 回傳給使用者
HardwareSerial.cpp
硬體相關函式實作解析 
Serial.write ( ) 
◦函式功能: 
寫入 data 到 COM port 
◦函式實作內容: 
判斷 tx buffer 是否為已滿, 如果是, 則等到有空 間時把一個 data 丟進 tx buffer, 如果不是則立 刻把一個 data 丟進去
HardwareSerial.cpp
下一個推倒對象: 86Duino
86Duino硬體配置 
多功能 外部中 斷 I/O 
USB 2.0 
Arduino Leonardo 相容 I/O 
Arduino Leonardo 相容 I/O 
Arduino Leonardo 相容 I/O
86Duino硬體配置 
MicroSD 
LAN 
PCI-e target
86Duino 軟體設計概觀 
IDE 設計原則 
◦不改變 Arduino IDE 原有功能的前提下, 加 入對 86Duino 的編譯及燒錄支援 
移植 coreboot + SeaBIOS 做為 86Duino 的開源 BIOS 
韌體使用 FreeDOS 做為 OS 
◦快速開機: 通電 2 秒內 run 起使用者程式 
◦中斷掛載容易實現 
◦架構上最接近 Arduino 韌體架構
86Duino 軟體設計概觀 
採用 DJGPP 做為 86Duino 的編譯系統 
◦DJGPP: 第一款出現在 x86 上的 GUN gcc 
◦相容大部分 avr-gcc 的語法 
◦執行於 x86 保護模式下, 無記憶體使用限制 
使用 DJGPP 的問題 
◦DJGPP 為 DOS 程式, 無法直接在 Linux, Mac, 64-bit Win7/Win8 下執行 
◦目前解決方法: 86Duino IDE 調用 DOSBOX 執行 DJGPP
軟體開發背後堅持的原則 
在軟體系統每個環節, 只使用歐噴壽司 工具 
◦BIOS: coreboot + SeaBIOS (open source) 
◦OS: FreeDOS (open source) 
◦編譯系統: DJGPP & DOSBOX (open source) 
◦程式庫: DJGPP & Arduino上各種第三方開 源程式庫 (ex: Allegro) 
◦IDE: Processing/Arduino IDE (open source) 
◦燒錄軟體: 自己寫 (open source)
Arduino Standard API 在 86Duino 上的移植 
直接來自 C/C++ standard library 的 API 
◦DJGPP 與 avr-gcc 相容, 無需移植 
直接使用 C 語言巨集定義的 API 
◦直接沿用 Arduino 原始碼 
平台獨立 API 
◦直接沿用 Arduino 原始碼 
硬體相關 API 
◦重新改寫至 x86 平台
硬體相關 API 在 86Duino 上的實作 
pinMode( ) 
◦函式功能: 
用以配置腳位為輸出或輸入模式 
◦程式設計流程: 
與 Arduino 流程相同 
改填屬於 86Duino 自己的暫存器
wiring_digital.cpp
硬體相關 API 在 86Duino 上的實作 
digitalWrite (pin, value) 
◦函式功能: 
設定腳位輸出電位為 HIGH/LOW 
◦函式實作內容: 
1. 檢查指定 pin 上的硬體 PWM 是否正在被使用, 如果是則停止它 
2. 由 pin 編號找到對應的暫存器 
3. 依照輸入的 value, 修改暫存器設定
wiring_digital.cpp
digitalRead (pin) 
◦函式功能: 
讀取指定腳位的輸入電位, 回傳 HIGH/LOW 
◦函式實作內容: 
1. 檢查指定 pin 的硬體 PWM 是否正在被使用, 如 果是則停止它 
2. 由 pin 編號找到對應的暫存器, 讀取並判斷暫存 器值後, 回傳 HIGH/LOW 硬體相關 API 在 86Duino 上的實作
wiring_digital.cpp
硬體相關 API 在 86Duino 上的實作 
analogRead (pin) 
◦函式功能: 
讀取 A/D 的電壓數值 
◦函式實作內容: 
1. 初始化 A/D 
2. 設定 PIN 
3. 開始做 A/D 轉換 
4. 回傳轉換後的值
wiring_analog.cpp
硬體相關 API 在 86Duino 上的實作 
analogWrite (pin, val) 
◦函式功能: 
使用 86duino 中的 MCM 之 PWM 硬體送出指定 duty 的 PWM 
◦函式實作內容: 
1. 從指定 pin 編號, 找到相對應的 MCM 
2. 將指定 pin 切成 PWM 輸出 
3. 把 val 設定至 PWM 相關暫存器 
4. Enable PWM
wiring_analog.cpp
wiring_analog.cpp
硬體相關 API 在 86Duino 上的實作 
tone (pin, frequency, duration) 
◦函式功能: 
從指定的 pin 送出 frequency 頻率的 pulse (duty 為 50%) 並持續一段 duration 時間 
◦函式實作內容: 
1. 計算輸入的 frequency 並將結果填入設定 PWM 相關暫存器 
2. 將 duration 與 frequency 換算成 PWM period 的總個數 
3. 開啟 MCM 中斷, 在 ISR 中進行/停止 pulse 輸出 
Tone ( ) 的 PWM 主要作為 timer 用, 指定腳位上不會輸出 PWM pulse
Tone.cpp
Tone.cpp
硬體相關 API 在 86Duino 上的實作 
noTone (pin) 
◦函式功能: 
停止指定 pin 的 pulse 輸出 
◦函式實作內容: 
1. 關閉 MCM PWM 
2. 將輸出 pin 的電位設定為 0
Tone.cpp
硬體相關 API 在 86Duino 上的實作 
shiftOut (datapin, clockpin, bitorder, val) 
◦函式功能: 
選用兩個 pin 作為 datapin 與 clockpin, 將 8-bit val 用指定的 bitorder 送出 
◦函式實作內容: 
內容與 Arduino 相同, 未做任何修改
硬體相關 API 在 86Duino 上的實作 
shiftIn (datapin, clockpin, bitorder) 
◦函式功能: 
選用兩個 pin 作為 datapin 與 clockpin, 用指定的 bitorder 讀取 8-bit 的 value 
◦函式實作內容: 
內容與 Arduino 相同, 未做任何修改
硬體相關 API 在 86Duino 上的實作 
PulseIn (pin, state, timeout) 
◦函式功能: 
對指定的 pin 去計算輸入 state (high/low) 的持續時間 
◦函式實作內容: 
1. 設定硬體 PWM 參數 
2. 等待 pin 的電位變化到非指定的 state 
3. 等待 pin 的電位變化到指定的 state 並開始計時 
4. 等待 pin 的電位變化到非指定的 state 並停止計時 
5. 回傳硬體 PWM 的 sample cycle 
6. 計算時間並回傳數值
wiring_pulse.cpp
硬體相關 API 在 86Duino 上的實作 
millis ( ) 
◦函式功能: 
回傳 86duino 運行後所經過的時間, 單位是 millisencond, resolution 是 1ms 
◦函式實作內容: 
回傳 timer_nowtime ( ) 的值 
timer_nowtime() 函式實作內容: 在 DOS DJGPP 環境底下調用 uclock(), 取得的時間換算成 millisecond 後回傳
wiring.cpp 
common.cpp
硬體相關 API 在 86Duino 上的實作 
micros ( ) 
◦函式功能: 
回傳 86duino 運行後所經過的時間, 單位是 microsencond, resolution 是 1us 
◦函式實作內容: 
1. 取得 CPU clock count 
2. 將 count 以 CPU 時脈換算後回傳
wiring.cpp 
common.cpp
硬體相關 API 在 86Duino 上的實作 
delay (ms) 
◦函式功能: 
延長一段指定的時間, 單位是 ms, resolution 是 1ms 
◦函式實作內容: 
1. 將 timer_nowtime ( ) 得到的數值加上輸入的 ms 計算出目標時間 
2. 無限等待, 直到超過/到達目標時間
wiring.cpp 
common.cpp
硬體相關 API 在 86Duino 上的實作 
delayMicroseconds (us) 
◦函式功能: 
延長一段指定的時間, 單位是 us, resolution 是 1us 
◦函式實作內容: 
將目前時間減去進入此 function 的時間, 將結果 轉換成 microsecond 單位後與輸入的 us 值比較, 直到值大於 us 為止
wiring.cpp 
common.cpp
硬體相關 API 在 86Duino 上的實作 
interrupts ( ) 
◦函式功能: 
打開 global 中斷 
◦函式實作內容: 
對 EFLAGS 的 IF bit 填 1 
Arduino.h 
io.c
硬體相關 API 在 86Duino 上的實作 
nointerrupts ( ) 
◦函式功能: 
關閉 global 中斷 
◦函式實作內容: 
對 EFLAGS 的 IF bit 填 0 
Arduino.h 
io.c
硬體相關 API 在 86Duino 上的實作 
attachInterrupt(intnum, userFunc, mode) 
◦函式功能: 
掛載使用者的 callback function, 並依據輸入 mode 決定觸發外部中斷的條件 
◦函式實作內容: 
1. 掛載 user function 
2. 設定觸發 mode 
3. 依據指定的 intnum, 啟用可作為外部觸發功能 的腳位
WInterrupts.cpp
硬體相關 API 在 86Duino 上的實作 
detachInterrupt(intnum) 
◦函式功能: 
卸載指定 intnum 的外部中斷功能 
◦函式實作內容: 
關閉指定的 intnum 中斷
WInterrupts.cpp
硬體相關 API 在 86Duino 上的實作 
Serial.begin (baud) 
◦函式功能: 
設定串列傳輸的 buadrate 
◦函式實作內容: 
1. 設定鮑率。 
2. 設定傳輸資料長度、同位元檢查、停止位元。 
3. 清空 TX、RXQueue。 
4. 設定 timeout。
HardwareSerial.cpp
硬體相關 API 在 86Duino 上的實作 
Serial.available ( ) 
◦函式功能: 
判斷 COM port 是否收到數據 
◦函式實作內容: 
回傳 rx queue中的 data 個數 
HardwareSerial.cpp
硬體相關 API 在 86Duino 上的實作 
Serial.read ( ) 
◦函式功能: 
讀取 COM port 讀到的數據 
◦函式實作內容: 
調用 com lib 中的 com_Read ( ) 
讀取一個 rx buffer 中的值並回傳 
HardwareSerial.cpp
硬體相關 API 在 86Duino 上的實作 
Serial.write ( ) 
◦函式功能: 
寫入 data 到 COM port 
◦函式實作內容: 
調用 com lib 中的 com_Write ( ), 傳送一個 8-bit 值 
HardwareSerial.cpp
Arduino 原始碼讀書會 (II) : Bootloader 解析
找出 bootloader 原始碼
讓我們再次回到熟悉的地方 
https://github.com/arduino/Arduino
Arduino 原始碼根目錄 
改過的 Processing IDE 原始碼 (Arduino 相關) 
Processing IDE 原始碼 
存放編譯結果的目錄 
Arduino Bootloader, Standard API 原始碼 
Arduino Library 原始碼
hardware → arduino 
各種版本 bootloader 原始碼 
Standard API 原始碼(共用部分) 
各種周邊配套的處理器韌體 
Standard API 不共用部分 
定義 Board 選單及編譯參數 
定義 Programmers 選單及燒錄參數
hardware → arduino → bootloaders 
Duemilanove , Diecimila , Nano , Fio ....... 
Arduino NG or older w/ ATmega8 
BT ATmega328 , BT ATmega168 
Arduino Robot 
LilyPad Arduino USB 
Leonardo , Micro , Esplora 
LilyPad Arduino ATmega168 
Uno , Mini ATmega328 , Ethernet 
Mega 2560 , Mega ADK 
本次原始碼解析目標 
(其它bootloaders可以此類推)
UNO Bootloader 
optiboot source code 
已編譯好的各種 版本 16 進位檔
Leonardo Bootloader 
caterina source code 
已編譯好的各種 版本 16 進位檔 
各種版本 bootloader 說明
Serial Bootloader 解析 --- 以 UNO 為例
Arduino UNO Bootloader 
Arduino UNO 使用了 optiboot,優點: 
◦佔用空間只有1.5kB 
◦鮑率115200,上傳程序速度較舊版 ATmega bootloader 快 
◦程式碼進行了優化,運行效率較舊版提高, 並且無看門狗問題 
◦支持較多的 ATmega 晶片
與 Bootloader 有關的電路 USB to Serial bridge Arduino 主晶片 
USB 接頭 PC 
USB 
Serial
與 Bootloader 有關的電路 Serial TX/RX 資料傳輸線 
Serial DTR 
(用於 reset 
Arduino) 
Arduino 
主晶片 USB to Serial bridge
UNO Bootloader 程式流程 
UART init 
Watchdog init 
是否由 RESET Pin 引起 
執行 Arduino F/W 
否 
是 
依命令把 Arduino F/W寫入 Flash 
把 watchdog 設定成 16ms, 並等待系統自行 reset 
reset 
每接收一個字元都會 重設 watchdog 
Watchdog 預設 1s (timeout 自行 reset) 
TX, RX 燈號是由 Atmega16U2(USB to Serial bridge) 控制 
由 serial port 接收 Host 命令 
是 
否 
收到 exit bootloader 命令
Bootloader 原始碼重要細節 
判斷 reset 來源, 如果不是 reset button 或 serial DTR reset, 就呼叫 appStart() 直 接執行 Arduino F/W 
初始化 watchdog timer = 1s, (如果一秒內 bootloader 沒有從 serial 收到任何資 料, 將會自動跳出並執行 Arduino F/W)
Bootloader 原始碼重要細節 
從 serial port 讀取字元 Bootloader main loop 
進行 STK500 通訊協定的命令處理 (STK500協定規範請自行參考 Atmel 文件: http://www.atmel.com/Images/doc2591.pdf) 
如果收到 exit 命令, 則設定 watchdog timer = 16ms, 並 呼叫 verifySpace() 等待系 統自行 reset
Bootloader 重要函式註解 
getch ( ) 
◦從 serial port 讀取一字元 
putch ( ) 
◦由 serial port 送出一字元 
verifySpace ( ) 
◦接受並回應 STK500 命令結尾 token
Bootloader 重要函式註解 
watchdogReset ( ) 
◦Reset watchdog timer 
watchdogConfig ( ) 
◦設定 watchdog timer 
appStart ( ) 
◦執行使用者燒錄的 Arduino 韌體程式
Arduino IDE 對 Bootloader 的操作 
IDE 將編譯程 式, 並透過 bootloader 將 編譯結果 上傳到 Arduino 板子上
Arduino IDE 對 Bootloader 的操作 
IDE 上傳程式的流程 
取得要燒錄的檔案所在路徑 和檔案名稱 
由板子版本決定燒錄參數 
取得燒錄程式路徑與檔名 
執行燒錄程式 avrdude.exe 
是否燒錄成 功? 
回傳失敗 
是 (由 avrdude.exe 的回傳值決定) 
否 
(IDE 這部分的原始碼等之後 的讀書會再進行詳細解析) 
回傳成功 
Avrdude 會自行透過 DTR 重啟 Arduino, 以進入 bootlaoder
USB Bootloader 解析 --- 以 Leonardo 為例
Arduino Leonardo Bootloader 
Arduino Leonardo 使用 caterina bootloader 
◦透過 USB 直接與 PC 通訊, 省掉 USB to Serial bridge, 降低成本 
◦使用 LUFA library 來進行 USB 通訊 
LUFA 是一套 AVR 系列微處理機專用的通訊程式 庫, 支援各種 USB Class 
caterina 只用到 CDC Class 的功能
與 Bootloader 有關的電路 USB 通訊線 Arduino 主晶片
與 Bootloader 有關的電路 
USB 通訊線 USB 電源輸入 USB 接頭
Leonardo Bootloader 程式流程 
HW init 
Timer 
LUFA init 
是否有 POWER-ON reset 
Detach USB 並執行 Arduino F/W 
否 
是 
Timer 中斷設定成每 1ms 觸發 一次, 裡面處理 TX/RX LED 與 bootloader timeout 
依命令把 Arduino F/W 寫入 flash, 並重置 timeout count 
(timeout count > 8000) 
把 timeout count 設 定為 7500 
等待 timeout 
timeout count 不累加 
Arduino F/W 是否存 在? 
timeout count ++ 
是 
否 
點滅 TX/RX LED 
是否 timerout 
是 
否 
Timer 中斷副程式 
Bootloader 主程式 
由 USB 接收 Host 命令, 點亮 TX/RX LED 
收到 exit bootloader 命令 
是 
否
Bootloader 原始碼重要細節 
如果是由 reset button 引 起的 reset, 則進入 bootloader 
如果不是軟體 reset, 則直接執行 Arduino F/W 
如果是 POWER-ON reset, 則直接執行 Arduino F/W
Bootloader 原始碼重要細節 Bootloader main loop 
執行 AVR910 通訊協定命令 
LUFA library 的 USB 通訊處理 
超過 8 秒沒從 host 收到資 料, 則跳出 bootloader 執行 Arduino F/W 
執行 Arduino F/W 
切斷 USB 連結 (Arduino F/W 會自己再一次進 行 USB 連接行為)
Bootloader 原始碼重要細節 
Bootloader timer 中斷副程式, 每隔 1ms觸發執行一次 
Bootloader 使用的 timerout count 變數
Bootloader 原始碼重要細節 
AVR910 通訊協定處理函式 
指定 USB 資料讀取通道 
從 USB 讀取字元 
判斷 USB 通道是否有資料存在 
如果收到 exit 命令, 則等待 0.5 秒再跳出執行 Arduino F/W 
進行 AVR910 通訊協定 的命令處理 (AVR910協定請自行參 考 Atmel 文件: http://www.atmel.com/images/doc0943.pdf)
Bootloader 重要函式註解 
FetchNextCommandByte ( ) 
◦從 USB port 讀取一字元 
WriteNextResponseByte ( ) 
◦由 USB port 送出一字元 
SetupHardware ( ) 
◦硬體初始化函式
Bootloader 重要函式註解 
StartSketch ( ) 
◦執行使用者的 Arduino 韌體程式 
EVENT_USB_Device_ConfigurationChanged ( ) 
◦USB 事件處理 callback 
EVENT_USB_Device_ControlRequest ( ) 
◦USB 事件處理 callback
Arduino IDE 對 Bootloader 的操作 
IDE 上傳程式的流程 
取得要燒錄的檔案所在路徑 和檔案名稱 
由板子版本決定燒錄參數 
取得燒錄程式路徑與檔名 
執行燒錄程式 avrdude.exe 
是否燒錄成 功? 
對目前的 USB serial port 設定 1200 bps baudrate 後再關閉 
等待 bootloader USB serial port 出現 
Timeout?(5s) 
等待 Arduino sketch USB serial port 出現 
將 Arduino sketch USB serial port baudrate 改 成正常值, 並回傳燒錄 成功 
Timeout?(2s) 
回傳燒錄成功 
回傳失敗 
回傳失敗 
是 
否 
是 (由 avrdude.exe 的回傳值決定) 
否 
是 
否 
Arduino 自行切斷 USB 再重新連線 
(IDE 這部分的原始碼等之後的讀 書會再進行詳細解析) 
(對 Arduino 做軟體 reset)
Leonardo 軟體 RESET 機制的實作 
在 IDE 上傳 Arduino F/W 之前, 會先將 USB serial port 設定成 1200bps baudrate, 然後再關閉 serial port 
上述行為會讓 Leonardo 上的 F/W 對一個 指定記憶體空間填入 bootkey, 然後再自己 reset 
reset 後進入 bootloader, 會去判斷是否為 軟體 reset (檢查 bootkey), 如果是, 則進入 bootloader main loop 開始接收資料
輕鬆小品, 休息一下~~ 複習 Arduino Bootloader 燒錄
接線路(Arduino to Arduino)
接線路(Arduino to MCU)
開啟 ArduinoISP程式檔
將程式上傳到Arduino板子上
選擇板子種類
開始燒錄bootloader
86Duino 的 Bootloader 實作
86Duino Bootloader 行為 
86Duino Bootloader 只是開機第一個執行 的 DOS 執行檔 
行為大部分與 Arduino Leonardo 相同 
只有軟體 reset 可以啟動 Arduino 韌體燒 錄機制 
◦Arduino Leonardo 則是軟體 reset 和 reset button 皆會啟動 Adruino 韌體燒錄機制
86Duino Bootloader 行為 
86Duino F/W 先整個被接收到記憶體內, 再一次寫入 flash 
◦當傳輸過程出錯, 不會破壞原有韌體程式 
86Duino F/W 會先燒錄至暫存空間, 成功 後再映射至韌體存放空間 
◦當寫入過程出錯, 不會破壞原有韌體程式
Bootloader 原始碼重要細節 
86Duinio F/W 最大 SIZE 
Bootloader timeout 時間 
可燒錄的程式類型
Bootloader 原始碼重要細節 
初始化 I/O port 
決定 bootloader 的運作模式 
判斷是否有軟體 reset
Bootloader 原始碼重要細節 
初始化 USB device port 
配置存放 86Duino F/W 的記憶體陣列
Bootloader 原始碼重要細節 
Bootloader main 
loop 開始
Bootloader 原始碼重要細節 
讀取要燒錄的 86Duino F/W 大小
Bootloader 原始碼重要細節 
從 USB 接收 86Duino F/W 檔案
Bootloader 原始碼重要細節 
86Duino F/W 燒錄
Bootloader 原始碼重要細節 
若是執行 Bootloader 燒錄則 reboot, 反之 則執行 86Duino F/W
初版程式燒錄的 protocol 
沒有使用 protocol (未來會新增) 
初版是直接傳送特定格式的資料 
TYPE 
Data length 
Data 
1 Byte 
4 Bytes 
N Bytes 
1: 檔案是 bootloader 2: 檔案是 user program
86Duino 軟體 RESET 機制的實作 
由 IDE 把 USB serial port 開啟為 1200bps baudrate 後再關閉 (與 Arduino Leonardo 相同) 
86Duino 收到上述行為後, 會對一個 I/O 空間寫入特定值, 然後自己 reset 
reset 後進入 bootloader, 判斷上次是否 為軟體 reset, 如果是, 則開始接收新的 F/W
Arduino 原始碼讀書會(III) : Arduino IDE 解析
Arduino IDE 的編譯
取得 Arduino Source Code 
第一種方式: 
◦使用 git 軟體 
下載: http://git-scm.com/downloads 
◦指令: 
git clone https://github.com/arduino/Arduino.git
取得 Arduino Source Code 
第二種方式: 
◦直接下載 source code 
點選這裡可直接下載
●Arduino IDE Source Code 
https://github.com/arduino/Arduino 
●Cygwin 
http://cygwin.com/install.html 
●Sun Java JDK(Java SE Development Kit) 
http://www.oracle.com/technetwork/java/javase/downloads/index.html 
●Apache Ant Binary Distributions 
http://ant.apache.org/bindownload.cgi 
●git 
http://windows.github.com/ 
Windows-下載相關應用程式
Setup steps(1) 
安裝 Cygwin 
安裝 Java JDK 
解壓縮apache-ant-x.x.x-bin.zip至 ProgrmFiles
Setup steps(2) 
控制台所有控制台項目系統進階系統設定 進階環境變數
Setup steps(3) 
在使用者變數裡新增 
變數名稱 
變數值 
ANT_HOME 
C:Program Filesapache-ant-1.9.2 
(apache ant資料夾路徑) 
JAVA_HOME 
C:Program FilesJavajdk1.7.0_45 
(Java JDK資料夾路徑)
Setup steps(4) 
在系統變數中 
◦將apache-ant中的bin資料夾路徑加入Path變 數值中
Setup steps(5) 
開啟cmd,移至Arduino底下的build 
>ant 
>ant run
Setup steps(6) 
將…buildwindows中的jre.zip裡面的java 資料夾解壓縮到…buildwindowswork
Linux(Ubuntu)所需的應用程式 
●Sun Java JDK 
$sudo add-apt-repository ppa:webupd8team/java $sudo apt-get update 
$sudo apt-get install oracle-java8-installer 
●Apache Ant 
$ sudo apt-get install ant 
●avr-gcc, avr-g++, avr-libc 
$ sudo apt-get install arduino 
●Make 
$ sudo apt-get install make 
●(git) 
$ sudo apt-get install git
Setup steps 
●$ git clone git://github.com/arduino/Arduino.git 
●$ cd ./Arduino/build/ 
●$ ant 
●$ ant run
Mac OSX所需要的應用程式 
●Java for OSX 
http://support.apple.com/kb/dl1572 
●(git) 
–$ sudo port selfupdate 
–$ sudo port install git-core
Setup steps 
●$ git clone git://github.com/arduino/Arduino.git 
●$ cd ./Arduino/build/ 
●$ ant 
●$ ant run
開胃小菜: Arduino IDE Hacking Tips
讓我們再次回到熟悉的地方 
https://github.com/arduino/Arduino
切換到 1.5.x 分支 
1.5.x 支援 Arduino Due, Yun, …
Arduino 原始碼根目錄 
改過的 Processing IDE 原始碼 (Arduino 相關) 
Processing IDE 原始碼 
存放編譯結果的目錄 
Arduino Bootloader, Standard API 原始碼 
Arduino Library 原始碼
App →src →processing →app 
Arduino 編譯、燒錄相關程式碼 
前置處理的相關程式碼, 例如: 字串轉換… 
Arduino IDE 選單、按鈕功能程式碼 
處理Sketch.ino 相關程式碼
App →src →processing →app →preproc 
處理字串問題程式碼
App→src →processing→app→ debug 
Arduino 編譯相關程式碼
語言設定 
如何客製化呢?
App →src →processing →app 
語言設定檔的位置 
中英說明文件 (修改後沒有效果) 
英轉中 編碼轉換設定檔
修改中文顯示訊息 
Resources_zh_tw.po 
Resources_zh_tw.properties 
英文字串 Open… 替換成 開啟… (unicode 編碼)
修改範例 
修改後重新編譯 IDE 即可看到結果 
中文: 我愛Fablab (unicode)
在下拉式選單新增選項 
新增 Burn Bootloader 子選單 
新增 Arduino Bootloader 項目 
選項動作 callback 
修改 Editor.java 的 buildToolsMenu( ) 
Example: 
新增 86Duino Bootloader 項目 
修改結果:
在 hardware 下新增資料夾。 Ex: 86Duinox86 
資料夾底下需要這幾個資料夾和檔案 
以上這些檔案不需重新編譯 Arduino IDE,只需新 增檔案並且重新開啟 Arduino IDE 即可看到效果。 添加 Arduino 相容板 
bootloaders 
libraries 
編譯、上傳參數 設定 
standardAPI 
Arduino 相容板 子的各種參數
添加 Arduino 相容板 
boards.txt 
platform.txt 
設定板子名稱 
設定板子相關參數 
設定板子選單名稱
添加 Arduino 相容板 
尚未添加板子前 boards 選單 
添加後的 boards 選單
存放 UI 外觀圖檔及設定檔的路徑: buildsharedlibtheme 修改 UI 外觀顯示
UI 設定檔 
theme.txt 文件內容
更換 IDE 的啟動 logo 
直接修改或更換此檔案,並且重新編譯Arduino IDE,編 譯完成即可看到更改後圖案。
修改 IDE 顯示版本號 
修改此字串並重新編譯, 即可更換 IDE 顯示的版本號 
build.xml 內容
修改 IDE 顯示版本號 
修改的版本號:~1.5.4^^
修改 IDE 視窗左上角小圖示 
打開 Papplet.java 檔
修改 IDE 視窗左上角小圖示 
把 ICON_IMAGE 陣列內容換成 想換的小圖示, 格式必須為 GIF
修改 IDE 視窗左上角小圖示 
IDE 視窗 
Serial monitor 視窗 
修改結果: 
修改後重新編譯 IDE 即可看到效果
第一道主菜: Sketch 編譯機制
Arduino 編譯流程
IDE 視窗 
按下編譯按鈕主要做了三個動作: 1. 產生暫存資料夾 (Sketch.java) 2. 前處理 Sketck.ino 檔 (PdePreprocessor.java) 3. 編譯 Sketck.ino 檔 (Compiler.java)
App →src →processing →app 
Arduino 編譯、燒錄相關程式碼 
處理字串問題相關程式碼 
Arduino IDE 選單、按鈕功能程式碼 
處理Sketch.ino 相關程式碼
產生存放編譯結果的暫存資料夾 
處理 Sketch.ino檔 並開始編譯 
Editor.java – DefaultPresentHandler( )
App →src →processing →app 
Arduino 編譯、燒錄相關程式碼 
處理字串問題相關程式碼 
Arduino IDE 選單、按鈕功能程式碼 
處理Sketch.ino 相關程式碼
前處理 Sketch.ino檔案 
找出 .ino 和 .pde 檔 
在 .ino/.pde 檔中加入檔頭修正 (請參考第 1 次讀書會內容) 
Sketch.java - preprocess( ) 
修改Sketch.ino 檔案
App →src →processing →app →preproc 
Sketch 前處理的程式碼
前處理 Sketch.ino檔案 
PdePreprocessor.java – writeProgram( ) 
在 .ino/.pde 檔中加入 
#include “Arduino.h ” 
加入函式原型宣告 
加入行號修正
原始 skecth 
被 IDE 改寫的 skecth 
Sketch 處理前後之差異
找出 sketch 內呼叫的 libraries 
找出 include 的 library 
PdePreprocessor.java – writePrefix( )
App→src →processing→app→ debug 
Arduino 編譯相關程式碼
Sketch 編譯流程重點講解 
取得暫存資料夾路徑 
取得libraries路徑 
Compiler.java - compile( )
Sketch 編譯流程重點講解 
編譯Sketch.ino 
編譯libraries 
編譯standardAPI 
產生.elf檔 
產生.eep檔 
產生.hex 執行檔 並結束編譯
Sketch 編譯流程重點講解 
Compiler.java - compileSketch( ) 
呼叫 CompileFiles 執行 sketch 編譯
Sketch 編譯流程重點講解 
Compiler.java - compileLibraries( ) 
讀取所有被 include 的 libraries 
在 tmp 建立 library 資料夾 
在 library 資料夾 底下建立 utility 資料夾 
編譯 library 
編譯 library 底下 utility
Sketch 編譯流程重點講解 
Compiler.java - compileCore( ) 
讀取 standaAPI 路徑 
讀取 variant 資料夾路徑 
編譯 standaAPI 
編譯 variant 資料夾下的 檔案 
取得 .a 檔編譯 pattern 
編譯 .a 檔 
加入編譯 .a 檔參數
產生編譯.s檔案的 gcc 命令 
執行avrgcc 
Compiler.java - compileFiles( ) Sketch 編譯流程重點講解
Sketch 編譯流程重點講解 
產生編譯 .c檔案的 gcc 命令 
產生編譯 .cpp檔案的 gcc 命令 
執行 avrgcc 
執行 avrgcc
Sketch 編譯流程重點講解 
將編譯結果顯示到 IDE 訊息框內 
開新的 process 執行avrgcc 命令 
Compiler.java - execAsynchronously( )
配菜: 加入 86Duino 程式編譯 對 IDE 所做的修改
86Duino 編譯系統 
DOSBox + DJGPP 
DOSBox 是一個跨平台的 DOS 模擬軟體 
◦在 IDE 的路徑: buildwindowsworkDOSBox-0.74 
DJGPP 是一個可在 DOS 下編譯程式的 GNU gcc 
◦在 IDE 的路徑: buildwindowsworkDJGPP
86Duino 編譯流程
86Duino原始碼重要細節 
如果使用者選的板子是 86Duino, 則跳到 duinocompiler.java 編譯 
Compiler.java - compile( )
86Duino原始碼重要細節 
設定所需程式的路徑參數 
DuinoCompiler.java - compile( )
86Duino原始碼重要細節 
Makefile 檔案路徑、編譯出檔案路徑 設定 
DuinoCompiler.java - compile( )
86Duino原始碼重要細節 
Dosbox config設定 
Makefile 設定 
設定 DOSBox 執行命令 
將編譯訊息寫到 MESSAGE.TXT 
DuinoCompiler.java - compile( )
86Duino原始碼重要細節 
Dosbox參數設定 
Dosbox執行編譯參數設定 
DuinoCompiler.java - writeDosboxconf( )
86Duino原始碼重要細節 
設定編譯命令參數 
將之前Makefile設定 讀取進來並編譯 
DuinoCompiler.java - writeMakefile( )
第二道主菜: Arduino 程式的燒錄機制
實作燒錄的 IDE 原始碼: app→src → processing → app → debug 
本次解析目標 
處理 Arduino 程式燒錄動作 
處理 Arduino 程式燒錄動作
Arduino 程式燒錄設定檔 
hardware→arduino→avr 
分別簡要介紹 
定義 boards 選單、編譯及燒錄參數 
定義編譯及燒錄參數 
本次解析目標
燒錄設定檔的用途 
Arduino IDE 在燒錄程式之前, 會從燒錄設定 檔讀取與板子相關的燒錄參數 
這些設定檔中, 使用一種特定的格式, 記錄了 每塊 Arduino 板子的差異, 例如: 
◦CPU時脈、燒錄的 protocol、燒錄檔案的最大 size 等等 
只要推出一片新的板子, 依照指定的格式加入 新參數, 就可以直接套用到目前的 IDE, 不需 要重新編譯程式
boards.txt 格式: 以 Leonardo 為例 
要在 Boards 選單上顯示的名稱 
燒錄工具程式檔名 
燒錄用的 protocol 
允許燒錄的 binary 最大 size 
燒錄用的 baudrate 
板子名稱 
燒錄 sketch 的參數設定 
燒錄 bootloader 的參數設定 
設定燒錄時 IDE 清空 serial data 值 
設定燒錄時用 1200 baudrate 來 reset Arduino 
設定 reset Arduino 後要等待 upload port 出現才可進行燒錄 
這次讀書會不講燒錄 bootloader 部分
boards.txt 格式: 以 Leonardo 為例 
板子名稱 
編譯 sketch 的相關參數 
Leonardo 的 CPU 型號( 燒錄會用到的參數)
platform.txt 的格式: 以 Leonardo 為例 
在 linux 下, 燒錄工具程式的位置以及燒錄 config 檔的位置 
在 windows 和 Mac 下, 燒錄工具程式的位置以及燒錄 config 檔的位置
platform.txt 格式: 以 Leonardo 為例 
IDE 燒錄程式時下 
的命令列參數 
燒錄過程中會被替換成正確參數
實際燒錄一次, 看看輸出訊息 
燒錄程式 
Avrdude config 檔 
Leonardo CPU 
COM port 
燒錄 baudrate 
要燒錄的檔案 
protocol
IDE 執行燒錄的機制 
執行 avrdude 燒錄命令 
取得 sketch binary 檔路徑 
Reset Arduino 
使用 serial bootloader 的板子, 例如: UNO … 
使用 usb bootloader 的 板子, 例如: Leonardo 
詳細流程請參考第 2 次 Arduino 原始碼讀書會內容 
設定正確的板子 燒錄參數 
BasicUploader.java 
是否需要 reset Arduino board 
Uploader.java 
是 
否 
等待 upload port 出現
燒錄工具程式 Avrdude 簡介 
普遍用來燒錄 Atmel AVR 的工具程式 
跨多種平台, Windows, FreeBSD, linux, UNIX … 
使用命令列來完成燒錄動作 
參考資料 
◦馬大的 Avrdude GUI 教學 
http://www.coopermaa2nd.blogspot.tw/2011_06_01_archive.html 
◦詳細的 avrdude 命令, 可見 AVR Tutorial: 
http://www.ladyada.net/learn/avr/avrdude.html 
◦Avrdude 原始碼 
https://github.com/arduino/avrdude
Avrdude 程式放在哪? 
Windows/Mac : hardwaretoolsavrbin
Avrdude 程式放在哪? 
Linux : hardwaretools
Arduino 燒錄機制原始碼重點講解
BasicUploader.java → Class BasicUploader → uploadUsingPreferences() 
取得目前 Serial USB port 
對 upload port 設定 1200 baud 再關閉 (soft-reset Arduino) 
如果設定要等待 upload port 出現 
如果設定 1200 baudrate reset → 執行 USB bootloader 燒錄流程 
取得 user 設定的 upload port 
等待 Arduino reset 完畢, 重新 取得 upload port (見下頁)
BasicUploader.java → Class BasicUploader → waitForUploadPort() 
Timeout 時間: 20 秒 
找出 Arduino reset 後, 重 新連線的 upload port 
如果找到 upload port 
如果沒有找到 upload port, delay 250ms 再重新尋找 
如果超過時限未找到新 upload port (win: 10 秒, 其他: 500ms), 且 user 選擇的 upload port 並未消失, 則回傳 user 選擇的 upload port 
將找到的 upload 
port 回傳
回到 BasicUploader.java → Class BasicUploader → uploadUsingPreferences() 
取得燒錄程式用的命令列pattern 
設定正確的命令列參數 
執行 avrdude 燒錄工具 程式(見下頁)
Uploader.java → Class Uploader→ executeUploadCommand () 
開新的 process 執行燒錄命令 
將編譯結果顯示到 IDE 訊息框內 
等待燒錄 process 執行完畢 
檢查燒錄是否燒 錄成功
回到 BasicUploader.java → Class BasicUploader → uploadUsingPreferences() 
如果設定要等待 upload port 出現 
檢查 upload port 是否出現, timeout = 2s 
如果找到 upload port 
將 upload port 設定 回 9600 baudrate
點心: 加入 86Duino 程式燒錄 對 IDE 所做的修改
加入 86Duino 板子的資料夾結構
建立 boards.txt
建立 platform.txt
修改 BasicUploader.java 
加入板子判斷 
根據 86Duino 修改燒錄參數
將燒錄工具程式放到 IDE 指定資料夾下 
燒錄工具程式必須依不同的平台而放在不同 的目錄(下頁說明) 
在 build IDE source code 的過程, 燒錄工具程 式會自動被移到 IDE 規定的執行時期位置 ( 詳見 build.xml 中的設定)
Case 1: Windows XP/7/8 
將 window 版的 86Duino 燒錄工 具壓縮至 avr_tool.zip 裡面
Case 2: Mac OS X 
將 MAC 版的 86Duino 燒錄工具 壓縮至 avr_tool.zip 裡面
Case 3: Linux 
將 Linux 版的 86Duino 燒錄工具 複製到此資料夾下
燒錄工具程式的一點開發經驗 
在 ubuntu 遇到的問題 
◦在 ubuntu 11.04 版本及之後的版本, 內建的 modem manager 會干擾 USB CDC 裝置的傳輸 
◦https://bugs.launchpad.net/ubuntu/+source/modemmanager/+bug/1153632/+activity 
◦這會造成燒錄程序被干擾而失敗 
◦解決方式: 將 USB CDC 裝置的 PID 和 VID 加入 modem manager 的忽略清單
燒錄工具程式的一點開發經驗 
在 Mac OS X 遇到的問題 
◦USB CDC 裝置的 Call Management Functional Descriptor 中的 最後一個 data 必須為 0x01, 否則 Mac 會認不到 USB CDC 裝 置 
◦http://stackoverflow.com/questions/5009593/acessing- a-serial-to-usb-device-with-i-o-kit
燒錄工具程式的一點開發經驗 
在 Mac OS X 遇到的問題 (cont.) 
◦USB CDC 裝置的 Configuration Descriptor 中不可 宣告 remote wakeup 功能, 否則會大大延長 Mac 辨 識此 USB CDC 裝置的時間
Arduino 原始碼讀書會(IV) : Arduino Standard Libraries 重點解析 (上)
Wire 函式庫
TWI 介面 
TWI 全名: Two Wire Interface 
Atmel 當初是為了避免侵犯 I2C 的註冊 商標, 特將此介面命名為 TWI 
在傳輸資料上仍為 I2C 協定
認識 I2C 介面 
它是由 Philips 公司在 1980 年時期,為 了方便同一個電路板上的各個組件互相 通信,而開發出來的一種介面 
全名: Inter-Integrated Circuit 
I2C 介面只用兩條訊號線來連接其他元 件: 
◦SDA (資料線) 
◦SCL (時脈線)
I2C 元件的連接方式 
圖片出處:http://en.wikipedia.org/wiki/I%C2%B2C 
Master 端:通 常是微處理器, 負責發送時脈和 slave 位址 
Slave 端:通常是感測器元 件 (或其他微處理器),每個 元件都有自己的位址 
Pull-up 電阻:由於 I2C 採 open-drain 設計,master 端若需要 送出 HIGH 信號,必須靠上拉電阻接 Vdd,讓信號線電位呈現 HIGH 狀態
詳細的 I2C 通訊協定 
I2C 的通訊協定較為複雜, 此次讀書會 不詳細說明, 有興趣的朋友可以參考下 面的連結內容: 
◦Wiki: http://en.wikipedia.org/wiki/I%C2%B2C
Arduino Leonardo 的 TWI 輸出腳位 
SCL 和 SDA 與第 2, 3 腳位共用
Arduino Uno 的 TWI 輸出腳位 
R3 版本後, 額外拉出 SDA 和 SCL 腳位 (與 A/D第 A4, A5 腳 位共用)
I2C 連接範例: 使兩塊 Arduino Uno 可以互相傳輸資料 
圖片出處:Arduino 互動設計入門 旗標出版
Wire 函式功能與使用範例
Wire.begin() 
函式功能: 
◦初始化 I2C 硬體 
◦把 Arduino 當 I2C master
Wire.begin(address) 
函式功能: 
◦初始化 I2C 硬體 
◦除了把 Arduino 當 master 之外, 也啟動 I2C slave 功能 
Slave 位址使用傳入的 address 參數 (注意必需為 7-bit 位址) 
當 Arduino 在 I2C Bus 上收到 address 時, 會進入 slave 模式
Wire.beginTransmission(address) 
函式功能: 
◦用來啟始 I2C master 的資料傳輸 
◦address 指定外部 I2C slave 裝置的位址 (7- bit) 
注意: Wire.beginTransmission() 的參數必須輸入 7-bit 形式的 slave address, 但市面上有些產品開發商只提供 8-bit slave address, 使用者必須自行轉換成正確的形式 例如: 廠商提供的 8-bit address 是 0x6A, 轉換成 7-bit 後, 值是 0x35, 然後將 0x35 填入 Wire.beginTransmission() 中
Wire.write(value) Wire.write(data, length) Wire.write(string) 
函式功能: 
◦當 Arduino 是 I2C master 時: 傳送資料給 slave 端 
資料會先寫入內部 master queue, 再由中斷副程 式傳送出去 
◦當 Arduino 是 I2C slave 時: 回應資料給 master 端 
資料會先寫入內部 slave queue, 再由中斷副程式 傳送出去
Wire.endTransmission() Wire.endTransmission(stop) 
函式功能: 
◦結束資料傳輸動作 
啟動中斷副程式, 把 master queue 中的資料傳送 出去 
◦若沒有 stop 參數, 則資料送完後發 I2C STOP 信號 
◦若 stop 參數為 true, 則資料送完後改發 I2C RESTART 信號
Wire.requestFrom(address, quantity) Wire.requestFrom(address, quantity, stop) 
函式功能: 
◦用來起始 I2C master 的資料讀取程序 
address 是要讀取的 I2C slave 裝置位址 
quantity 是要讀取的位元組個數 
◦將啟動中斷副程式讀取所需要的資料並存 放在內部的 rx queue 中 
使用者可調用 Wire.read() 取出 rx queue 中的值 
◦stop 參數功能與上頁相同
Wire.read() 
函式功能: 
◦從 rx queue 中取出一個 byte 
◦假如 rx queue 中沒有值, 會得到 -1
Wire.avairlable() 
函式功能: 
◦回傳 rx queue 中還未讀的 byte 數
Wire.onReceive(myHandler) 
函式功能: 
◦用來掛載 I2C slave 模式下的 callback function (myHandler) 
◦當 Arduino 在 I2C slave 模式下收到 master 端的資料後, 會調用此 callback function
使用範例: 透過 I2C 連接兩片 Arduino UNO 
連接方式:
Master 端 
Slave 端 使用範例: 透過 I2C 連接兩片 Arduino UNO 
Slave 端要設 定位址 
Master 端要 送出去的位址 
兩 者 要 一 樣
把程式個別燒入 UNO 後, 可以在 slave 端的 serial monitor 上看到 master 端傳過來的字串 使用範例: 透過 I2C 連接兩片 Arduino UNO 
圖片出處:Arduino 互動設計入門 旗標出版
Wire 函式庫原始碼解析
Wire 函式庫資料夾內容 
Wire 資料夾 
utility 資料夾 
Wire 函式庫的原始碼 
硬體相關的程式原始碼
Wire 函式庫實作架構 
Wire.cpp: 
◦實作對外的 API 介面 
◦透過 twi.c 傳送和接收資料 
twi.c: 
◦操縱 ATmega TWI (I2C)硬體 暫存器, 以中斷服務常式 (ISR) 處理傳送/接收資料的行為 
Wire lib 
TWI lib 
Arduino TWI hardware 
ISR 
queue
Wire 函式庫原始碼重要細節 
設定 Arduino I2C 裝置 的 slave 位址 
掛載 callback function 
初始化 Arduino I2C 硬體 
Wire.cpp:begin()
Wire 函式庫原始碼重要細節 
Wire.cpp:requestFrom() 
調用 twi.c 中的 function, 將取得的 值放到 rxbuffer 陣列中 
回傳讀到的總數
Wire 函式庫原始碼重要細節 
Wire.cpp:write() 
Wire.cpp:read() 
Master 模式 
Slave 模式 
把資料寫到 txbuffer 陣列 
從 rxbuffer 陣列中讀值
Wire 函式庫原始碼重要細節 
Wire.cpp:beginTransmission() 以及 endTransmission() 
此時才真正把 txbuffer 中的值寫出去 
賦予變 數初值 
預設為 master 模式
Wire 函式庫原始碼重要細節 
Wire.cpp:onReceiveService() 
掛載 callback function 
把中斷副程式中收到的陣 列內容拷貝到 Wire.cpp 中的 buffer 
重置 read() 會用到的變數 
調用 user 的 callback function
Wire 函式庫原始碼重要細節 
Wire.cpp:onRequestService() 
掛載 callback function 
調用 user 的 callback function
twi.c:twi_readForm() 
操作 I2C 暫存器, 開始從 I2C Bus 上讀值 
等待讀值過程結束 
把讀到的值存到 目標陣列 
初始化相關變數 
I2C 硬體仍忙碌時, 循環等待 
設置外部 slave 位址以及讀取命令
twi.c:twi_writeTo() 
操作 I2C 暫存器, 開始對 I2C Bus 上寫值 
等待寫值過程結束 
回傳寫值過程的結果 
初始化相關變數 
I2C 硬體仍忙碌時, 循環等待 
設置外部 slave 位址以及寫命令
twi.c:中斷副程式 
不同的 I2C 硬體狀態 (狀態暫存 器內的值) 
掛載中斷副程式 
中斷副程式主要運作方式: 
發生某種狀態, 就做對應的事情 
繼續送下一個 byte 
發生錯誤的處理方式 
送 stop condition 
送 restart condition
Wire 函式庫的移植: 以 86Duino 為例
Wire 在 86Duino 上的移植 
與硬體無關的 code: 
◦例如: Wire.cpp 
◦可以直接拿來用, 不用修改 (或者做些把 queue buffer 加大等小改進) 
與硬體相關 code: 
◦例如: twi.c 
◦根據硬體暫存器之間的規格差異, 移植難度也不同 
◦86Duino I2C 硬體暫存器設定與 ATmega TWI 頗為 相似, 因此移植時需要修改的地方並不多
86Duino twi.c:中斷副程式 
Master 完成 傳送位址、 資料的狀態 
取得 I2C 狀態 暫存器的值 
假如要從 I2C Bus 上讀值 
讀值的 
操作 
過程 
使 I2C 硬體開始 讀值 
送 stop condition 
等待讀值過程結束 
讀最後一筆
86Duino twi.c:中斷副程式 (續) 
把 1 byte 寫到 I2C BUS 上 
寫值的 
操作 
過程 
其它部分的移植方法都是相同概念: 
把硬體暫存器的存取改成 Vortex86EX 的版本 
送 stop condition 
送 restart condition 
假如是最後一筆
Servo 函式庫
RC Servo 簡介 
Radio Control Servo 
Servo 是一個整合馬達、減速機、控制 驅動的系統, 可根據外部命令, 控制馬達 轉到目標角度或速度
RC Servo 的應用領域 
在遙控模型(遙控車、 遙控飛機)上, 用來控制 遙控模型的姿態和移動 方向 
RC Servo 
目前也廣泛應用在機器 人領域, 做為機器人的 關節致動器
RC Servo 的組成 
圖片出處:Arduino 開發實戰指南 機械工業出版社 
基本功能: 接收主控器傳過來的目標位置信號, 與目前馬達位 置比較後, 以 PID 方式, 控制使馬達轉到目標位置 
用來測量馬達 的轉動角度 
用來放大直流馬達的扭力
常見的 RC Servo 控制信號 
主流為 PWM, 部分機器人專用伺服機則 採用 RS232 或 RS485 
Arduino 的 Servo 函式庫只以 PWM 命 令的 RC Servo 為控制對象 
生產公司 
RC Serco 的通訊方式 
Robotics(韓國) 
RS232、RS485 
KONDO (日本) 
PWM、RS232 
祥儀 (台灣) 
PWM 
廣營 (台灣) 
PWM 
TOWERPRO (大陸) 
PWM
PWM 信號(Pulse Width Modulation) 
全名為脈波寬度調變 
如下圖所示: 
Duty Cycle: 
在一個週期中, HIGH 電位的 時間所占的比 例 
Period: 即一個 PWM pulse 的週期
PWM 信號與 RC Servo 位置關係圖 
使用 PWM duty 的寬度來控制 servo 的轉動角度: 
duty 範圍通常介於 700us ~ 2300us 之間 
PWM 週期通常為 20ms 
圖片出處:Arduino 開發實戰指南 機械工業出版社
用 Arduino 連接 RC Servo 
電源線 
接地 
PWM 信號線 
PWM servo 連接線:
Servo.attach(pin) 
函式功能: 
◦指定要做為輸出 PWM 信號的 pin 編號
Servo.write(angle) 
函式功能 
◦輸出指定 duty 寬度的 PWM 信號 
◦參數 angle 
可以輸入 0 ~180, 代表轉動角度 
也可以輸入實際的 duty 時間值, 例如: 800, 1500 等數值, 單位是 us
Servo Lib 使用範例: 讓 RC Servo 來回轉動 
實際運行結果影片:
Servo 函式庫原始碼解析
Servo 函式庫實作 
實作概要: 
◦使用軟體設定 I/O pin HIGH/LOW 的方式模擬 PWM 信號 
◦HIGH/LOW 時間長短由 Timer 中斷所控制 
◦Arduino 1 個 Timer 最多控制 12 個 PWM channels 
◦超過 12 channels, 則需要用到更多 Timer (某些 Arduino 版子只能支援 12 channels) 
Servo 函式庫會與 analogWrite() 衝突, 通常不 能同時使用 
Servo Lib 
每個 channel 結構 
Timer 中斷副程式 
GPIO 輸出
多個 channels 的 PWM 輸出 
你可能以為是這樣: 
‧ ‧ ‧ 
Channel 1 
Channel 2 
Channel n 
20ms (PWM period)
實際上, Arduino 是這樣輸出的: 
多個 channels 的 PWM 輸出 
‧ ‧ ‧ 
20ms 
Channel 1 
Channel 2 
Channel 3
假設平均 duty 是 1500us (Servo 中點), 則有 20ms / (1500us+ISR overhead)  12 
如果所有 12 channels 都輸出最大 duty 2400us, 則 PWM period 會超過 12 x 2400us = 28.8ms 
◦若你使用的 RC Servo 不允許超過 20ms 的 PWM 週期, 則需注意 Servo 函式庫此特性
Servo Lib 的運作架構 
建構 Servo 物件 
設定 channel 
Timer 中斷副程式 
初始化 Timer 
Servo.attach() 
更新 channel 的 duty 值 
Servo.write() 
有下一個 channel? 
目前時間是 否超過 20ms? 
將此 channel 設 HIGH 並且設定下一次進入 中斷的時間 = duty 
設定下次進入中斷的 時間為 2us 後 
設定下一次進入中斷的 時間 = 20ms – 目前時間 
新的 20ms 周期開始? 
將原 channel 設 LOW 
否 
是 
否 
否 
是 
是 
宣告 Servo
Servo Lib 原始碼重要細節 
Servo.cpp 中的 attach() 函式 
若是第一次使用此 Timer 
初始化Timer 中斷 
取得 servo pin 對應的 timer 編號
Servo Lib 原始碼重要細節 
Servo.cpp 中的 write() 函式 
若輸入的值小於 544 
把值 map 到 544 ~ 2400 
調用 writeMicroseconds 
把值傳給中斷副程式 中會用到的變數 
把 us 轉成 Timer 單位
Servo Lib 原始碼重要細節 
將原 channel 輸出 LOW 
若是新的周期開始, 就重置 Time counter 
指向下一個 channel 
Servo.cpp 中的 Timer 中斷程式碼 
將此 channel 設 HIGH 
假如沒有可用的 channel 
設定 Timer = duty 
目前時間超過 20ms, 將下次中斷時間設成 2us 後 
若目前時間還小於 20ms, 將下次中斷時間設成 20ms
因為用軟體模擬 PWM, 所以實際輸出的 PWM duty 時間會有抖動現象 (jitter) 
當使用的 PWM channel 超過 12 組, Arduino 會啟用更多組 Timer, 多個 Timer 中斷彼此干擾, 有時會惡化 PWM jitter 現象
Servo 函式庫的移植: 以 86Duino 為例
Servo 函式庫在 86Duino 上的 實作改良 
用新的算法在 20ms 內模擬更多 PWM channels 
支援硬體 PWM 功能的 I/O pin, 直接以硬體功 能輸出 PWM 信號 
 以一個 Timer 中斷支持最多 45 個 PWM channels
接上 32 顆 RC Servo 的 Demo 
+ 
= 
32 channels 
RC Servo 
Demo 影片: 
86Duino ONE 
Arduino sensor shield 
18 channels 
14 channels 
https://www.youtube.com/watch?v=1H72d62AB08
86Duino Servo 函式庫的 PWM 輸出 
‧ ‧ ‧ 
20ms 
Channel 1 
Channel 2 
Channel 3 
Channel n
PWM 模擬算法概要 
排序所有 channels 的 duty 值 
根據 duty 大小的排序, 依序在對應的 I/O pin 上輸出 PWM 
同時在兩個 I/O pin 上輸出 PWM 波型 
使用 Vortex86EX event trigger 功能縮小由於 interrupt latency 造成的 PWM jitter
Servo.cpp 中的 attach() 函式 
初始化硬體 PWM pin 
初始化以軟體模擬的 PWM pin
Servo.cpp 中的 writeMicroseconds() 函式 
更新排序內容, 然後把結果複製到 A 排序陣列中 
若是第一次更新, 初始 化 B 排序陣列 
啟動 Timer
Servo.cpp 中的中斷副程式 
外部非正在更新排序 
排序方式有被更新過 
交換排序陣列 A, B 的 指標, 完成資料更新 
週期結束 
啟動下一個週期
Servo.cpp 中的中斷副程式(續) 
若是最後的 pin, 將它設定為 LOW, 結束 PWM 週期 
若是倒數第二 pin, 將自己設定為 LOW, 不啟動下一個 pin 
若都以上條件都不滿足, 就把目前 pin 設定為 LOW, 把下一個 pin 設定為 HIGH
PWM Duty 抖動現象 
由於在 Servo 函式庫裡 PWM 是用軟體模擬 的方式來實現, 所以實際輸出的 duty 會有抖 動現象 
因抖動造成的誤差範圍與 CPU 特性及軟體模 擬算法有關 
抖動現象
以 Arduino UNO 為例, 觀察 PWM 抖動情況 
+ 
示波器 
Arduino UNO 
波型抖動 
實況影片:
PWM 抖動現象的影響 
在命令解析度比較高的 RC Servo 上, 會造成 servo 輸出軸實際的抖動 
一般模型用的低價 RC Servo 解析度較低, 受 PWM 抖動現象的影響不大 
Arduino UNO 
+ 
KONDO 
KRS4014 servo 
Servo抖動 實況影片
在 Arduino 和 86Duino 上只使用 1 個 servo pin, 並量測輸出的 PWM duty 與目標值的誤 差, 所測得的數據如下表所示: 各板子的 PWM Duty 抖動實測 
板子 
目標 duty 
實際量測值 
duty 誤差範圍 
最小 
最大 
Arduino UNO 
1000 us 
1000.04 us 
1006.42 us 
約 6 ~ 7 us 
Arduino Leonardo 
1000 us 
1000.04 us 
1007.92 us 
約 7 ~ 8 us 
Arduino DUE 
1000 us 
998.200 us 
998.280 us 
約 1 ~ 2 us 
Arduino Mega2560 
1000 us 
1001.12 us 
1008.87 us 
約 8 ~ 9 us 
86Duino 
1000 us 
998.64 us 
1001.1 us 
約 1 ~ 2 us ** 
** 在 86Duino 有標註硬體 PWM 功能的 I/O pin 上, 誤差則是 0
在 Arduino DUE / Mega2560 和 86Duino 上啟 用 45 組 servo pins, 並量測其中一個 pin 輸出 的 PWM duty 與目標值的誤差, 所測得的數據 如下表所示: 
各板子的 PWM Duty 抖動實測 
板子 
目標 duty 
實際量測值 
duty 誤差範圍 
最小 
最大 
Arduino DUE 
1000 us 
998.05 us 
1004.68 us 
約 2 ~ 5 us 
Arduino Mega2560 
1000 us 
1001.09 us 
1076.96 us 
約 1 ~ 77 us 
86Duino 
1000 us 
998.70 us 
1001.31 us 
約 1 ~ 2 us 
Arduino 的 Servo 函式庫在超過 12 組 channels 時, 會啟用 2 組以上 Timer 中斷, 以上表格可以看出多組 Timer 中斷互相影響所造成的 jitter 惡化情形
FIRMATA
Command 
Message
Firmata 
Examples 
◦Simple Analog Firmata 
◦Servo Firmata 
Firmata.h 
Firmata.cpp 
Boards.h
Firmata 
•Examples 
–Simple Analog Firmata 
–Servo Firmata 
•Firmata.h 
•Firmata.cpp 
•Boards.h
Firmata.attach(); //掛載要執行的函式 
Firmata.processInput(); //接收並執行來自HOST的指令
Firmata 
•Examples 
–Simple Analog Firmata 
–Servo Firmata 
•Firmata.h 
•Firmata.cpp 
•Boards.h
Arduino 底層原始碼解析心得
Firmata 
•Examples 
–Simple Analog Firmata 
–Servo Firmata 
•Firmata.h 
•Firmata.cpp 
•Boards.h
#include “Boards.h” //依照不同晶片,套用不同的腳位定義
Arduino 底層原始碼解析心得
Arduino 底層原始碼解析心得
Arduino 底層原始碼解析心得
Firmata 
•Examples 
–Simple Analog Firmata 
–Servo Firmata 
•Firmata.h 
•Firmata.cpp 
•Boards.h
Arduino 底層原始碼解析心得
Firmata.begin(); //即為Serial.begin()
Firmata.available(); // 即為Serial.available()
將一包訊息接收完成後,依照不同的command做不同的處理
利用function pointer來執行先前attach的function
switch依照不同的command來做不同的設定
回傳至HOST的訊息也用相同的格式
Arduino 底層原始碼解析心得
Arduino 底層原始碼解析心得
Firmata 
•Examples 
–Simple Analog Firmata 
–Servo Firmata 
•Firmata.h 
•Firmata.cpp 
•Boards.h
不同的晶片有不同的腳位定義,利用Boards.h來設定
readPort();
writePort();
Arduino 底層原始碼解析心得
Firmata @ 86Duino
Firmata @ 86Duino 
•Examples 
–Simple Analog Firmata 
–Servo Firmata 
•Firmata.h 
•Firmata.cpp 
•Boards.h
Arduino 底層原始碼解析心得
SD CARD
SD卡的傳輸模式 
SPI 
◦Chip Select, Clock, MISO, MOSI 
1-bit SD data transfer mode 
◦Command, Clock, DATA0 
4-bit SD data transfer mode 
◦Command, Clock, DATA0, DATA1, DATA2, DATA3
FAT檔案系統
SD 
./Examples 
◦Files.ino 
◦Datalogger.ino 
./utility →檔案系統 
SD.h 
SD.cpp →開關存取SD卡 
File.cpp →開關存取檔案
SD 
•./Examples 
–Files.ino 
–Datalogger.ino 
•./utility 
•SD.h 
•SD.cpp 
•File.cpp
#include <SPI.h> // Arduino透過SPI介面連接SD卡 
File myFile; //建立一個自己的File物件 
SD.begin(); //開啟SD卡
SD.open(“example.txt”, FILE_READ); //從頭開始讀 
SD.open(“example.txt”, FILE_WRITE); //從尾繼續寫
Arduino 底層原始碼解析心得
SD 
•./Examples 
–Files.ino 
–Datalogger.ino 
•./utility 
•SD.h 
•SD.cpp 
•File.cpp
Arduino 底層原始碼解析心得
Arduino 底層原始碼解析心得
dataFile.println(dataString); //將字串寫入檔案 dataFile.close(); //儲存並關閉檔案
SD 
•./Examples 
–Files.ino 
–Datalogger.ino 
•./utility 
•SD.h 
•SD.cpp 
•File.cpp
SdFile.cpp 
SdVolume.cpp 
FAT檔案系統 
Sd2Card.cpp 
SD卡讀/寫指令、寫入資料 
SPI.cpp 
透過SPI模式對SD卡存取
SD 
•./Examples 
–Files.ino 
–Datalogger.ino 
•./utility 
•SD.h 
•SD.cpp 
•File.cpp
Arduino 底層原始碼解析心得
Arduino 底層原始碼解析心得
Arduino 底層原始碼解析心得
Arduino 底層原始碼解析心得
SD @ 86Duino
SD @ 86Duino 
86Duino透過作業系統運作,SD卡為系統磁 碟 
86Duino的作業系統內就有FAT檔案系統 
86Duino利用stdio.h內的FILE structure來存取 檔案 
86Duino使用4-bit模式與SD卡連接
SD @ 86Duino 
•File.cpp 
•SD.h 
•SD.cpp
fwrite 寫入檔案
fgetpos 取得目前在檔案內的位置 fread 從檔案讀出
fflush 寫入檔案
fseek 移至檔案的某個特定位置 ftell 取得目前在檔案內的位置 fclose 關閉檔案
Arduino 底層原始碼解析心得
fopen 開啟檔案 (r,w,a為開啟模式)
EEPROM Library
EEPROM 簡介 
EEPROM, 或寫作E2PROM, 全稱電子 抹除式可複寫唯讀記憶體, 是一種可以 通過電子方式多次複寫的半導體存儲設 備 
Arduino EEPROM 大小: 
◦ATmega328 : 1024 Byte 
◦ATmega168, ATmega8 : 512 Byte 
◦ATmega1280, ATmega2560 : 4K Byte
EEPROM 函式 
EEPROM.read(address) 
◦從 address (位址)讀取值出來 
 EEPROM.write(addr, val) 
◦將 val (數值)寫到 addr (位址)
EEPROM 函式庫範例 
從EEPROM讀 值 
寫值到EEPROM
EEPROM 函式庫原始碼解析
EEPROM 函式庫原始碼重要細節 
呼叫 AVR EEPROM 函式庫從 EEPROM 讀值 
引用 Atmel 官方提供的 AVR EEPROM 函式庫 
呼叫 AVR EEPROM 函式庫寫值到EEPROM 
EEPROM 是 Arduino 標準函式庫裡實作最簡單的一個  但不代表容易移植
EEPROM 函式庫的移植: 以 86Duino 為例
叫我移植這麼簡單的 EEPROM Lib ??? 
我覺得我被輕視了… 
苦主 RD
什麼! 86Duino 沒有 EEPROM! 
這麼爛的板子是誰做的啊! 
苦主 RD
開個檔案模擬 EEPROM 讀寫, 
十分鐘搞定, 嘿嘿... 
苦主 RD 
這樣是嚇不倒 我滴!
結果在測試了 EEPROM 的 官方範例之後…86Duino 就葛屁了(DOS 檔案系統損 毀) Orz
以檔案模擬 EEPROM 的問題 
若 86Duino 在寫入檔案時, 被斷電或重 置… 
◦輕則檔案資料遺失 
◦重則整個檔案系統損毀 
需要設計一個不 怕斷電與重置的 演算法… 
苦主 RD 
嗚嗚, 只好 
重寫了~~
86Duino 兩種實現 EEPROM 等價功能的 方法 
方法一: 利用板上 CMOS 記憶體 
◦優點: 速度快, 程式簡單, 讀寫時不怕 CPU 斷 電 
◦缺點: 容量只有 200 bytes, 移除 86Duino 板 上 RTC 電池會使資料遺失 
方法二: 利用 BIOS flash 的剩餘空間 
◦優點: 容量可達 16 KB, 不需電池仍可保存資 料 
◦缺點: 速度較慢, 需設計容錯算法避免讀寫 時斷電的資料損毀  實作較複雜
CMOS bank 方法的實作
CMOS 方法原始碼重要細節 
切換 CMOS 分頁(分為兩頁各 128 bytes) 
設定要讀取的 CMOS 位址 
從 CMOS 讀值
CMOS 方法原始碼重要細節 
切換 CMOS 分頁(分為兩頁各 128 bytes) 
設定要寫入的 CMOS 位址 
寫值到CMOS
Flash bank 方法的實作
算法原理
算法原理
EEPROM 
初始化 
初始化物件 SPI Flash / DRAM 
SPI Flash (c) 
清除 SPI Flash (c) 
選擇 
SPI Flash (a/b) 
將 Flash 資料讀 取到 DRAM 
結束 
滿 
未滿
EEPROM 
write 
SPI Flash(a /b) 
清除 SPI Flash (a/b) 
將 DRAM 內容寫回 SPI Flash (a/b) (1k) 
SPI Flash (c) 
清除 SPI Flash (c) 
填 1-bit 0 到 
SPI Flash (c) 
更改 SPI Flash (a/b) 開始寫資料的位置 
寫值到 DRAM 
寫值到 SPI Flash(a/b) 
結束 
滿 
滿 
未滿 
未滿
Arduino 底層原始碼解析心得
Flash 方法原始碼重要細節 
宣告 SPI Flash ( a ) 
宣告 SPI Flash ( b ) 
宣告 SPI Flash ( c ) 
宣告 DRAM 4k 
判斷 SPI Flash ( c ) 是否 滿了 
判斷目前使用 
SPI Flash (a/b) 
選擇目前使用 
SPI Flash (a/b) 
將SPI Flash 填到DRAM 
計算DRAM 正確的值
Flash 方法原始碼重要細節 
判斷SPI Flash ( a / b ) 是否滿 了 
Reset SPI Flash ( a / b ) 
將數值寫回SPI Flash ( a / b ) 
前面 1k 部分 
寫 0 到 SPI Flash ( c ) 
寫入位置回到初始狀態
Flash 方法原始碼重要細節 
填值到 DRAM 
決定填值到哪一組 SPI Flash ( a / b ) 
填值到SPI Flash ( a / b )
Flash 方法原始碼重要細節 
從DRAM 讀值
EEPROM 讀取性能測試 
板子 
平均讀取時間 
Arduino Leonardo 實體 EEPROM 
1 us 
86Duino (CMOS bank) 
2 us 
86Duino (Flash bank) 
< 0.1us 
測試程式: 
連續讀取200 次, 
計算平均讀取時間
EEPROM 寫入性能測試 
板子 
平均寫入時間 
Arduino Leonardo 實體 EEPROM 
3395 us 
86Duino (CMOS bank) 
3 us 
86Duino (Flash bank) 
125 us (沒有跨 1K 邊界時的情況) 
510 us (跨 1K 邊界時的情況) 
測試程式: 
連續寫入200 次, 
計算平均寫入時間
Arduino 原始碼讀書會(V) : Arduino Standard Libraries 重點解析 (下) 
DMP Electronics Inc. (瞻營全電子) 
robotics@dmp.com.tw
SPI 函式庫
SPI 
全名: Serial Peripheral Interface 
許多電子裝置都有用到它,例如: 
◦SD 記憶卡 
◦數位/類比轉換 IC (例如 AD7928) 
◦LED 控制晶片 (例如 MAX7219) 
◦還有很多 這裡無法一一列出…
SPI 介面 
SPI 採用四條線連接主機和周邊設備, 這四條 線的名稱和用途如下: 
◦SS:周邊選擇線(Slave Select),指定要連接哪一個 周邊設備。這條線也稱為 CS (Chip Select 晶片選 擇線) 
圖片出處:超圖解 Arduino 互動設計入門第一版 旗標出版
SPI 介面 (續) 
◦MOSI:從主機(master)送往周邊(slave)的資料線, (Master Output Slave Input) 
◦MISO:從周邊(slave)送往主機(master)的資料線, (Master Input Slave Output) 
◦SCK:序列時脈線 
圖片出處:超圖解 Arduino 互動設計入門第一版 旗標出版
Arduno UNO 上的 SPI 腳位 
有用 UNO 燒錄過 Arduino bootloader 的人,對 SPI 腳位應該 不陌生。如下圖所示: 
圖片出處:超圖解 Arduino 互動設計入門第一版 旗標出版
UNO 上的 SPI 腳位 (電路圖) 
圖片出處:Arduino UNO 官方電路圖 
Reset 
有 4 支腳 
有 3 支腳
Arduno Leonardo 上的 SPI 腳位 
圖片出處:超圖解 Arduino 互動設計入門第一版 旗標出版 
SS pin 為什麼在這裡!? 
(看下頁)
Leonardo 上的 SPI 腳位 (電路圖) 
圖片出處:Arduino Leonardo 官方電路圖 
SS 與 RXLED 是 共用腳位
電路圖中搜尋 RXLED 關鍵字 
心中 OS:或許選一支 GPIO 來當 SS 會比較方便 
直接與 LED 相連 
一路上都是 SS
SPI 的通訊格式 
SPI 是一種同步全雙工的序列埠,主機和周邊之間的 資料傳遞,都要跟著時脈的 High、Low 一同進行 
SPI 介面沒有強制規範時脈訊號的標準,大部分是由 SPI 介面晶片來決定使用哪一種時脈訊號格式 
一般來說,SPI 可以由 CPOL 和 CPHA 來組成四種不 同的格式: 
◦CPOL:時脈極性,時脈信號的電位基準 
圖片出處:超圖解 Arduino 互動設計入門第一版 旗標出版
SPI 的通訊格式 (續) 
◦CPHA:時脈相位,資料在時脈的上升階段或者下降階段被讀 取/送出 
圖片出處:http://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus 
兩個模式的 共同之處: 
資料在時脈 上升或下降 階段,同時 收或送資料 
SS 要先設為 Low 來啟用裝置 
接收與發送 1 個 byte 的過程
SPI 的通訊格式 (續) 
CPOL 和 CPHA 配合後,四種組合如下: 
與裝置通訊前的確認事項 
◦資料傳遞的格式 
◦訊號傳遞位元順序 (bit order):分成高位元先傳 (MSBFRIST) 和低位元先傳 (LSBFIRST) 兩種 
◦裝置所能接收的最高時脈頻率 
圖片出處:超圖解 Arduino 互動設計入門第一版 旗標出版 
Arduino 函 式庫中的 命名
SPI 函式功能與使用範例
SPI.begin() 
函式功能: 
◦初始化 SPI 硬體 
設定為 Master 端 
預設資料格式是 CPOL = 0,CPHA = 0 
預設傳輸速度是 4MBps 
預設傳遞位元順序是高位元先傳 (MSBFIRST)
SPI.end() 
函式功能: 
◦關閉 SPI 硬體功能
SPI. setBitOrder() 
函式功能: 
◦設定傳遞位元順序,可輸入兩種參數: 
MSBFIRST 
LSBFIRST
SPI. setDataMode() 
函式功能: 
◦設定資料格式,可輸入四種參數: 
SPI_MODE0 
SPI_MODE1 
SPI_MODE2 
SPI_MODE3
SPI. setClockDivider() 
函式功能: 
◦設定傳輸速度,可輸入七種參數: 
SPI_CLOCK_DIV2 :8MBps 
SPI_CLOCK_DIV4 :4MBps 
SPI_CLOCK_DIV8 :2MBps 
SPI_CLOCK_DIV16 :1MBps 
SPI_CLOCK_DIV32 :500KBps 
SPI_CLOCK_DIV64 :250KBps 
SPI_CLOCK_DIV128 :125KBps
SPI. transfer() 
函式功能: 
◦傳送並同時接收資料
SPI 使用範例 
傳送/接收資料 
Int data; void setup() { SPI.begin(); } void loop() { digitalWrite(SS, LOW); // 把 SS 設定為 LOW,開始傳送資料 SPI.transfer(0x01); // 送 0x01 給 slave data = SPI.transfer(0x00); // 讀取 slave 回傳的值 digitalWrite(SS, HIGH); // 把 SS 設定為 HIGH,結束資料傳送 Serial.println(data); delay(10); } 
這裡傳送的資料是隨便給的 實際要看 slave 晶片而定
SPI Library 常常被引用 
它們都是 SPI 介面: 
◦Ethernet Library 
◦TFT Library 
◦SD Library 
◦Wifi Library 
◦SpiderL3S Library 
Arduino Ethernet shield 
Arduino TFT 
SD shield 
Arduino Wifi shield 
SpiderL3S (CC3000 Wifi module)
SPI 函式庫原始碼解析
SPI 函式庫資料夾內容 
https://github.com/arduino/Arduino/tree/master/libraries/SPI
SPI 函式庫原始碼重要細節 
SPI.cpp:begin() 
將 SS pin 設定為 output HIGH 確保等一下 enable SPI 後會是 Master 狀態 
將 SPI 設定為 Master 然後 enable 
SPI enable 後,SCK 和 MOSI pin 的方向需自行定義
SPI 函式庫原始碼重要細節 
SPI.cpp:end() 
SPI.cpp:setBitOrder() 
LSBFIRST 
MSBFIRST
SPI 函式庫原始碼重要細節 
SPI.cpp: setDataMode() 
SPI.cpp: setClockDivider() 
設定 divider 暫存器
SPI 函式庫原始碼重要細節 
SPI.h: transfer() 
資料送完的時候,SPIF 會設 1 
(設 1 後第一次對它讀取會清 0) 
將要送的資料填入 SPDR 暫存器 
回傳收到的值
SPI 函式庫的移植: 以 86Duino 為例
SPI 在 86Duino 上的移植 
移植重點: 
◦將填 ATmega CPU 內的 SPI 暫存器的行為,改成填 86Duino CPU 內的 SPI 暫存器 
◦其它與硬體無關的程式碼幾乎無需改動,可直接 延用
86Duino spi.cpp:begin() 
在 86Duino 中,SPI 是一個 PCI 裝置, 所以需要先取得 I/O address 
設定 SPI 為全雙工 
預設速度為 4MHz 
預設傳輸格式為 SPI_MODE0 
開啟 FIFO 功能 
將 SS (實際上是 SPICS) 設定為 HIGH
86Duino spi.cpp:end() 
86Duino spi.cpp:setBitOrder() 
設定為 LSBFIRST 
設定為 MSBFIRST
86Duino spi.cpp:setDataMode() 
86Duino spi.cpp:setClockDivider() 
限制值的範圍在 1 ~ 4095,因 為 divider register 只有 12 bit 
設定 SPI 傳輸模式
86Duino spi.cpp:transfer() 
檢查 Output FIFO 是否為空 
檢查 Input FIFO 是否為空 
回傳收到的值 
否 
是 
是 
否 
送出值
不同 Arduino 板子的 SPI 速度差異 
在 Arduino UNO 上,SPI 速度只有固定那七 種 
在 Arduino Due 及 86Duino 上,可允許更快 的 SPI 速度 
◦在新版的 Arduino IDE 1.5.x 新增了beginTransaction() 來使用更快的 SPI 速度 
但目前 Arduino 網站尚未提供關於此函式的使用文件~冏rz 
◦另一種使用更快 SPI 速度的方式是直接對 setClockDivider() 輸入對應的 divider 數值 (而不是 像 SPI_CLOCK_DIV2 這樣的常數) 
但使用此法需要先知道不同 Arduino 板子上 SPI 速度的計 算方式
86Duino SPI clock 的計算方式 
在 86Duino 上,計算 SPI 速度的公式如下: 
當 div 設成 1 時,86Duino 最快可輸出的 SPI clock 速度:50MHz 
100MHz / (2  div) 
div 是 divider 值,範圍:1 ~ 4095
Ethernet 函式庫
Arduino Ethernet shield 簡介 
操作電壓:5V 
控制晶片:W5100 
速度:10/100 Mbps 
通訊介面:SPI 
WIZnet W5100 datasheet: http://www.wiznet.co.kr/UpLoad_Files/ReferenceFiles/W5100_Datasheet_v1.2.2.pdf 
Ethernet shield 外觀 
WIZnet W5100
Arduino Ethernet shield 電路 
對 Arduino 的通 訊介面:SPI 
輸出:LAN 的 差動信號 
圖片出處:http://arduino.cc/en/uploads/Main/arduino-ethernet-shield-06-schematic.pdf
Arduino Ethernet shield 工作原理 
OSI 模型: http://linux.vbird.org/linux_server/0110network_basic.php#route_route 
將每個 frame 轉換為 0、1 信號 
網路接頭 
使用 IEEE 802.3 封包協議 來傳送 MAC 
支援的通訊協定 
軟體處理部分 
硬體處理部分
Ethernet 使用範例:ChatServer 
把 Arduino 當作 WebServer,等待 client 連線 
設定網路卡實 體位址、IP位 址、子網路遮 罩和閘道器位 址 
設定伺服器的 port 為 23,預 設使用 Telnet 服務 
啟動乙太網路連線 
啟動伺服器
ChatServer:loop() 
聆聽用戶的連線請求 
如果收到用戶的連線 請求 
第一個用戶連線,送出 Hello 字串 
檢查用戶是否有送字 元過來,如果有,則 返回相同的字元給所 有已連結上的用戶
ChatServer 執行結果 
PC:putty.exe 
86Duino :Serial Monitor 
Server 端 
Client 端
Ethernet Library 原始碼概觀
由於 Ethernet Library 相當龐大,這裡 不深入討論上面每個 .cpp 裡的函式細 節 
只討論和移植有關的大架構
Ethernet 資料夾 
從 DHCP 伺服器取得動態 IP 
從 DNS 伺服器將網址轉換成實際位址 
Ethernet 初始化函式 
建立 client 端,以 TCP/IP 方式連線 
建立 server 端,以 TCP/IP 方式連線 
以 UDP 方式連線 
https://github.com/arduino/Arduino/tree/master/libraries/Ethernet
Ethernet / utility 資料夾 
https://github.com/arduino/Arduino/tree/master/libraries/Ethernet/utility 
透過 SPI 介面將命令送給 W5100 晶片 
Arduino 提供的底層 API (部分遵循 BSD Socket 標準,但沒有完全相容)
Arduino Ethernet Library 的架構 
Socket 
W5100 命令 
Arduino Ethernet Shield 
Server 
Client 
UDP 
Ethernet 
SPI Bus 
初始化函式 
呼叫 
取得/設定 IP、子網 路遮罩、閘道器位 址等等
Ethernet Library 在 86Duino 上的移植
86Duino 內建的 Ethernet 電路 
網路卡內建在 CPU 中 (含 PHY) 
Vortex86EX 
CPU LAN 
差動信號輸出 
Transformer 
86Duino 底板 
(PCI 裝置) 
網路接頭
DOS 下的網路驅動程式 
內建在 86Duino 韌體裡的 NDIS driver 
NDIS: Network Driver Interface Specification, 參考資料: 
◦http://en.wikipedia.org/wiki/Network_Driver_Interface_Specification
DOS 下的 Socket Library 
BSD Socket 規範: http://web.mit.edu/macdev/Development/MITSupportLib/SocketsLib/Documentation/sockets.html 
DOS 下常用的 Socket Library: 
◦Watt32: http://www.watt-32.net/ 
◦SwsSock (86Duino 使用的 Socket Library): http://www.softsystem.co.uk/products/swssock.htm 
◦…
Ethernet Library 移植方式 
Socket 
W5100 命令 
Ethernet Shield 
Server 
Client 
UDP 
Ethernet 
沿用大部分 Arduino 的 API 名稱,但內容 全部用標準 Socket API (SwsSock library 提供) 來實作 
虛擬層 (NDIS to Package) 
NDIS driver 
86Duino LAN 
Arduino Ethernet Library 
86Duino Ethernet Library 
移植 
替換
移植後的差異: 以 Ethernet Server:begin() 為例 
86Duino 
Arduino 
呼叫 Socket API
WiFi 函式庫
WiFi shield 簡介 
工作電壓:3.3V 
控制晶片:AT32UC3A1256 
無線模組:HDG104 
無線網路通訊標準:802.11/g 
資料加密方式:WEP 或 WPA2 
與 Arduino 的通訊介面:SPI 
WiFi shield 外觀 
AT32UC3A1256 datasheet: 
http://www.gaw.ru/pdf/Atmel/AVR_32/AT32UC3A0512_0256_0128_1512_1256_1128s.pdf 
HDG104 datasheet: 
http://datasheet.octopart.com/HDG104-DN-3-H%26D-Wireless-datasheet-11793609.pdf 
AT32UC3A1256 
HDG104
Arduino WiFi shield 電路 
圖片出處:http://arduino.cc/en/uploads/Main/arduino-wifi-shield-schematic.pdf 
AT32UC3A1256 
電壓準位從 5V 轉成 3.3V 
對 Arduino 的通訊介 面:SPI 
透過內部 第二組 SPI Bus 和無線模 組通訊 
無線模組 
HDG104
WiFi 使用範例:WifiCharSever 
輸入你的 SSID 
輸入 WEP/WAP2 形式的密碼 
檢查 WiFi shield 是否存在
WifiCharSever:setup() 
begin() 會不斷嘗試連線 
假如尚未連線成功 
連線成功後,啟動伺服器 
印出目前的 SSID,取得 的 IP,以及訊號強度
WifiCharSever:loop() 
聆聽用戶的連線請求 
如果收到用戶的連線 請求 
第一個用戶連線,送出 Hello 字串 
檢查用戶是否有送字 元過來,如果有,則 返回相同的字元給所 有已連結上的用戶
WifiChatServer 執行結果 
PC:putty.exe 
86Duino :Serial Monitor 
Server 端 
Client 端
WiFi 原始碼概觀 
功能皆類似 Ethernet Library 
https://github.com/arduino/Arduino/tree/master/libraries/WiFi 
Ethernet
WiFi 原始碼概觀 
https://github.com/arduino/Arduino/tree/master/libraries/WiFi/utility 
Ethernet/utility 
底層的 SPI driver 
底層的 SPI driver 
Socket Interface 
Socket Interface
WiFi Library 在 86Duino 上的移植 
移植重點:WiFi Library 與硬體相關的 只有 SPI 的部分,其它部分程式碼與硬 體無關,可以在 86Duino 上直接延用 
◦將 spi_drv.cpp 存取方式換成 86Duino SPI 的 存取方式 
◦上層的 wifi_drv、server_drv、WIFIClient 等等都不用動
移植後的 spi_drv.cpp 差異 
86Duino 
Arduino 
替換 
替換
GSM 函式庫
GSM 簡介 
GSM 全名 Global System for Mobile Communications (全球行動通訊系統) 
在台灣,GSM 的頻段是 900、1800MHz,由 於在同一頻段內要讓多人使用又要抗干擾, 所以實際上傳送數據的速度只達到 9.6Kbps( 相當於看一個 200KB 的網頁要需要等 20 幾 秒)
GPRS 簡介 
GPRS 全名 General Packet Radio Service,在 現有 GSM 技術上,加上數據交換節點(具有 處理封包的能力),配合動態分配頻段來增 加使用率,在連線人數不多的情況下,速度 可達 56Kbps ~ 100多Kbps,用來看網頁和圖 片,已經綽綽有餘。
Arduino GSM shield 簡介 
使用 M10 晶片: 有 GSM + GPRS 功能 
支援 4 種頻段: GSM850MHz GSM900MHz DCS1800MHz DCS1900MHz 
支援 TCP/UDP 和 HTTP 網路通訊協定 上傳和下載的速度 最高可達 85.6Kbps 
Arduino 透過 AT command 控制 GSM shield 
GSM shield 外觀 
圖片出處: http://arduino.cc/en/Main/ArduinoGSMShield
Arduino GSM shield 電路 
使用 PIN2 和 PIN3 做為 Serial 腳位 
增加訊號的 驅動能力 
M10 
圖片出處:http://arduino.cc/en/uploads/Main/arduino-gsm-shield-schematic.pdf
使用 GSM shield 前應注意的事項 
GSM Library 中預設使用 software serial 來傳送 AT command: 
◦M10 晶片支援的 AT command: http://arduino.cc/en/uploads/Main/Quectel_M10_AT_commands. pdf 
◦GSM shield 使用 PIN2 和 PIN3 做為預設的 software serial 輸 出腳位,不使用 hardware serial (PIN0 和 PIN 1) 來傳輸資料, 因為這會與 Arduino 燒錄程式的腳位衝突。 
GSM shield 在使用 modem 傳送資料的時候用電量稍 大,建議接上外部電源 (700mA ~ 1A),而不要只使 用 USB 供電。 
需要一張 SIM 卡才能撥打電話、發簡訊以及上網( 必須先向電信業者開通上網功能)
使用 GSM shield 前應注意的事項(續) 
在 Atmega 2560 上,GSM shield 需要額外的跳線: 
第一步:把 PIN2 的腳往外扳 
第二步:將 PIN2 與 PIN10 相連 
第三步:插上 GSM shield 
這是因為具有 toggle trigger 的中斷腳位,在 UNO 上是 PIN2 ,在 2560 上是 PIN10 的緣故。(在 Leonardo 上則要換成 PIN8) 
圖片出處: http://arduino.cc/en/Main/ArduinoGSMShield
用 Arduino + GSM shield 打電話和接電話
準備 
首先,拿一張可用的 SIM 卡,插入 GSM shield 
圖片出處: http://arduino.cc/en/Guide/ArduinoGSMShield#toc4 
用的是 mini SIM 卡,手機 用的是 micro SIM 卡,需要 使用轉卡才不 會掉出來
MakeVoiceCall 範例程式 
使用者可透過 Serial monitor 輸入電話 號碼來撥打給對方 
#include <GSM.h> 
#define PINNUMBER “" 
GSM gsmAccess; 
GSMVoiceCall vcs; 
String remoteNumber = “"; 
char charbuffer[20]; 
void setup() 
{ 
Serial.begin(9600); 
while (!Serial) { 
; // wait for serial port to connect. Needed for Leonardo only 
} 
如果已經在手機上已取消 PIN 碼,這 裡就不用輸入 PIN 碼 
初始化 GSMAccessProvider class 
初始化 GSMVoiceProvider class
MakeVoiceCall:setup() 
… // Start GSM shield // If your SIM has PIN, pass it as a parameter of begin() in quotes while(notConnected) { if(gsmAccess.begin(PINNUMBER)==GSM_READY) notConnected = false; else { Serial.println("Not connected"); delay(1000); } } Serial.println("GSM initialized."); Serial.println("Enter phone number to call."); … 
begin() 完成基本的初始化 
回傳結果都沒問題,就可 以開始打電話了
上傳 MakeVoiceCall 之後… 
3. 撥出電話 
4. 對方接通,開始通話 
5. 對方掛斷電話,結束通話 
1.打開 serial monitor 
2.輸入要撥打的電話 (前面需要加上台灣區碼:+886),輸 入完後按 Send
用 GSM shield 接電話 
ReceiveVoiceCall 範例程式 (內容與 MakeVoiceCall 類似,所以 略過) 
上傳後打開 serial monitor: 
接到一通電話,並顯示電話號碼 
雙方通話中 
初始化完成,等待別人撥電話進來 
Send ‘n’ 後結束通話
GSM Library 原始碼概觀
GSM Library 
到 Arduino 的 GitHub 網站,看看 GSM 資料 夾內的檔案: 
◦https://github.com/arduino/Arduino/blob/master/libraries/GSM
Arduino 底層原始碼解析心得
Arduino 底層原始碼解析心得
Arduino 底層原始碼解析心得
Arduino 底層原始碼解析心得
Arduino 底層原始碼解析心得
Arduino 底層原始碼解析心得
Arduino 底層原始碼解析心得
Arduino 底層原始碼解析心得
Arduino 底層原始碼解析心得
Arduino 底層原始碼解析心得
Arduino 底層原始碼解析心得
Arduino 底層原始碼解析心得
Arduino 底層原始碼解析心得
Arduino 底層原始碼解析心得
Arduino 底層原始碼解析心得
Arduino 底層原始碼解析心得
Arduino 底層原始碼解析心得
Arduino 底層原始碼解析心得
Arduino 底層原始碼解析心得
Arduino 底層原始碼解析心得
Arduino 底層原始碼解析心得
Arduino 底層原始碼解析心得
Arduino 底層原始碼解析心得
Arduino 底層原始碼解析心得
Arduino 底層原始碼解析心得
Arduino 底層原始碼解析心得
Arduino 底層原始碼解析心得
Arduino 底層原始碼解析心得
Arduino 底層原始碼解析心得
Arduino 底層原始碼解析心得
Arduino 底層原始碼解析心得
Arduino 底層原始碼解析心得
Arduino 底層原始碼解析心得
Arduino 底層原始碼解析心得
Arduino 底層原始碼解析心得
Arduino 底層原始碼解析心得
Arduino 底層原始碼解析心得
Arduino 底層原始碼解析心得
Arduino 底層原始碼解析心得
Arduino 底層原始碼解析心得
Arduino 底層原始碼解析心得
Arduino 底層原始碼解析心得
Arduino 底層原始碼解析心得
Arduino 底層原始碼解析心得
Arduino 底層原始碼解析心得

More Related Content

What's hot

[嵌入式系統] 嵌入式系統進階
[嵌入式系統] 嵌入式系統進階[嵌入式系統] 嵌入式系統進階
[嵌入式系統] 嵌入式系統進階Simen Li
 
深入淺出C語言
深入淺出C語言深入淺出C語言
深入淺出C語言Simen Li
 
Arduino + rcs620sで遊ぼう
Arduino + rcs620sで遊ぼうArduino + rcs620sで遊ぼう
Arduino + rcs620sで遊ぼうtreby
 
Arduino應用系統設計 - Arduino程式快速入門
Arduino應用系統設計 - Arduino程式快速入門Arduino應用系統設計 - Arduino程式快速入門
Arduino應用系統設計 - Arduino程式快速入門吳錫修 (ShyiShiou Wu)
 
HC 05藍芽模組連線
HC 05藍芽模組連線HC 05藍芽模組連線
HC 05藍芽模組連線Chen-Hung Hu
 
系統程式 -- 第 3 章 組合語言
系統程式 -- 第 3 章 組合語言系統程式 -- 第 3 章 組合語言
系統程式 -- 第 3 章 組合語言鍾誠 陳鍾誠
 
Debug Information And Where They Come From
Debug Information And Where They Come FromDebug Information And Where They Come From
Debug Information And Where They Come FromMin-Yih Hsu
 
Verilog 語法教學
Verilog 語法教學 Verilog 語法教學
Verilog 語法教學 艾鍗科技
 
[ZigBee 嵌入式系統] ZigBee Architecture 與 TI Z-Stack Firmware
[ZigBee 嵌入式系統] ZigBee Architecture 與 TI Z-Stack Firmware[ZigBee 嵌入式系統] ZigBee Architecture 與 TI Z-Stack Firmware
[ZigBee 嵌入式系統] ZigBee Architecture 與 TI Z-Stack FirmwareSimen Li
 
LLVM Backend Porting
LLVM Backend PortingLLVM Backend Porting
LLVM Backend PortingShiva Chen
 
移植FreeRTOS 之嵌入式軟體研究與開發
移植FreeRTOS 之嵌入式軟體研究與開發移植FreeRTOS 之嵌入式軟體研究與開發
移植FreeRTOS 之嵌入式軟體研究與開發艾鍗科技
 
ISUCONで学ぶ Webアプリケーションのパフォーマンス向上のコツ 実践編 完全版
ISUCONで学ぶ Webアプリケーションのパフォーマンス向上のコツ 実践編 完全版ISUCONで学ぶ Webアプリケーションのパフォーマンス向上のコツ 実践編 完全版
ISUCONで学ぶ Webアプリケーションのパフォーマンス向上のコツ 実践編 完全版Masahiro Nagano
 
Chapter 5 introduction to VHDL
Chapter 5 introduction to VHDLChapter 5 introduction to VHDL
Chapter 5 introduction to VHDLSSE_AndyLi
 
[嵌入式系統] MCS-51 實驗 - 使用 IAR (1)
[嵌入式系統] MCS-51 實驗 - 使用 IAR (1)[嵌入式系統] MCS-51 實驗 - 使用 IAR (1)
[嵌入式系統] MCS-51 實驗 - 使用 IAR (1)Simen Li
 

What's hot (20)

Arduino基礎IO控制
Arduino基礎IO控制Arduino基礎IO控制
Arduino基礎IO控制
 
[嵌入式系統] 嵌入式系統進階
[嵌入式系統] 嵌入式系統進階[嵌入式系統] 嵌入式系統進階
[嵌入式系統] 嵌入式系統進階
 
Python與Ardinio整合應用
Python與Ardinio整合應用Python與Ardinio整合應用
Python與Ardinio整合應用
 
深入淺出C語言
深入淺出C語言深入淺出C語言
深入淺出C語言
 
Arduino + rcs620sで遊ぼう
Arduino + rcs620sで遊ぼうArduino + rcs620sで遊ぼう
Arduino + rcs620sで遊ぼう
 
Arduino應用系統設計 - Arduino程式快速入門
Arduino應用系統設計 - Arduino程式快速入門Arduino應用系統設計 - Arduino程式快速入門
Arduino應用系統設計 - Arduino程式快速入門
 
Arduino overview
Arduino overviewArduino overview
Arduino overview
 
HC 05藍芽模組連線
HC 05藍芽模組連線HC 05藍芽模組連線
HC 05藍芽模組連線
 
系統程式 -- 第 3 章 組合語言
系統程式 -- 第 3 章 組合語言系統程式 -- 第 3 章 組合語言
系統程式 -- 第 3 章 組合語言
 
Arduino簡介
Arduino簡介Arduino簡介
Arduino簡介
 
Debug Information And Where They Come From
Debug Information And Where They Come FromDebug Information And Where They Come From
Debug Information And Where They Come From
 
Verilog 語法教學
Verilog 語法教學 Verilog 語法教學
Verilog 語法教學
 
[ZigBee 嵌入式系統] ZigBee Architecture 與 TI Z-Stack Firmware
[ZigBee 嵌入式系統] ZigBee Architecture 與 TI Z-Stack Firmware[ZigBee 嵌入式系統] ZigBee Architecture 與 TI Z-Stack Firmware
[ZigBee 嵌入式系統] ZigBee Architecture 與 TI Z-Stack Firmware
 
LLVM Backend Porting
LLVM Backend PortingLLVM Backend Porting
LLVM Backend Porting
 
移植FreeRTOS 之嵌入式軟體研究與開發
移植FreeRTOS 之嵌入式軟體研究與開發移植FreeRTOS 之嵌入式軟體研究與開發
移植FreeRTOS 之嵌入式軟體研究與開發
 
Learn C Programming Language by Using GDB
Learn C Programming Language by Using GDBLearn C Programming Language by Using GDB
Learn C Programming Language by Using GDB
 
I2c drivers
I2c driversI2c drivers
I2c drivers
 
ISUCONで学ぶ Webアプリケーションのパフォーマンス向上のコツ 実践編 完全版
ISUCONで学ぶ Webアプリケーションのパフォーマンス向上のコツ 実践編 完全版ISUCONで学ぶ Webアプリケーションのパフォーマンス向上のコツ 実践編 完全版
ISUCONで学ぶ Webアプリケーションのパフォーマンス向上のコツ 実践編 完全版
 
Chapter 5 introduction to VHDL
Chapter 5 introduction to VHDLChapter 5 introduction to VHDL
Chapter 5 introduction to VHDL
 
[嵌入式系統] MCS-51 實驗 - 使用 IAR (1)
[嵌入式系統] MCS-51 實驗 - 使用 IAR (1)[嵌入式系統] MCS-51 實驗 - 使用 IAR (1)
[嵌入式系統] MCS-51 實驗 - 使用 IAR (1)
 

Similar to Arduino 底層原始碼解析心得

IoT 與 WoT 物聯網裝置實作:使用 Arch Pro 與 mbed
IoT 與 WoT 物聯網裝置實作:使用 Arch Pro 與 mbedIoT 與 WoT 物聯網裝置實作:使用 Arch Pro 與 mbed
IoT 與 WoT 物聯網裝置實作:使用 Arch Pro 與 mbedBang Min Shiue
 
Arduino Basic
Arduino BasicArduino Basic
Arduino Basicmmiwwcom
 
Sigreturn Oriented Programming
Sigreturn Oriented ProgrammingSigreturn Oriented Programming
Sigreturn Oriented ProgrammingAngel Boy
 
LinkIt Smart 7688程式開發
LinkIt Smart 7688程式開發LinkIt Smart 7688程式開發
LinkIt Smart 7688程式開發Wei-Tsung Su
 
Arduino 與 s4 a
Arduino 與 s4 aArduino 與 s4 a
Arduino 與 s4 aWayne Huang
 
Sy03091说明书
Sy03091说明书Sy03091说明书
Sy03091说明书guest8f3690
 
基于 FRIDA 的全平台逆向分析
基于 FRIDA 的全平台逆向分析基于 FRIDA 的全平台逆向分析
基于 FRIDA 的全平台逆向分析CC
 
嵌入式inux應用專題文件-智慧家庭系統
嵌入式inux應用專題文件-智慧家庭系統嵌入式inux應用專題文件-智慧家庭系統
嵌入式inux應用專題文件-智慧家庭系統艾鍗科技
 
Linux binary Exploitation - Basic knowledge
Linux binary Exploitation - Basic knowledgeLinux binary Exploitation - Basic knowledge
Linux binary Exploitation - Basic knowledgeAngel Boy
 
181201_CoAP_coding365
181201_CoAP_coding365181201_CoAP_coding365
181201_CoAP_coding365Peter Yi
 
Ch1 系统启动
Ch1 系统启动Ch1 系统启动
Ch1 系统启动guest4d1b8c
 
Processing / Android / Arduino
Processing / Android / ArduinoProcessing / Android / Arduino
Processing / Android / ArduinoCAVEDU Education
 
LinkIt 7697 開發平台簡介 (Traditional Chinese)
LinkIt 7697 開發平台簡介 (Traditional Chinese)LinkIt 7697 開發平台簡介 (Traditional Chinese)
LinkIt 7697 開發平台簡介 (Traditional Chinese)Bear Wang
 
Java Crash分析(2012-05-10)
Java Crash分析(2012-05-10)Java Crash分析(2012-05-10)
Java Crash分析(2012-05-10)Kris Mok
 
20160924 创客空间活动arduino教学
20160924 创客空间活动arduino教学20160924 创客空间活动arduino教学
20160924 创客空间活动arduino教学Tzu-Heng Lin (Brian)
 

Similar to Arduino 底層原始碼解析心得 (20)

IoT 與 WoT 物聯網裝置實作:使用 Arch Pro 與 mbed
IoT 與 WoT 物聯網裝置實作:使用 Arch Pro 與 mbedIoT 與 WoT 物聯網裝置實作:使用 Arch Pro 與 mbed
IoT 與 WoT 物聯網裝置實作:使用 Arch Pro 與 mbed
 
Arduino Basic
Arduino BasicArduino Basic
Arduino Basic
 
Sigreturn Oriented Programming
Sigreturn Oriented ProgrammingSigreturn Oriented Programming
Sigreturn Oriented Programming
 
LinkIt Smart 7688程式開發
LinkIt Smart 7688程式開發LinkIt Smart 7688程式開發
LinkIt Smart 7688程式開發
 
Arduino overview
Arduino overviewArduino overview
Arduino overview
 
LinkIt 7697 IoT tutorial
LinkIt 7697 IoT tutorialLinkIt 7697 IoT tutorial
LinkIt 7697 IoT tutorial
 
Arduino 與 s4 a
Arduino 與 s4 aArduino 與 s4 a
Arduino 與 s4 a
 
Sy03091说明书
Sy03091说明书Sy03091说明书
Sy03091说明书
 
Cch2v6
Cch2v6Cch2v6
Cch2v6
 
基于 FRIDA 的全平台逆向分析
基于 FRIDA 的全平台逆向分析基于 FRIDA 的全平台逆向分析
基于 FRIDA 的全平台逆向分析
 
嵌入式inux應用專題文件-智慧家庭系統
嵌入式inux應用專題文件-智慧家庭系統嵌入式inux應用專題文件-智慧家庭系統
嵌入式inux應用專題文件-智慧家庭系統
 
AMA 中級術科實作III
AMA 中級術科實作IIIAMA 中級術科實作III
AMA 中級術科實作III
 
Linux binary Exploitation - Basic knowledge
Linux binary Exploitation - Basic knowledgeLinux binary Exploitation - Basic knowledge
Linux binary Exploitation - Basic knowledge
 
181201_CoAP_coding365
181201_CoAP_coding365181201_CoAP_coding365
181201_CoAP_coding365
 
Ch1 系统启动
Ch1 系统启动Ch1 系统启动
Ch1 系统启动
 
Tcfsh bootcamp day2
 Tcfsh bootcamp day2 Tcfsh bootcamp day2
Tcfsh bootcamp day2
 
Processing / Android / Arduino
Processing / Android / ArduinoProcessing / Android / Arduino
Processing / Android / Arduino
 
LinkIt 7697 開發平台簡介 (Traditional Chinese)
LinkIt 7697 開發平台簡介 (Traditional Chinese)LinkIt 7697 開發平台簡介 (Traditional Chinese)
LinkIt 7697 開發平台簡介 (Traditional Chinese)
 
Java Crash分析(2012-05-10)
Java Crash分析(2012-05-10)Java Crash分析(2012-05-10)
Java Crash分析(2012-05-10)
 
20160924 创客空间活动arduino教学
20160924 创客空间活动arduino教学20160924 创客空间活动arduino教学
20160924 创客空间活动arduino教学
 

More from roboard

Introduction to Vortex86EX SoC
Introduction to Vortex86EX SoCIntroduction to Vortex86EX SoC
Introduction to Vortex86EX SoCroboard
 
廢柴小六足機器人 DIY 課程
廢柴小六足機器人 DIY 課程廢柴小六足機器人 DIY 課程
廢柴小六足機器人 DIY 課程roboard
 
3D Printer 關鍵軟體控制技術之分析與探討 @ COSCUP 2014
3D Printer 關鍵軟體控制技術之分析與探討 @ COSCUP 20143D Printer 關鍵軟體控制技術之分析與探討 @ COSCUP 2014
3D Printer 關鍵軟體控制技術之分析與探討 @ COSCUP 2014roboard
 
LinuxCNC 入門簡介
LinuxCNC 入門簡介LinuxCNC 入門簡介
LinuxCNC 入門簡介roboard
 
3D Printer 韌體原始碼解析心得 (以 Marlin 為對象)
3D Printer 韌體原始碼解析心得 (以 Marlin 為對象)3D Printer 韌體原始碼解析心得 (以 Marlin 為對象)
3D Printer 韌體原始碼解析心得 (以 Marlin 為對象)roboard
 
Introduction to Vortex86EX Motion Control Modules
Introduction to Vortex86EX Motion Control ModulesIntroduction to Vortex86EX Motion Control Modules
Introduction to Vortex86EX Motion Control Modulesroboard
 
BLDC FOC 控制原理
BLDC FOC 控制原理BLDC FOC 控制原理
BLDC FOC 控制原理roboard
 
Introduction to Vortex86DX2 Motion-Control Evaluation Board
Introduction to Vortex86DX2 Motion-Control Evaluation BoardIntroduction to Vortex86DX2 Motion-Control Evaluation Board
Introduction to Vortex86DX2 Motion-Control Evaluation Boardroboard
 
RoBoard x LabVIEW 特別節目劇情版
RoBoard x LabVIEW 特別節目劇情版RoBoard x LabVIEW 特別節目劇情版
RoBoard x LabVIEW 特別節目劇情版roboard
 
RoBoard 與 Lego NXT Sensors 之連接
RoBoard 與 Lego NXT Sensors 之連接RoBoard 與 Lego NXT Sensors 之連接
RoBoard 與 Lego NXT Sensors 之連接roboard
 
Robotis Servo 與 RoBoard 之連接介面
Robotis Servo 與 RoBoard 之連接介面Robotis Servo 與 RoBoard 之連接介面
Robotis Servo 與 RoBoard 之連接介面roboard
 
六足機器人超入門簡介
六足機器人超入門簡介六足機器人超入門簡介
六足機器人超入門簡介roboard
 
認識 RoBoard 硬體
認識 RoBoard 硬體認識 RoBoard 硬體
認識 RoBoard 硬體roboard
 
馬達基本認識與 BLDC 驅動實驗
馬達基本認識與 BLDC 驅動實驗馬達基本認識與 BLDC 驅動實驗
馬達基本認識與 BLDC 驅動實驗roboard
 

More from roboard (14)

Introduction to Vortex86EX SoC
Introduction to Vortex86EX SoCIntroduction to Vortex86EX SoC
Introduction to Vortex86EX SoC
 
廢柴小六足機器人 DIY 課程
廢柴小六足機器人 DIY 課程廢柴小六足機器人 DIY 課程
廢柴小六足機器人 DIY 課程
 
3D Printer 關鍵軟體控制技術之分析與探討 @ COSCUP 2014
3D Printer 關鍵軟體控制技術之分析與探討 @ COSCUP 20143D Printer 關鍵軟體控制技術之分析與探討 @ COSCUP 2014
3D Printer 關鍵軟體控制技術之分析與探討 @ COSCUP 2014
 
LinuxCNC 入門簡介
LinuxCNC 入門簡介LinuxCNC 入門簡介
LinuxCNC 入門簡介
 
3D Printer 韌體原始碼解析心得 (以 Marlin 為對象)
3D Printer 韌體原始碼解析心得 (以 Marlin 為對象)3D Printer 韌體原始碼解析心得 (以 Marlin 為對象)
3D Printer 韌體原始碼解析心得 (以 Marlin 為對象)
 
Introduction to Vortex86EX Motion Control Modules
Introduction to Vortex86EX Motion Control ModulesIntroduction to Vortex86EX Motion Control Modules
Introduction to Vortex86EX Motion Control Modules
 
BLDC FOC 控制原理
BLDC FOC 控制原理BLDC FOC 控制原理
BLDC FOC 控制原理
 
Introduction to Vortex86DX2 Motion-Control Evaluation Board
Introduction to Vortex86DX2 Motion-Control Evaluation BoardIntroduction to Vortex86DX2 Motion-Control Evaluation Board
Introduction to Vortex86DX2 Motion-Control Evaluation Board
 
RoBoard x LabVIEW 特別節目劇情版
RoBoard x LabVIEW 特別節目劇情版RoBoard x LabVIEW 特別節目劇情版
RoBoard x LabVIEW 特別節目劇情版
 
RoBoard 與 Lego NXT Sensors 之連接
RoBoard 與 Lego NXT Sensors 之連接RoBoard 與 Lego NXT Sensors 之連接
RoBoard 與 Lego NXT Sensors 之連接
 
Robotis Servo 與 RoBoard 之連接介面
Robotis Servo 與 RoBoard 之連接介面Robotis Servo 與 RoBoard 之連接介面
Robotis Servo 與 RoBoard 之連接介面
 
六足機器人超入門簡介
六足機器人超入門簡介六足機器人超入門簡介
六足機器人超入門簡介
 
認識 RoBoard 硬體
認識 RoBoard 硬體認識 RoBoard 硬體
認識 RoBoard 硬體
 
馬達基本認識與 BLDC 驅動實驗
馬達基本認識與 BLDC 驅動實驗馬達基本認識與 BLDC 驅動實驗
馬達基本認識與 BLDC 驅動實驗
 

Recently uploaded

20200727_Insight workstation A1 plus 測試報告.pdf20200727_Insight workstation A1 ...
20200727_Insight workstation A1 plus 測試報告.pdf20200727_Insight workstation A1 ...20200727_Insight workstation A1 plus 測試報告.pdf20200727_Insight workstation A1 ...
20200727_Insight workstation A1 plus 測試報告.pdf20200727_Insight workstation A1 ...Jamie (Taka) Wang
 
函數微分_習題4.pptx 函數微分_習題4.pptx 函數微分_習題4.pptx
函數微分_習題4.pptx 函數微分_習題4.pptx 函數微分_習題4.pptx函數微分_習題4.pptx 函數微分_習題4.pptx 函數微分_習題4.pptx
函數微分_習題4.pptx 函數微分_習題4.pptx 函數微分_習題4.pptxNCU MCL
 
20200602_insight_business_plan_3.pdf20200602_insight_business_plan_3.pdf
20200602_insight_business_plan_3.pdf20200602_insight_business_plan_3.pdf20200602_insight_business_plan_3.pdf20200602_insight_business_plan_3.pdf
20200602_insight_business_plan_3.pdf20200602_insight_business_plan_3.pdfJamie (Taka) Wang
 
20200808自營電商平台策略討論20200808自營電商平台策略討論_v1.pdf
20200808自營電商平台策略討論20200808自營電商平台策略討論_v1.pdf20200808自營電商平台策略討論20200808自營電商平台策略討論_v1.pdf
20200808自營電商平台策略討論20200808自營電商平台策略討論_v1.pdfJamie (Taka) Wang
 
20200606_insight_Ignition.pdf20200606_insight_Ignition.pdf
20200606_insight_Ignition.pdf20200606_insight_Ignition.pdf20200606_insight_Ignition.pdf20200606_insight_Ignition.pdf
20200606_insight_Ignition.pdf20200606_insight_Ignition.pdfJamie (Taka) Wang
 
函數畫圖_習題5.pptx 函數畫圖_習題5.pptx 函數畫圖_習題5.pptx
函數畫圖_習題5.pptx 函數畫圖_習題5.pptx 函數畫圖_習題5.pptx函數畫圖_習題5.pptx 函數畫圖_習題5.pptx 函數畫圖_習題5.pptx
函數畫圖_習題5.pptx 函數畫圖_習題5.pptx 函數畫圖_習題5.pptxNCU MCL
 
20200607_insight_sync.pdf20200607_insight_sync.pdf
20200607_insight_sync.pdf20200607_insight_sync.pdf20200607_insight_sync.pdf20200607_insight_sync.pdf
20200607_insight_sync.pdf20200607_insight_sync.pdfJamie (Taka) Wang
 
20200429_01_software_v8.pdf20200429_01_software_v8.pdf20200429_01_software_v8...
20200429_01_software_v8.pdf20200429_01_software_v8.pdf20200429_01_software_v8...20200429_01_software_v8.pdf20200429_01_software_v8.pdf20200429_01_software_v8...
20200429_01_software_v8.pdf20200429_01_software_v8.pdf20200429_01_software_v8...Jamie (Taka) Wang
 
20200429_03_ec_v8.pdf20200429_03_ec_v8.pdf20200429_03_ec_v8.pdf
20200429_03_ec_v8.pdf20200429_03_ec_v8.pdf20200429_03_ec_v8.pdf20200429_03_ec_v8.pdf20200429_03_ec_v8.pdf20200429_03_ec_v8.pdf
20200429_03_ec_v8.pdf20200429_03_ec_v8.pdf20200429_03_ec_v8.pdfJamie (Taka) Wang
 
SymPy 在微積分上的應用_4.pptx SymPy 在微積分上的應用_4.pptx
SymPy 在微積分上的應用_4.pptx SymPy 在微積分上的應用_4.pptxSymPy 在微積分上的應用_4.pptx SymPy 在微積分上的應用_4.pptx
SymPy 在微積分上的應用_4.pptx SymPy 在微積分上的應用_4.pptxNCU MCL
 
函數畫圖_習題7.pptx 函數畫圖_習題7.pptx 函數畫圖_習題7.pptx
函數畫圖_習題7.pptx 函數畫圖_習題7.pptx 函數畫圖_習題7.pptx函數畫圖_習題7.pptx 函數畫圖_習題7.pptx 函數畫圖_習題7.pptx
函數畫圖_習題7.pptx 函數畫圖_習題7.pptx 函數畫圖_習題7.pptxNCU MCL
 
20220113_product_day copy.pdf20220113_product_day copy.pdf
20220113_product_day copy.pdf20220113_product_day copy.pdf20220113_product_day copy.pdf20220113_product_day copy.pdf
20220113_product_day copy.pdf20220113_product_day copy.pdfJamie (Taka) Wang
 
20200427_02_hardware_v3.pdf20200427_02_hardware_v3.pdf
20200427_02_hardware_v3.pdf20200427_02_hardware_v3.pdf20200427_02_hardware_v3.pdf20200427_02_hardware_v3.pdf
20200427_02_hardware_v3.pdf20200427_02_hardware_v3.pdfJamie (Taka) Wang
 
20210105_量產技轉.pdf20210105_量產技轉.pdf20210105_量產技轉.pdf
20210105_量產技轉.pdf20210105_量產技轉.pdf20210105_量產技轉.pdf20210105_量產技轉.pdf20210105_量產技轉.pdf20210105_量產技轉.pdf
20210105_量產技轉.pdf20210105_量產技轉.pdf20210105_量產技轉.pdfJamie (Taka) Wang
 
SymPy 在微積分上的應用_5.pptx SymPy 在微積分上的應用_5.pptx
SymPy 在微積分上的應用_5.pptx SymPy 在微積分上的應用_5.pptxSymPy 在微積分上的應用_5.pptx SymPy 在微積分上的應用_5.pptx
SymPy 在微積分上的應用_5.pptx SymPy 在微積分上的應用_5.pptxNCU MCL
 
买假和真英国驾驶执照买了假的英国驾照,那跟真的有什么区别吗?买假和真正的澳大利亚驾驶执照【微信qoqoqdqd】
买假和真英国驾驶执照买了假的英国驾照,那跟真的有什么区别吗?买假和真正的澳大利亚驾驶执照【微信qoqoqdqd】买假和真英国驾驶执照买了假的英国驾照,那跟真的有什么区别吗?买假和真正的澳大利亚驾驶执照【微信qoqoqdqd】
买假和真英国驾驶执照买了假的英国驾照,那跟真的有什么区别吗?买假和真正的澳大利亚驾驶执照【微信qoqoqdqd】黑客 接单【TG/微信qoqoqdqd】
 
函數畫圖_習題6.pptx 函數畫圖_習題6.pptx 函數畫圖_習題6.pptx
函數畫圖_習題6.pptx 函數畫圖_習題6.pptx 函數畫圖_習題6.pptx函數畫圖_習題6.pptx 函數畫圖_習題6.pptx 函數畫圖_習題6.pptx
函數畫圖_習題6.pptx 函數畫圖_習題6.pptx 函數畫圖_習題6.pptxNCU MCL
 

Recently uploaded (17)

20200727_Insight workstation A1 plus 測試報告.pdf20200727_Insight workstation A1 ...
20200727_Insight workstation A1 plus 測試報告.pdf20200727_Insight workstation A1 ...20200727_Insight workstation A1 plus 測試報告.pdf20200727_Insight workstation A1 ...
20200727_Insight workstation A1 plus 測試報告.pdf20200727_Insight workstation A1 ...
 
函數微分_習題4.pptx 函數微分_習題4.pptx 函數微分_習題4.pptx
函數微分_習題4.pptx 函數微分_習題4.pptx 函數微分_習題4.pptx函數微分_習題4.pptx 函數微分_習題4.pptx 函數微分_習題4.pptx
函數微分_習題4.pptx 函數微分_習題4.pptx 函數微分_習題4.pptx
 
20200602_insight_business_plan_3.pdf20200602_insight_business_plan_3.pdf
20200602_insight_business_plan_3.pdf20200602_insight_business_plan_3.pdf20200602_insight_business_plan_3.pdf20200602_insight_business_plan_3.pdf
20200602_insight_business_plan_3.pdf20200602_insight_business_plan_3.pdf
 
20200808自營電商平台策略討論20200808自營電商平台策略討論_v1.pdf
20200808自營電商平台策略討論20200808自營電商平台策略討論_v1.pdf20200808自營電商平台策略討論20200808自營電商平台策略討論_v1.pdf
20200808自營電商平台策略討論20200808自營電商平台策略討論_v1.pdf
 
20200606_insight_Ignition.pdf20200606_insight_Ignition.pdf
20200606_insight_Ignition.pdf20200606_insight_Ignition.pdf20200606_insight_Ignition.pdf20200606_insight_Ignition.pdf
20200606_insight_Ignition.pdf20200606_insight_Ignition.pdf
 
函數畫圖_習題5.pptx 函數畫圖_習題5.pptx 函數畫圖_習題5.pptx
函數畫圖_習題5.pptx 函數畫圖_習題5.pptx 函數畫圖_習題5.pptx函數畫圖_習題5.pptx 函數畫圖_習題5.pptx 函數畫圖_習題5.pptx
函數畫圖_習題5.pptx 函數畫圖_習題5.pptx 函數畫圖_習題5.pptx
 
20200607_insight_sync.pdf20200607_insight_sync.pdf
20200607_insight_sync.pdf20200607_insight_sync.pdf20200607_insight_sync.pdf20200607_insight_sync.pdf
20200607_insight_sync.pdf20200607_insight_sync.pdf
 
20200429_01_software_v8.pdf20200429_01_software_v8.pdf20200429_01_software_v8...
20200429_01_software_v8.pdf20200429_01_software_v8.pdf20200429_01_software_v8...20200429_01_software_v8.pdf20200429_01_software_v8.pdf20200429_01_software_v8...
20200429_01_software_v8.pdf20200429_01_software_v8.pdf20200429_01_software_v8...
 
20200429_03_ec_v8.pdf20200429_03_ec_v8.pdf20200429_03_ec_v8.pdf
20200429_03_ec_v8.pdf20200429_03_ec_v8.pdf20200429_03_ec_v8.pdf20200429_03_ec_v8.pdf20200429_03_ec_v8.pdf20200429_03_ec_v8.pdf
20200429_03_ec_v8.pdf20200429_03_ec_v8.pdf20200429_03_ec_v8.pdf
 
SymPy 在微積分上的應用_4.pptx SymPy 在微積分上的應用_4.pptx
SymPy 在微積分上的應用_4.pptx SymPy 在微積分上的應用_4.pptxSymPy 在微積分上的應用_4.pptx SymPy 在微積分上的應用_4.pptx
SymPy 在微積分上的應用_4.pptx SymPy 在微積分上的應用_4.pptx
 
函數畫圖_習題7.pptx 函數畫圖_習題7.pptx 函數畫圖_習題7.pptx
函數畫圖_習題7.pptx 函數畫圖_習題7.pptx 函數畫圖_習題7.pptx函數畫圖_習題7.pptx 函數畫圖_習題7.pptx 函數畫圖_習題7.pptx
函數畫圖_習題7.pptx 函數畫圖_習題7.pptx 函數畫圖_習題7.pptx
 
20220113_product_day copy.pdf20220113_product_day copy.pdf
20220113_product_day copy.pdf20220113_product_day copy.pdf20220113_product_day copy.pdf20220113_product_day copy.pdf
20220113_product_day copy.pdf20220113_product_day copy.pdf
 
20200427_02_hardware_v3.pdf20200427_02_hardware_v3.pdf
20200427_02_hardware_v3.pdf20200427_02_hardware_v3.pdf20200427_02_hardware_v3.pdf20200427_02_hardware_v3.pdf
20200427_02_hardware_v3.pdf20200427_02_hardware_v3.pdf
 
20210105_量產技轉.pdf20210105_量產技轉.pdf20210105_量產技轉.pdf
20210105_量產技轉.pdf20210105_量產技轉.pdf20210105_量產技轉.pdf20210105_量產技轉.pdf20210105_量產技轉.pdf20210105_量產技轉.pdf
20210105_量產技轉.pdf20210105_量產技轉.pdf20210105_量產技轉.pdf
 
SymPy 在微積分上的應用_5.pptx SymPy 在微積分上的應用_5.pptx
SymPy 在微積分上的應用_5.pptx SymPy 在微積分上的應用_5.pptxSymPy 在微積分上的應用_5.pptx SymPy 在微積分上的應用_5.pptx
SymPy 在微積分上的應用_5.pptx SymPy 在微積分上的應用_5.pptx
 
买假和真英国驾驶执照买了假的英国驾照,那跟真的有什么区别吗?买假和真正的澳大利亚驾驶执照【微信qoqoqdqd】
买假和真英国驾驶执照买了假的英国驾照,那跟真的有什么区别吗?买假和真正的澳大利亚驾驶执照【微信qoqoqdqd】买假和真英国驾驶执照买了假的英国驾照,那跟真的有什么区别吗?买假和真正的澳大利亚驾驶执照【微信qoqoqdqd】
买假和真英国驾驶执照买了假的英国驾照,那跟真的有什么区别吗?买假和真正的澳大利亚驾驶执照【微信qoqoqdqd】
 
函數畫圖_習題6.pptx 函數畫圖_習題6.pptx 函數畫圖_習題6.pptx
函數畫圖_習題6.pptx 函數畫圖_習題6.pptx 函數畫圖_習題6.pptx函數畫圖_習題6.pptx 函數畫圖_習題6.pptx 函數畫圖_習題6.pptx
函數畫圖_習題6.pptx 函數畫圖_習題6.pptx 函數畫圖_習題6.pptx
 

Arduino 底層原始碼解析心得

  • 4. 開啟 .ino 程式檔 Arduino IDE 的使用
  • 10. Q: Arduino 0023、1.0.5、1.5.2 原始碼, 要 推倒哪一個? A: 我們將以 Arduino 1.0.5 為主要推倒對 象
  • 12. 原始碼目錄介紹 改過的 Processing IDE 原始碼 (Arduino 相關) Processing IDE 原始碼 存放編譯結果的目錄 Arduino Bootloader, Standard API 原始碼 Arduino Library 原始碼
  • 13. app → src → processing → app → debug 處理 Arduino 韌體燒錄動作 處理 Arduino 韌體燒錄動作 處理 .ino 編譯動作 今天不談這裡
  • 14. hardware → arduino 各種版本 bootloader 原始碼 Standard API 原始碼(共用部分) 各種周邊配套的處理器韌體 Standard API 不共用部分 定義 Board 選單及編譯參數 定義 Programmers 選單及燒錄參數 今天只談它
  • 15. 如何編譯 Arduino 原始碼? http://code.google.com/p/arduino/wiki/BuildingArduino
  • 16. Windows 下編譯 Arduino 原始碼 下載 JAVA JDK 並完成安裝 下載 cygwin並完成安裝 ◦Linux-like environment for Windows ◦安裝 cygwin 過程中, 選擇安裝下列套件 git make, gcc-mingw, and g++ perl unzip, zip
  • 17. Windows 下編譯 Arduino 原始碼 下載 Apache Ant 程式 ◦JAVA base 編譯器 設定 Apache Ant 和 JAVA JDK 的環境變 數 執行 cygwin, 使用 git 指令下載 Arduino 最新原始碼
  • 18. Windows 下編譯 Arduino 原始碼 使用指令 ant/ant run 開始編譯 Arduino 原始碼
  • 19. Windows 下編譯 Arduino 原始碼 編譯完成的結果會存放在 (DIR) buildwindowswork 資料夾內
  • 20. Linux、Mac 下編譯 Arduino 原始碼 Orz… 目前還沒時間試… (哭~~~)
  • 22. .ino: 偽裝過的 C++ 一切都是幻覺, 嚇不倒我滴!! ◦Arduino 會先將 .ino 檔轉換為 .cpp 檔再進 行編譯 ◦可在 .ino 檔中使用 C++ 語法 (但不能使用 C++ standard library 內的某些物件或函式, 例如: cout, cin) ◦可使用 avr-gcc 的所有語法
  • 23. IDE 會將 .ino 轉換成 .cpp 加入 include ” Arduino.h” 加入所有.ino 內函式的原型宣告 加入編譯指示詞#line, 重新定義與原始.ino 檔一致的 行號
  • 24. .ino 的編譯流程概觀 Arduino IDE 會先建立一個暫存目錄 把 .ino 轉成 .cpp, 複製到暫存目錄下並 進行編譯 掃描並編譯 .ino 所 include 到的每個 library, 編譯結果輸出到暫存目錄下 所有編譯結果連結成一個 .hex 的韌體 燒錄檔 若編譯過程出錯, 會直接停止編譯並 show 出錯誤訊息
  • 25. 進入 Arduino Standard API (樓還沒歪…無誤)
  • 26. Standard API 概觀 Digital I/O ◦pinMode( ) ◦degitalWrite( ) ◦degitalRead( ) Analog I/O ◦analogReference() ◦analogRead() ◦analogWrite()
  • 27. Standard API 概觀 Advanced I/O ◦tone ( ) ◦noTone ( ) ◦shiftOut( ) ◦shiftIn( ) ◦pulseln( )
  • 28. Standard API 概觀 時間函式 ◦millis( ) ◦micros( ) ◦delay( ) ◦delayMicroseconds( )
  • 29. Standard API 概觀 基本數學函式 ◦min( ) ◦max( ) ◦abs( ) ◦constrain( ) ◦map( ) ◦pow( ) ◦sqrt( )
  • 30. Standard API 概觀 三角函式 ◦sin( ) ◦cos( ) ◦tan( ) 隨機數函式 ◦randomSeed( ) ◦random( )
  • 31. Standard API 概觀 位元操作 ◦lowByte( ) ◦highByte( ) ◦bitRead( ) ◦bitWrite( ) ◦bitSet( ) ◦bitClear( ) ◦bit( )
  • 32. Standard API 概觀 中斷相關函式 ◦attachInterrupt( ) ◦detachInterrupt( ) ◦Interrupts( ) ◦noInterrupts( )
  • 33. Standard API 概觀 串列通訊 ◦serial.begin( ) ◦serial.available( ) ◦serial.read( ) ◦serial.write( )
  • 34. 從進入的觀點看 Standard API 接著重新用嘿客的眼光來分類 Standard API 直接來自 C/C++ standard library 的函式 ◦pow( ) ◦sqrt( ) ◦sin( ) ◦cos( ) ◦tan( )
  • 35. 從進入的觀點看 Standard API 直接使用 C 語言巨集定義的函式 ◦min( ) ◦max( ) ◦constrain( ) ◦abs( ) Arduino.h
  • 36. 從進入的觀點看 Standard API 直接使用 C 語言巨集定義的函式 ◦lowByte( ) ◦highByte( ) ◦bitRead( ) ◦bitWrite( ) ◦bitSet( ) ◦bitClear( ) ◦bit( ) Arduino.h
  • 37. 從進入的觀點看 Standard API 平台獨立函式 ◦randomSeed( ) ◦random( ) ◦map( ) WMath.cpp
  • 38. 從進入的觀點看 Standard API 硬體相關函式 ◦pinMode( ) ◦degitalWrite( ) ◦degitalRead( ) ◦analogReference() ◦analogRead() ◦analogWrite() ◦tone ( ) ◦noTone ( )
  • 39. 從進入的觀點看 Standard API 硬體相關函式 ◦shiftOut( ) ◦shiftIn( ) ◦pulseln( ) ◦millis( ) ◦micros( ) ◦delay( ) ◦delayMicroseconds( )
  • 40. 從進入的觀點看 Standard API 硬體相關函式 ◦attachInterrupt( ) ◦detachInterrupt( ) ◦Interrupts( ) ◦noInterrupts( ) ◦serial.begin( ) ◦serial.available( ) ◦serial.read( ) ◦serial.write( )
  • 41. 硬體相關函式實作解析 pinMode (pin, mode) ◦函式功能: 設定腳位為輸出或輸入模式 ◦函式實作內容: 1. 由指定的 pin 編號來取得對應的 port 2. 由 port 找到對應的暫存器 3. 依照輸入的 mode, 修改暫存器設定
  • 43. 硬體相關函式實作解析 digitalWrite (pin, value) ◦函式功能: 設定腳位輸出電位為 HIGH/LOW ◦函式實作內容: 1. 由指定的 pin 編號來取得對應的 port 2. 檢查指定 pin 上的硬體 PWM 是否正在被使用, 如果是則停止它 3. 由 port 找到對應的暫存器 4. 依照輸入的 value, 修改暫存器設定
  • 45. 硬體相關函式實作解析 digitalRead (pin) ◦函式功能: 讀取指定腳位的輸入電位, 回傳 HIGH/LOW ◦函式實作內容: 1. 由指定的 pin 編號來取得對應的 port 2. 檢查指定 pin 的硬體 PWM 是否正在被使用, 如 果是則停止它 3. 由 port 找到對應的暫存器, 讀取並判斷暫存器 值, 回傳 HIGH/LOW
  • 47. 硬體相關函式實作解析 analogReference (mode) ◦函式功能: 設定 A/D 的參考電壓 ◦函式實作內容: 把指定的 mode 傳給內部宣告的變數 wiring_analog.c
  • 48. 硬體相關函式實作解析 analogRead (pin) ◦函式功能: 讀取 A/D 的電壓數值 ◦函式實作內容: 1. 依照不同的 Arduino 版本, 由輸入的 pin 編號來 取得對應的 analog IN 腳位 2. 設定 analog reference 和 PIN 3. 開始做 A/D 轉換並等待完成 4. 回傳轉換後的值
  • 51. 硬體相關函式實作解析 analogWrite (pin, val) ◦函式功能: 使用 Arduino 的 PWM 硬體送出指定 duty 的 PWM ◦函式實作內容: 1. 先將指定 pin 切成 OUTPUT 2. 再從指定 pin 編號, 找到相對應的 timer 3. 把 val 設定到 timer 暫存器 (藉由 timer 和 PWM generator 的硬體行為輸出指定 duty 的 PWM)
  • 53. 硬體相關函式實作解析 tone (pin, frequency, duration) ◦函式功能: 從指定的 pin 送出 frequency 頻率的 pulse (duty 為 50%) 並持續一段 duration 時間 ◦函式實作內容: 1. 依據輸入的 pin 編號, 初始化對應的 timer 2. 計算輸入的 frequency 並將結果填入 timer 暫 存器 3. 將 duration 與 frequency 換算成 timer counter 4. 開啟 timer 中斷, 在 ISR 中進行/停止 pulse 輸出
  • 56. 硬體相關函式實作解析 noTone (pin) ◦函式功能: 停止指定 pin 的 pulse 輸出 ◦函式實作內容: 1. 依據輸入的 pin 編號, 取得正在使用中的 timer 2. 關閉 timer 中斷 3. 將輸出 pin 的電位設定為 0
  • 58. 硬體相關函式實作解析 shiftOut (datapin, clockpin, bitorder, val) ◦函式功能: 選用兩個 pin 作為 datapin 與 clockpin, 將 8-bit val 用指定的 bitorder 送出 ◦函式實作內容: 1. 依照指定的 bitorder 將 val 從 datapin 輸出 2. 改變 clockpin 電位, 使其 high、low 各一次
  • 60. 硬體相關函式實作解析 shiftIn (datapin, clockpin, bitorder) ◦函式功能: 選用兩個 pin 作為 datapin 與 clockpin, 用指定的 bitorder 讀取 8-bit 的 value ◦函式實作內容: 1. 設定 clockpin 電位為 high 2. 用指定的 bitorder 從 datapin 讀取 1bit value 3. 設定 clockpin 電位為 low 4. 以上三個步驟重複 8 次
  • 62. 硬體相關函式實作解析 PulseIn (pin, state, timeout) ◦函式功能: 對指定的 pin 去計算輸入 state (high/low) 的持續時間 ◦函式實作內容: 1. 由指定的 pin 編號來取得對應的 port 2. 設定 state 的 timeout 時間 3. 等待 pin 的電位變化到非指定的 state 4. 等待 pin 的電位變化到指定的 state 並開始計時 5. 等待 pin 的電位變化到非指定的 state 並停止計時 6. 回傳指定 state 持續的總時間
  • 64. 硬體相關函式實作解析 millis ( ) ◦函式功能: 回傳 Arduino 運行後所經過的時間, 單位是 millisencond, resolution 是 1ms ◦函式實作內容: 1. 關中斷 2. 讀取目前的 timer0_millis 變數值 3. 開中斷 4. 回傳其值
  • 66. 硬體相關函式實作解析 micros ( ) ◦函式功能: 回傳 Arduino 運行後所經過的時間, 單位是 microsencond, resolution 是 4us (for 16MHz) ◦函式實作內容: 1. 關中斷 2. 先讀取 timer overflow 的次數 3. 判斷此時 timer 是否 overflow, 若是則加一次 4. 讀取目前的 timer counter 5. 開中斷 6. 計算 timer overflow 次數與 counter 值 7. 將計算結果回傳
  • 68. 硬體相關函式實作解析 delay (ms) ◦函式功能: 延長一段指定的時間, 單位是 ms, resolution 是 1ms ◦函式實作內容: 1. 調用 micros ( ) 得到目前的時間 count 值 2. 每經過 1ms 後把指定的 ms 值減一, 直到 ms 等於 0 為止
  • 70. 硬體相關函式實作解析 delayMicroseconds (us) ◦函式功能: 延長一段指定的時間, 單位是 us, resolution 是 1us ◦函式實作內容: 1. 依據 CPU 時脈與輸入的 us, 算出需要的 count 總數 2. 將 count 減一, 直到 0 為止
  • 72. 硬體相關函式實作解析 interrupts ( ) ◦函式功能: 打開 global 中斷 ◦函式實作內容: 對 SREG 的第 7 bit (Global Interrupt Enable) 填 1 Arduino.h interrupt.h
  • 73. 硬體相關函式實作解析 nointerrupts ( ) ◦函式功能: 關閉 global 中斷 ◦函式實作內容: 對 SREG 的第 7 bit (Global Interrupt Enable) 填 0 Arduino.h interrupt.h
  • 74. 硬體相關函式實作解析 attachInterrupt(intnum, userFunc, mode) ◦函式功能: 掛載使用者的 callback function, 並依據輸入 mode 決定觸發外部中斷的條件 ◦函式實作內容: 1. 掛載 user function 2. 設定觸發 mode 3. 依據指定的 intnum, 啟用可作為外部觸發功能 的腳位
  • 76. 硬體相關函式實作解析 detachInterrupt(intnum) ◦函式功能: 卸載指定 intnum 的外部中斷功能 ◦函式實作內容: 依據使用的 Arduino 版本, 關閉指定的外部中斷
  • 78. 硬體相關函式實作解析 Serial.begin (baud) ◦函式功能: 設定串列傳輸的 buadrate ◦函式實作內容: 依據使用的 Arduino 版本, 把指定的 baudrate 設 定到 baudrate 暫存器中 啟用 RX、 TX、RX complete 中斷、Data Register Empty 中斷
  • 80. 硬體相關函式實作解析 Serial.available ( ) ◦函式功能: 判斷 COM port 是否收到數據 ◦函式實作內容: 回傳 rx buffer 中的 data 個數 HardwareSerial.cpp
  • 81. 硬體相關函式實作解析 Serial.read ( ) ◦函式功能: 讀取 COM port 讀到的數據 ◦函式實作內容: 判斷 rx buffer 是否為空, 如果是則回傳 -1, 如果 不是則讀取一個 data, 回傳給使用者
  • 83. 硬體相關函式實作解析 Serial.write ( ) ◦函式功能: 寫入 data 到 COM port ◦函式實作內容: 判斷 tx buffer 是否為已滿, 如果是, 則等到有空 間時把一個 data 丟進 tx buffer, 如果不是則立 刻把一個 data 丟進去
  • 86. 86Duino硬體配置 多功能 外部中 斷 I/O USB 2.0 Arduino Leonardo 相容 I/O Arduino Leonardo 相容 I/O Arduino Leonardo 相容 I/O
  • 88. 86Duino 軟體設計概觀 IDE 設計原則 ◦不改變 Arduino IDE 原有功能的前提下, 加 入對 86Duino 的編譯及燒錄支援 移植 coreboot + SeaBIOS 做為 86Duino 的開源 BIOS 韌體使用 FreeDOS 做為 OS ◦快速開機: 通電 2 秒內 run 起使用者程式 ◦中斷掛載容易實現 ◦架構上最接近 Arduino 韌體架構
  • 89. 86Duino 軟體設計概觀 採用 DJGPP 做為 86Duino 的編譯系統 ◦DJGPP: 第一款出現在 x86 上的 GUN gcc ◦相容大部分 avr-gcc 的語法 ◦執行於 x86 保護模式下, 無記憶體使用限制 使用 DJGPP 的問題 ◦DJGPP 為 DOS 程式, 無法直接在 Linux, Mac, 64-bit Win7/Win8 下執行 ◦目前解決方法: 86Duino IDE 調用 DOSBOX 執行 DJGPP
  • 90. 軟體開發背後堅持的原則 在軟體系統每個環節, 只使用歐噴壽司 工具 ◦BIOS: coreboot + SeaBIOS (open source) ◦OS: FreeDOS (open source) ◦編譯系統: DJGPP & DOSBOX (open source) ◦程式庫: DJGPP & Arduino上各種第三方開 源程式庫 (ex: Allegro) ◦IDE: Processing/Arduino IDE (open source) ◦燒錄軟體: 自己寫 (open source)
  • 91. Arduino Standard API 在 86Duino 上的移植 直接來自 C/C++ standard library 的 API ◦DJGPP 與 avr-gcc 相容, 無需移植 直接使用 C 語言巨集定義的 API ◦直接沿用 Arduino 原始碼 平台獨立 API ◦直接沿用 Arduino 原始碼 硬體相關 API ◦重新改寫至 x86 平台
  • 92. 硬體相關 API 在 86Duino 上的實作 pinMode( ) ◦函式功能: 用以配置腳位為輸出或輸入模式 ◦程式設計流程: 與 Arduino 流程相同 改填屬於 86Duino 自己的暫存器
  • 94. 硬體相關 API 在 86Duino 上的實作 digitalWrite (pin, value) ◦函式功能: 設定腳位輸出電位為 HIGH/LOW ◦函式實作內容: 1. 檢查指定 pin 上的硬體 PWM 是否正在被使用, 如果是則停止它 2. 由 pin 編號找到對應的暫存器 3. 依照輸入的 value, 修改暫存器設定
  • 96. digitalRead (pin) ◦函式功能: 讀取指定腳位的輸入電位, 回傳 HIGH/LOW ◦函式實作內容: 1. 檢查指定 pin 的硬體 PWM 是否正在被使用, 如 果是則停止它 2. 由 pin 編號找到對應的暫存器, 讀取並判斷暫存 器值後, 回傳 HIGH/LOW 硬體相關 API 在 86Duino 上的實作
  • 98. 硬體相關 API 在 86Duino 上的實作 analogRead (pin) ◦函式功能: 讀取 A/D 的電壓數值 ◦函式實作內容: 1. 初始化 A/D 2. 設定 PIN 3. 開始做 A/D 轉換 4. 回傳轉換後的值
  • 100. 硬體相關 API 在 86Duino 上的實作 analogWrite (pin, val) ◦函式功能: 使用 86duino 中的 MCM 之 PWM 硬體送出指定 duty 的 PWM ◦函式實作內容: 1. 從指定 pin 編號, 找到相對應的 MCM 2. 將指定 pin 切成 PWM 輸出 3. 把 val 設定至 PWM 相關暫存器 4. Enable PWM
  • 103. 硬體相關 API 在 86Duino 上的實作 tone (pin, frequency, duration) ◦函式功能: 從指定的 pin 送出 frequency 頻率的 pulse (duty 為 50%) 並持續一段 duration 時間 ◦函式實作內容: 1. 計算輸入的 frequency 並將結果填入設定 PWM 相關暫存器 2. 將 duration 與 frequency 換算成 PWM period 的總個數 3. 開啟 MCM 中斷, 在 ISR 中進行/停止 pulse 輸出 Tone ( ) 的 PWM 主要作為 timer 用, 指定腳位上不會輸出 PWM pulse
  • 106. 硬體相關 API 在 86Duino 上的實作 noTone (pin) ◦函式功能: 停止指定 pin 的 pulse 輸出 ◦函式實作內容: 1. 關閉 MCM PWM 2. 將輸出 pin 的電位設定為 0
  • 108. 硬體相關 API 在 86Duino 上的實作 shiftOut (datapin, clockpin, bitorder, val) ◦函式功能: 選用兩個 pin 作為 datapin 與 clockpin, 將 8-bit val 用指定的 bitorder 送出 ◦函式實作內容: 內容與 Arduino 相同, 未做任何修改
  • 109. 硬體相關 API 在 86Duino 上的實作 shiftIn (datapin, clockpin, bitorder) ◦函式功能: 選用兩個 pin 作為 datapin 與 clockpin, 用指定的 bitorder 讀取 8-bit 的 value ◦函式實作內容: 內容與 Arduino 相同, 未做任何修改
  • 110. 硬體相關 API 在 86Duino 上的實作 PulseIn (pin, state, timeout) ◦函式功能: 對指定的 pin 去計算輸入 state (high/low) 的持續時間 ◦函式實作內容: 1. 設定硬體 PWM 參數 2. 等待 pin 的電位變化到非指定的 state 3. 等待 pin 的電位變化到指定的 state 並開始計時 4. 等待 pin 的電位變化到非指定的 state 並停止計時 5. 回傳硬體 PWM 的 sample cycle 6. 計算時間並回傳數值
  • 112. 硬體相關 API 在 86Duino 上的實作 millis ( ) ◦函式功能: 回傳 86duino 運行後所經過的時間, 單位是 millisencond, resolution 是 1ms ◦函式實作內容: 回傳 timer_nowtime ( ) 的值 timer_nowtime() 函式實作內容: 在 DOS DJGPP 環境底下調用 uclock(), 取得的時間換算成 millisecond 後回傳
  • 114. 硬體相關 API 在 86Duino 上的實作 micros ( ) ◦函式功能: 回傳 86duino 運行後所經過的時間, 單位是 microsencond, resolution 是 1us ◦函式實作內容: 1. 取得 CPU clock count 2. 將 count 以 CPU 時脈換算後回傳
  • 116. 硬體相關 API 在 86Duino 上的實作 delay (ms) ◦函式功能: 延長一段指定的時間, 單位是 ms, resolution 是 1ms ◦函式實作內容: 1. 將 timer_nowtime ( ) 得到的數值加上輸入的 ms 計算出目標時間 2. 無限等待, 直到超過/到達目標時間
  • 118. 硬體相關 API 在 86Duino 上的實作 delayMicroseconds (us) ◦函式功能: 延長一段指定的時間, 單位是 us, resolution 是 1us ◦函式實作內容: 將目前時間減去進入此 function 的時間, 將結果 轉換成 microsecond 單位後與輸入的 us 值比較, 直到值大於 us 為止
  • 120. 硬體相關 API 在 86Duino 上的實作 interrupts ( ) ◦函式功能: 打開 global 中斷 ◦函式實作內容: 對 EFLAGS 的 IF bit 填 1 Arduino.h io.c
  • 121. 硬體相關 API 在 86Duino 上的實作 nointerrupts ( ) ◦函式功能: 關閉 global 中斷 ◦函式實作內容: 對 EFLAGS 的 IF bit 填 0 Arduino.h io.c
  • 122. 硬體相關 API 在 86Duino 上的實作 attachInterrupt(intnum, userFunc, mode) ◦函式功能: 掛載使用者的 callback function, 並依據輸入 mode 決定觸發外部中斷的條件 ◦函式實作內容: 1. 掛載 user function 2. 設定觸發 mode 3. 依據指定的 intnum, 啟用可作為外部觸發功能 的腳位
  • 124. 硬體相關 API 在 86Duino 上的實作 detachInterrupt(intnum) ◦函式功能: 卸載指定 intnum 的外部中斷功能 ◦函式實作內容: 關閉指定的 intnum 中斷
  • 126. 硬體相關 API 在 86Duino 上的實作 Serial.begin (baud) ◦函式功能: 設定串列傳輸的 buadrate ◦函式實作內容: 1. 設定鮑率。 2. 設定傳輸資料長度、同位元檢查、停止位元。 3. 清空 TX、RXQueue。 4. 設定 timeout。
  • 128. 硬體相關 API 在 86Duino 上的實作 Serial.available ( ) ◦函式功能: 判斷 COM port 是否收到數據 ◦函式實作內容: 回傳 rx queue中的 data 個數 HardwareSerial.cpp
  • 129. 硬體相關 API 在 86Duino 上的實作 Serial.read ( ) ◦函式功能: 讀取 COM port 讀到的數據 ◦函式實作內容: 調用 com lib 中的 com_Read ( ) 讀取一個 rx buffer 中的值並回傳 HardwareSerial.cpp
  • 130. 硬體相關 API 在 86Duino 上的實作 Serial.write ( ) ◦函式功能: 寫入 data 到 COM port ◦函式實作內容: 調用 com lib 中的 com_Write ( ), 傳送一個 8-bit 值 HardwareSerial.cpp
  • 131. Arduino 原始碼讀書會 (II) : Bootloader 解析
  • 134. Arduino 原始碼根目錄 改過的 Processing IDE 原始碼 (Arduino 相關) Processing IDE 原始碼 存放編譯結果的目錄 Arduino Bootloader, Standard API 原始碼 Arduino Library 原始碼
  • 135. hardware → arduino 各種版本 bootloader 原始碼 Standard API 原始碼(共用部分) 各種周邊配套的處理器韌體 Standard API 不共用部分 定義 Board 選單及編譯參數 定義 Programmers 選單及燒錄參數
  • 136. hardware → arduino → bootloaders Duemilanove , Diecimila , Nano , Fio ....... Arduino NG or older w/ ATmega8 BT ATmega328 , BT ATmega168 Arduino Robot LilyPad Arduino USB Leonardo , Micro , Esplora LilyPad Arduino ATmega168 Uno , Mini ATmega328 , Ethernet Mega 2560 , Mega ADK 本次原始碼解析目標 (其它bootloaders可以此類推)
  • 137. UNO Bootloader optiboot source code 已編譯好的各種 版本 16 進位檔
  • 138. Leonardo Bootloader caterina source code 已編譯好的各種 版本 16 進位檔 各種版本 bootloader 說明
  • 139. Serial Bootloader 解析 --- 以 UNO 為例
  • 140. Arduino UNO Bootloader Arduino UNO 使用了 optiboot,優點: ◦佔用空間只有1.5kB ◦鮑率115200,上傳程序速度較舊版 ATmega bootloader 快 ◦程式碼進行了優化,運行效率較舊版提高, 並且無看門狗問題 ◦支持較多的 ATmega 晶片
  • 141. 與 Bootloader 有關的電路 USB to Serial bridge Arduino 主晶片 USB 接頭 PC USB Serial
  • 142. 與 Bootloader 有關的電路 Serial TX/RX 資料傳輸線 Serial DTR (用於 reset Arduino) Arduino 主晶片 USB to Serial bridge
  • 143. UNO Bootloader 程式流程 UART init Watchdog init 是否由 RESET Pin 引起 執行 Arduino F/W 否 是 依命令把 Arduino F/W寫入 Flash 把 watchdog 設定成 16ms, 並等待系統自行 reset reset 每接收一個字元都會 重設 watchdog Watchdog 預設 1s (timeout 自行 reset) TX, RX 燈號是由 Atmega16U2(USB to Serial bridge) 控制 由 serial port 接收 Host 命令 是 否 收到 exit bootloader 命令
  • 144. Bootloader 原始碼重要細節 判斷 reset 來源, 如果不是 reset button 或 serial DTR reset, 就呼叫 appStart() 直 接執行 Arduino F/W 初始化 watchdog timer = 1s, (如果一秒內 bootloader 沒有從 serial 收到任何資 料, 將會自動跳出並執行 Arduino F/W)
  • 145. Bootloader 原始碼重要細節 從 serial port 讀取字元 Bootloader main loop 進行 STK500 通訊協定的命令處理 (STK500協定規範請自行參考 Atmel 文件: http://www.atmel.com/Images/doc2591.pdf) 如果收到 exit 命令, 則設定 watchdog timer = 16ms, 並 呼叫 verifySpace() 等待系 統自行 reset
  • 146. Bootloader 重要函式註解 getch ( ) ◦從 serial port 讀取一字元 putch ( ) ◦由 serial port 送出一字元 verifySpace ( ) ◦接受並回應 STK500 命令結尾 token
  • 147. Bootloader 重要函式註解 watchdogReset ( ) ◦Reset watchdog timer watchdogConfig ( ) ◦設定 watchdog timer appStart ( ) ◦執行使用者燒錄的 Arduino 韌體程式
  • 148. Arduino IDE 對 Bootloader 的操作 IDE 將編譯程 式, 並透過 bootloader 將 編譯結果 上傳到 Arduino 板子上
  • 149. Arduino IDE 對 Bootloader 的操作 IDE 上傳程式的流程 取得要燒錄的檔案所在路徑 和檔案名稱 由板子版本決定燒錄參數 取得燒錄程式路徑與檔名 執行燒錄程式 avrdude.exe 是否燒錄成 功? 回傳失敗 是 (由 avrdude.exe 的回傳值決定) 否 (IDE 這部分的原始碼等之後 的讀書會再進行詳細解析) 回傳成功 Avrdude 會自行透過 DTR 重啟 Arduino, 以進入 bootlaoder
  • 150. USB Bootloader 解析 --- 以 Leonardo 為例
  • 151. Arduino Leonardo Bootloader Arduino Leonardo 使用 caterina bootloader ◦透過 USB 直接與 PC 通訊, 省掉 USB to Serial bridge, 降低成本 ◦使用 LUFA library 來進行 USB 通訊 LUFA 是一套 AVR 系列微處理機專用的通訊程式 庫, 支援各種 USB Class caterina 只用到 CDC Class 的功能
  • 152. 與 Bootloader 有關的電路 USB 通訊線 Arduino 主晶片
  • 153. 與 Bootloader 有關的電路 USB 通訊線 USB 電源輸入 USB 接頭
  • 154. Leonardo Bootloader 程式流程 HW init Timer LUFA init 是否有 POWER-ON reset Detach USB 並執行 Arduino F/W 否 是 Timer 中斷設定成每 1ms 觸發 一次, 裡面處理 TX/RX LED 與 bootloader timeout 依命令把 Arduino F/W 寫入 flash, 並重置 timeout count (timeout count > 8000) 把 timeout count 設 定為 7500 等待 timeout timeout count 不累加 Arduino F/W 是否存 在? timeout count ++ 是 否 點滅 TX/RX LED 是否 timerout 是 否 Timer 中斷副程式 Bootloader 主程式 由 USB 接收 Host 命令, 點亮 TX/RX LED 收到 exit bootloader 命令 是 否
  • 155. Bootloader 原始碼重要細節 如果是由 reset button 引 起的 reset, 則進入 bootloader 如果不是軟體 reset, 則直接執行 Arduino F/W 如果是 POWER-ON reset, 則直接執行 Arduino F/W
  • 156. Bootloader 原始碼重要細節 Bootloader main loop 執行 AVR910 通訊協定命令 LUFA library 的 USB 通訊處理 超過 8 秒沒從 host 收到資 料, 則跳出 bootloader 執行 Arduino F/W 執行 Arduino F/W 切斷 USB 連結 (Arduino F/W 會自己再一次進 行 USB 連接行為)
  • 157. Bootloader 原始碼重要細節 Bootloader timer 中斷副程式, 每隔 1ms觸發執行一次 Bootloader 使用的 timerout count 變數
  • 158. Bootloader 原始碼重要細節 AVR910 通訊協定處理函式 指定 USB 資料讀取通道 從 USB 讀取字元 判斷 USB 通道是否有資料存在 如果收到 exit 命令, 則等待 0.5 秒再跳出執行 Arduino F/W 進行 AVR910 通訊協定 的命令處理 (AVR910協定請自行參 考 Atmel 文件: http://www.atmel.com/images/doc0943.pdf)
  • 159. Bootloader 重要函式註解 FetchNextCommandByte ( ) ◦從 USB port 讀取一字元 WriteNextResponseByte ( ) ◦由 USB port 送出一字元 SetupHardware ( ) ◦硬體初始化函式
  • 160. Bootloader 重要函式註解 StartSketch ( ) ◦執行使用者的 Arduino 韌體程式 EVENT_USB_Device_ConfigurationChanged ( ) ◦USB 事件處理 callback EVENT_USB_Device_ControlRequest ( ) ◦USB 事件處理 callback
  • 161. Arduino IDE 對 Bootloader 的操作 IDE 上傳程式的流程 取得要燒錄的檔案所在路徑 和檔案名稱 由板子版本決定燒錄參數 取得燒錄程式路徑與檔名 執行燒錄程式 avrdude.exe 是否燒錄成 功? 對目前的 USB serial port 設定 1200 bps baudrate 後再關閉 等待 bootloader USB serial port 出現 Timeout?(5s) 等待 Arduino sketch USB serial port 出現 將 Arduino sketch USB serial port baudrate 改 成正常值, 並回傳燒錄 成功 Timeout?(2s) 回傳燒錄成功 回傳失敗 回傳失敗 是 否 是 (由 avrdude.exe 的回傳值決定) 否 是 否 Arduino 自行切斷 USB 再重新連線 (IDE 這部分的原始碼等之後的讀 書會再進行詳細解析) (對 Arduino 做軟體 reset)
  • 162. Leonardo 軟體 RESET 機制的實作 在 IDE 上傳 Arduino F/W 之前, 會先將 USB serial port 設定成 1200bps baudrate, 然後再關閉 serial port 上述行為會讓 Leonardo 上的 F/W 對一個 指定記憶體空間填入 bootkey, 然後再自己 reset reset 後進入 bootloader, 會去判斷是否為 軟體 reset (檢查 bootkey), 如果是, 則進入 bootloader main loop 開始接收資料
  • 163. 輕鬆小品, 休息一下~~ 複習 Arduino Bootloader 燒錄
  • 171. 86Duino Bootloader 行為 86Duino Bootloader 只是開機第一個執行 的 DOS 執行檔 行為大部分與 Arduino Leonardo 相同 只有軟體 reset 可以啟動 Arduino 韌體燒 錄機制 ◦Arduino Leonardo 則是軟體 reset 和 reset button 皆會啟動 Adruino 韌體燒錄機制
  • 172. 86Duino Bootloader 行為 86Duino F/W 先整個被接收到記憶體內, 再一次寫入 flash ◦當傳輸過程出錯, 不會破壞原有韌體程式 86Duino F/W 會先燒錄至暫存空間, 成功 後再映射至韌體存放空間 ◦當寫入過程出錯, 不會破壞原有韌體程式
  • 173. Bootloader 原始碼重要細節 86Duinio F/W 最大 SIZE Bootloader timeout 時間 可燒錄的程式類型
  • 174. Bootloader 原始碼重要細節 初始化 I/O port 決定 bootloader 的運作模式 判斷是否有軟體 reset
  • 175. Bootloader 原始碼重要細節 初始化 USB device port 配置存放 86Duino F/W 的記憶體陣列
  • 178. Bootloader 原始碼重要細節 從 USB 接收 86Duino F/W 檔案
  • 180. Bootloader 原始碼重要細節 若是執行 Bootloader 燒錄則 reboot, 反之 則執行 86Duino F/W
  • 181. 初版程式燒錄的 protocol 沒有使用 protocol (未來會新增) 初版是直接傳送特定格式的資料 TYPE Data length Data 1 Byte 4 Bytes N Bytes 1: 檔案是 bootloader 2: 檔案是 user program
  • 182. 86Duino 軟體 RESET 機制的實作 由 IDE 把 USB serial port 開啟為 1200bps baudrate 後再關閉 (與 Arduino Leonardo 相同) 86Duino 收到上述行為後, 會對一個 I/O 空間寫入特定值, 然後自己 reset reset 後進入 bootloader, 判斷上次是否 為軟體 reset, 如果是, 則開始接收新的 F/W
  • 183. Arduino 原始碼讀書會(III) : Arduino IDE 解析
  • 185. 取得 Arduino Source Code 第一種方式: ◦使用 git 軟體 下載: http://git-scm.com/downloads ◦指令: git clone https://github.com/arduino/Arduino.git
  • 186. 取得 Arduino Source Code 第二種方式: ◦直接下載 source code 點選這裡可直接下載
  • 187. ●Arduino IDE Source Code https://github.com/arduino/Arduino ●Cygwin http://cygwin.com/install.html ●Sun Java JDK(Java SE Development Kit) http://www.oracle.com/technetwork/java/javase/downloads/index.html ●Apache Ant Binary Distributions http://ant.apache.org/bindownload.cgi ●git http://windows.github.com/ Windows-下載相關應用程式
  • 188. Setup steps(1) 安裝 Cygwin 安裝 Java JDK 解壓縮apache-ant-x.x.x-bin.zip至 ProgrmFiles
  • 190. Setup steps(3) 在使用者變數裡新增 變數名稱 變數值 ANT_HOME C:Program Filesapache-ant-1.9.2 (apache ant資料夾路徑) JAVA_HOME C:Program FilesJavajdk1.7.0_45 (Java JDK資料夾路徑)
  • 191. Setup steps(4) 在系統變數中 ◦將apache-ant中的bin資料夾路徑加入Path變 數值中
  • 193. Setup steps(6) 將…buildwindows中的jre.zip裡面的java 資料夾解壓縮到…buildwindowswork
  • 194. Linux(Ubuntu)所需的應用程式 ●Sun Java JDK $sudo add-apt-repository ppa:webupd8team/java $sudo apt-get update $sudo apt-get install oracle-java8-installer ●Apache Ant $ sudo apt-get install ant ●avr-gcc, avr-g++, avr-libc $ sudo apt-get install arduino ●Make $ sudo apt-get install make ●(git) $ sudo apt-get install git
  • 195. Setup steps ●$ git clone git://github.com/arduino/Arduino.git ●$ cd ./Arduino/build/ ●$ ant ●$ ant run
  • 196. Mac OSX所需要的應用程式 ●Java for OSX http://support.apple.com/kb/dl1572 ●(git) –$ sudo port selfupdate –$ sudo port install git-core
  • 197. Setup steps ●$ git clone git://github.com/arduino/Arduino.git ●$ cd ./Arduino/build/ ●$ ant ●$ ant run
  • 198. 開胃小菜: Arduino IDE Hacking Tips
  • 200. 切換到 1.5.x 分支 1.5.x 支援 Arduino Due, Yun, …
  • 201. Arduino 原始碼根目錄 改過的 Processing IDE 原始碼 (Arduino 相關) Processing IDE 原始碼 存放編譯結果的目錄 Arduino Bootloader, Standard API 原始碼 Arduino Library 原始碼
  • 202. App →src →processing →app Arduino 編譯、燒錄相關程式碼 前置處理的相關程式碼, 例如: 字串轉換… Arduino IDE 選單、按鈕功能程式碼 處理Sketch.ino 相關程式碼
  • 203. App →src →processing →app →preproc 處理字串問題程式碼
  • 204. App→src →processing→app→ debug Arduino 編譯相關程式碼
  • 206. App →src →processing →app 語言設定檔的位置 中英說明文件 (修改後沒有效果) 英轉中 編碼轉換設定檔
  • 207. 修改中文顯示訊息 Resources_zh_tw.po Resources_zh_tw.properties 英文字串 Open… 替換成 開啟… (unicode 編碼)
  • 208. 修改範例 修改後重新編譯 IDE 即可看到結果 中文: 我愛Fablab (unicode)
  • 209. 在下拉式選單新增選項 新增 Burn Bootloader 子選單 新增 Arduino Bootloader 項目 選項動作 callback 修改 Editor.java 的 buildToolsMenu( ) Example: 新增 86Duino Bootloader 項目 修改結果:
  • 210. 在 hardware 下新增資料夾。 Ex: 86Duinox86 資料夾底下需要這幾個資料夾和檔案 以上這些檔案不需重新編譯 Arduino IDE,只需新 增檔案並且重新開啟 Arduino IDE 即可看到效果。 添加 Arduino 相容板 bootloaders libraries 編譯、上傳參數 設定 standardAPI Arduino 相容板 子的各種參數
  • 211. 添加 Arduino 相容板 boards.txt platform.txt 設定板子名稱 設定板子相關參數 設定板子選單名稱
  • 212. 添加 Arduino 相容板 尚未添加板子前 boards 選單 添加後的 boards 選單
  • 213. 存放 UI 外觀圖檔及設定檔的路徑: buildsharedlibtheme 修改 UI 外觀顯示
  • 214. UI 設定檔 theme.txt 文件內容
  • 215. 更換 IDE 的啟動 logo 直接修改或更換此檔案,並且重新編譯Arduino IDE,編 譯完成即可看到更改後圖案。
  • 216. 修改 IDE 顯示版本號 修改此字串並重新編譯, 即可更換 IDE 顯示的版本號 build.xml 內容
  • 217. 修改 IDE 顯示版本號 修改的版本號:~1.5.4^^
  • 218. 修改 IDE 視窗左上角小圖示 打開 Papplet.java 檔
  • 219. 修改 IDE 視窗左上角小圖示 把 ICON_IMAGE 陣列內容換成 想換的小圖示, 格式必須為 GIF
  • 220. 修改 IDE 視窗左上角小圖示 IDE 視窗 Serial monitor 視窗 修改結果: 修改後重新編譯 IDE 即可看到效果
  • 223. IDE 視窗 按下編譯按鈕主要做了三個動作: 1. 產生暫存資料夾 (Sketch.java) 2. 前處理 Sketck.ino 檔 (PdePreprocessor.java) 3. 編譯 Sketck.ino 檔 (Compiler.java)
  • 224. App →src →processing →app Arduino 編譯、燒錄相關程式碼 處理字串問題相關程式碼 Arduino IDE 選單、按鈕功能程式碼 處理Sketch.ino 相關程式碼
  • 225. 產生存放編譯結果的暫存資料夾 處理 Sketch.ino檔 並開始編譯 Editor.java – DefaultPresentHandler( )
  • 226. App →src →processing →app Arduino 編譯、燒錄相關程式碼 處理字串問題相關程式碼 Arduino IDE 選單、按鈕功能程式碼 處理Sketch.ino 相關程式碼
  • 227. 前處理 Sketch.ino檔案 找出 .ino 和 .pde 檔 在 .ino/.pde 檔中加入檔頭修正 (請參考第 1 次讀書會內容) Sketch.java - preprocess( ) 修改Sketch.ino 檔案
  • 228. App →src →processing →app →preproc Sketch 前處理的程式碼
  • 229. 前處理 Sketch.ino檔案 PdePreprocessor.java – writeProgram( ) 在 .ino/.pde 檔中加入 #include “Arduino.h ” 加入函式原型宣告 加入行號修正
  • 230. 原始 skecth 被 IDE 改寫的 skecth Sketch 處理前後之差異
  • 231. 找出 sketch 內呼叫的 libraries 找出 include 的 library PdePreprocessor.java – writePrefix( )
  • 232. App→src →processing→app→ debug Arduino 編譯相關程式碼
  • 233. Sketch 編譯流程重點講解 取得暫存資料夾路徑 取得libraries路徑 Compiler.java - compile( )
  • 234. Sketch 編譯流程重點講解 編譯Sketch.ino 編譯libraries 編譯standardAPI 產生.elf檔 產生.eep檔 產生.hex 執行檔 並結束編譯
  • 235. Sketch 編譯流程重點講解 Compiler.java - compileSketch( ) 呼叫 CompileFiles 執行 sketch 編譯
  • 236. Sketch 編譯流程重點講解 Compiler.java - compileLibraries( ) 讀取所有被 include 的 libraries 在 tmp 建立 library 資料夾 在 library 資料夾 底下建立 utility 資料夾 編譯 library 編譯 library 底下 utility
  • 237. Sketch 編譯流程重點講解 Compiler.java - compileCore( ) 讀取 standaAPI 路徑 讀取 variant 資料夾路徑 編譯 standaAPI 編譯 variant 資料夾下的 檔案 取得 .a 檔編譯 pattern 編譯 .a 檔 加入編譯 .a 檔參數
  • 238. 產生編譯.s檔案的 gcc 命令 執行avrgcc Compiler.java - compileFiles( ) Sketch 編譯流程重點講解
  • 239. Sketch 編譯流程重點講解 產生編譯 .c檔案的 gcc 命令 產生編譯 .cpp檔案的 gcc 命令 執行 avrgcc 執行 avrgcc
  • 240. Sketch 編譯流程重點講解 將編譯結果顯示到 IDE 訊息框內 開新的 process 執行avrgcc 命令 Compiler.java - execAsynchronously( )
  • 241. 配菜: 加入 86Duino 程式編譯 對 IDE 所做的修改
  • 242. 86Duino 編譯系統 DOSBox + DJGPP DOSBox 是一個跨平台的 DOS 模擬軟體 ◦在 IDE 的路徑: buildwindowsworkDOSBox-0.74 DJGPP 是一個可在 DOS 下編譯程式的 GNU gcc ◦在 IDE 的路徑: buildwindowsworkDJGPP
  • 244. 86Duino原始碼重要細節 如果使用者選的板子是 86Duino, 則跳到 duinocompiler.java 編譯 Compiler.java - compile( )
  • 247. 86Duino原始碼重要細節 Dosbox config設定 Makefile 設定 設定 DOSBox 執行命令 將編譯訊息寫到 MESSAGE.TXT DuinoCompiler.java - compile( )
  • 249. 86Duino原始碼重要細節 設定編譯命令參數 將之前Makefile設定 讀取進來並編譯 DuinoCompiler.java - writeMakefile( )
  • 251. 實作燒錄的 IDE 原始碼: app→src → processing → app → debug 本次解析目標 處理 Arduino 程式燒錄動作 處理 Arduino 程式燒錄動作
  • 252. Arduino 程式燒錄設定檔 hardware→arduino→avr 分別簡要介紹 定義 boards 選單、編譯及燒錄參數 定義編譯及燒錄參數 本次解析目標
  • 253. 燒錄設定檔的用途 Arduino IDE 在燒錄程式之前, 會從燒錄設定 檔讀取與板子相關的燒錄參數 這些設定檔中, 使用一種特定的格式, 記錄了 每塊 Arduino 板子的差異, 例如: ◦CPU時脈、燒錄的 protocol、燒錄檔案的最大 size 等等 只要推出一片新的板子, 依照指定的格式加入 新參數, 就可以直接套用到目前的 IDE, 不需 要重新編譯程式
  • 254. boards.txt 格式: 以 Leonardo 為例 要在 Boards 選單上顯示的名稱 燒錄工具程式檔名 燒錄用的 protocol 允許燒錄的 binary 最大 size 燒錄用的 baudrate 板子名稱 燒錄 sketch 的參數設定 燒錄 bootloader 的參數設定 設定燒錄時 IDE 清空 serial data 值 設定燒錄時用 1200 baudrate 來 reset Arduino 設定 reset Arduino 後要等待 upload port 出現才可進行燒錄 這次讀書會不講燒錄 bootloader 部分
  • 255. boards.txt 格式: 以 Leonardo 為例 板子名稱 編譯 sketch 的相關參數 Leonardo 的 CPU 型號( 燒錄會用到的參數)
  • 256. platform.txt 的格式: 以 Leonardo 為例 在 linux 下, 燒錄工具程式的位置以及燒錄 config 檔的位置 在 windows 和 Mac 下, 燒錄工具程式的位置以及燒錄 config 檔的位置
  • 257. platform.txt 格式: 以 Leonardo 為例 IDE 燒錄程式時下 的命令列參數 燒錄過程中會被替換成正確參數
  • 258. 實際燒錄一次, 看看輸出訊息 燒錄程式 Avrdude config 檔 Leonardo CPU COM port 燒錄 baudrate 要燒錄的檔案 protocol
  • 259. IDE 執行燒錄的機制 執行 avrdude 燒錄命令 取得 sketch binary 檔路徑 Reset Arduino 使用 serial bootloader 的板子, 例如: UNO … 使用 usb bootloader 的 板子, 例如: Leonardo 詳細流程請參考第 2 次 Arduino 原始碼讀書會內容 設定正確的板子 燒錄參數 BasicUploader.java 是否需要 reset Arduino board Uploader.java 是 否 等待 upload port 出現
  • 260. 燒錄工具程式 Avrdude 簡介 普遍用來燒錄 Atmel AVR 的工具程式 跨多種平台, Windows, FreeBSD, linux, UNIX … 使用命令列來完成燒錄動作 參考資料 ◦馬大的 Avrdude GUI 教學 http://www.coopermaa2nd.blogspot.tw/2011_06_01_archive.html ◦詳細的 avrdude 命令, 可見 AVR Tutorial: http://www.ladyada.net/learn/avr/avrdude.html ◦Avrdude 原始碼 https://github.com/arduino/avrdude
  • 261. Avrdude 程式放在哪? Windows/Mac : hardwaretoolsavrbin
  • 264. BasicUploader.java → Class BasicUploader → uploadUsingPreferences() 取得目前 Serial USB port 對 upload port 設定 1200 baud 再關閉 (soft-reset Arduino) 如果設定要等待 upload port 出現 如果設定 1200 baudrate reset → 執行 USB bootloader 燒錄流程 取得 user 設定的 upload port 等待 Arduino reset 完畢, 重新 取得 upload port (見下頁)
  • 265. BasicUploader.java → Class BasicUploader → waitForUploadPort() Timeout 時間: 20 秒 找出 Arduino reset 後, 重 新連線的 upload port 如果找到 upload port 如果沒有找到 upload port, delay 250ms 再重新尋找 如果超過時限未找到新 upload port (win: 10 秒, 其他: 500ms), 且 user 選擇的 upload port 並未消失, 則回傳 user 選擇的 upload port 將找到的 upload port 回傳
  • 266. 回到 BasicUploader.java → Class BasicUploader → uploadUsingPreferences() 取得燒錄程式用的命令列pattern 設定正確的命令列參數 執行 avrdude 燒錄工具 程式(見下頁)
  • 267. Uploader.java → Class Uploader→ executeUploadCommand () 開新的 process 執行燒錄命令 將編譯結果顯示到 IDE 訊息框內 等待燒錄 process 執行完畢 檢查燒錄是否燒 錄成功
  • 268. 回到 BasicUploader.java → Class BasicUploader → uploadUsingPreferences() 如果設定要等待 upload port 出現 檢查 upload port 是否出現, timeout = 2s 如果找到 upload port 將 upload port 設定 回 9600 baudrate
  • 269. 點心: 加入 86Duino 程式燒錄 對 IDE 所做的修改
  • 273. 修改 BasicUploader.java 加入板子判斷 根據 86Duino 修改燒錄參數
  • 274. 將燒錄工具程式放到 IDE 指定資料夾下 燒錄工具程式必須依不同的平台而放在不同 的目錄(下頁說明) 在 build IDE source code 的過程, 燒錄工具程 式會自動被移到 IDE 規定的執行時期位置 ( 詳見 build.xml 中的設定)
  • 275. Case 1: Windows XP/7/8 將 window 版的 86Duino 燒錄工 具壓縮至 avr_tool.zip 裡面
  • 276. Case 2: Mac OS X 將 MAC 版的 86Duino 燒錄工具 壓縮至 avr_tool.zip 裡面
  • 277. Case 3: Linux 將 Linux 版的 86Duino 燒錄工具 複製到此資料夾下
  • 278. 燒錄工具程式的一點開發經驗 在 ubuntu 遇到的問題 ◦在 ubuntu 11.04 版本及之後的版本, 內建的 modem manager 會干擾 USB CDC 裝置的傳輸 ◦https://bugs.launchpad.net/ubuntu/+source/modemmanager/+bug/1153632/+activity ◦這會造成燒錄程序被干擾而失敗 ◦解決方式: 將 USB CDC 裝置的 PID 和 VID 加入 modem manager 的忽略清單
  • 279. 燒錄工具程式的一點開發經驗 在 Mac OS X 遇到的問題 ◦USB CDC 裝置的 Call Management Functional Descriptor 中的 最後一個 data 必須為 0x01, 否則 Mac 會認不到 USB CDC 裝 置 ◦http://stackoverflow.com/questions/5009593/acessing- a-serial-to-usb-device-with-i-o-kit
  • 280. 燒錄工具程式的一點開發經驗 在 Mac OS X 遇到的問題 (cont.) ◦USB CDC 裝置的 Configuration Descriptor 中不可 宣告 remote wakeup 功能, 否則會大大延長 Mac 辨 識此 USB CDC 裝置的時間
  • 281. Arduino 原始碼讀書會(IV) : Arduino Standard Libraries 重點解析 (上)
  • 283. TWI 介面 TWI 全名: Two Wire Interface Atmel 當初是為了避免侵犯 I2C 的註冊 商標, 特將此介面命名為 TWI 在傳輸資料上仍為 I2C 協定
  • 284. 認識 I2C 介面 它是由 Philips 公司在 1980 年時期,為 了方便同一個電路板上的各個組件互相 通信,而開發出來的一種介面 全名: Inter-Integrated Circuit I2C 介面只用兩條訊號線來連接其他元 件: ◦SDA (資料線) ◦SCL (時脈線)
  • 285. I2C 元件的連接方式 圖片出處:http://en.wikipedia.org/wiki/I%C2%B2C Master 端:通 常是微處理器, 負責發送時脈和 slave 位址 Slave 端:通常是感測器元 件 (或其他微處理器),每個 元件都有自己的位址 Pull-up 電阻:由於 I2C 採 open-drain 設計,master 端若需要 送出 HIGH 信號,必須靠上拉電阻接 Vdd,讓信號線電位呈現 HIGH 狀態
  • 286. 詳細的 I2C 通訊協定 I2C 的通訊協定較為複雜, 此次讀書會 不詳細說明, 有興趣的朋友可以參考下 面的連結內容: ◦Wiki: http://en.wikipedia.org/wiki/I%C2%B2C
  • 287. Arduino Leonardo 的 TWI 輸出腳位 SCL 和 SDA 與第 2, 3 腳位共用
  • 288. Arduino Uno 的 TWI 輸出腳位 R3 版本後, 額外拉出 SDA 和 SCL 腳位 (與 A/D第 A4, A5 腳 位共用)
  • 289. I2C 連接範例: 使兩塊 Arduino Uno 可以互相傳輸資料 圖片出處:Arduino 互動設計入門 旗標出版
  • 291. Wire.begin() 函式功能: ◦初始化 I2C 硬體 ◦把 Arduino 當 I2C master
  • 292. Wire.begin(address) 函式功能: ◦初始化 I2C 硬體 ◦除了把 Arduino 當 master 之外, 也啟動 I2C slave 功能 Slave 位址使用傳入的 address 參數 (注意必需為 7-bit 位址) 當 Arduino 在 I2C Bus 上收到 address 時, 會進入 slave 模式
  • 293. Wire.beginTransmission(address) 函式功能: ◦用來啟始 I2C master 的資料傳輸 ◦address 指定外部 I2C slave 裝置的位址 (7- bit) 注意: Wire.beginTransmission() 的參數必須輸入 7-bit 形式的 slave address, 但市面上有些產品開發商只提供 8-bit slave address, 使用者必須自行轉換成正確的形式 例如: 廠商提供的 8-bit address 是 0x6A, 轉換成 7-bit 後, 值是 0x35, 然後將 0x35 填入 Wire.beginTransmission() 中
  • 294. Wire.write(value) Wire.write(data, length) Wire.write(string) 函式功能: ◦當 Arduino 是 I2C master 時: 傳送資料給 slave 端 資料會先寫入內部 master queue, 再由中斷副程 式傳送出去 ◦當 Arduino 是 I2C slave 時: 回應資料給 master 端 資料會先寫入內部 slave queue, 再由中斷副程式 傳送出去
  • 295. Wire.endTransmission() Wire.endTransmission(stop) 函式功能: ◦結束資料傳輸動作 啟動中斷副程式, 把 master queue 中的資料傳送 出去 ◦若沒有 stop 參數, 則資料送完後發 I2C STOP 信號 ◦若 stop 參數為 true, 則資料送完後改發 I2C RESTART 信號
  • 296. Wire.requestFrom(address, quantity) Wire.requestFrom(address, quantity, stop) 函式功能: ◦用來起始 I2C master 的資料讀取程序 address 是要讀取的 I2C slave 裝置位址 quantity 是要讀取的位元組個數 ◦將啟動中斷副程式讀取所需要的資料並存 放在內部的 rx queue 中 使用者可調用 Wire.read() 取出 rx queue 中的值 ◦stop 參數功能與上頁相同
  • 297. Wire.read() 函式功能: ◦從 rx queue 中取出一個 byte ◦假如 rx queue 中沒有值, 會得到 -1
  • 298. Wire.avairlable() 函式功能: ◦回傳 rx queue 中還未讀的 byte 數
  • 299. Wire.onReceive(myHandler) 函式功能: ◦用來掛載 I2C slave 模式下的 callback function (myHandler) ◦當 Arduino 在 I2C slave 模式下收到 master 端的資料後, 會調用此 callback function
  • 300. 使用範例: 透過 I2C 連接兩片 Arduino UNO 連接方式:
  • 301. Master 端 Slave 端 使用範例: 透過 I2C 連接兩片 Arduino UNO Slave 端要設 定位址 Master 端要 送出去的位址 兩 者 要 一 樣
  • 302. 把程式個別燒入 UNO 後, 可以在 slave 端的 serial monitor 上看到 master 端傳過來的字串 使用範例: 透過 I2C 連接兩片 Arduino UNO 圖片出處:Arduino 互動設計入門 旗標出版
  • 304. Wire 函式庫資料夾內容 Wire 資料夾 utility 資料夾 Wire 函式庫的原始碼 硬體相關的程式原始碼
  • 305. Wire 函式庫實作架構 Wire.cpp: ◦實作對外的 API 介面 ◦透過 twi.c 傳送和接收資料 twi.c: ◦操縱 ATmega TWI (I2C)硬體 暫存器, 以中斷服務常式 (ISR) 處理傳送/接收資料的行為 Wire lib TWI lib Arduino TWI hardware ISR queue
  • 306. Wire 函式庫原始碼重要細節 設定 Arduino I2C 裝置 的 slave 位址 掛載 callback function 初始化 Arduino I2C 硬體 Wire.cpp:begin()
  • 307. Wire 函式庫原始碼重要細節 Wire.cpp:requestFrom() 調用 twi.c 中的 function, 將取得的 值放到 rxbuffer 陣列中 回傳讀到的總數
  • 308. Wire 函式庫原始碼重要細節 Wire.cpp:write() Wire.cpp:read() Master 模式 Slave 模式 把資料寫到 txbuffer 陣列 從 rxbuffer 陣列中讀值
  • 309. Wire 函式庫原始碼重要細節 Wire.cpp:beginTransmission() 以及 endTransmission() 此時才真正把 txbuffer 中的值寫出去 賦予變 數初值 預設為 master 模式
  • 310. Wire 函式庫原始碼重要細節 Wire.cpp:onReceiveService() 掛載 callback function 把中斷副程式中收到的陣 列內容拷貝到 Wire.cpp 中的 buffer 重置 read() 會用到的變數 調用 user 的 callback function
  • 311. Wire 函式庫原始碼重要細節 Wire.cpp:onRequestService() 掛載 callback function 調用 user 的 callback function
  • 312. twi.c:twi_readForm() 操作 I2C 暫存器, 開始從 I2C Bus 上讀值 等待讀值過程結束 把讀到的值存到 目標陣列 初始化相關變數 I2C 硬體仍忙碌時, 循環等待 設置外部 slave 位址以及讀取命令
  • 313. twi.c:twi_writeTo() 操作 I2C 暫存器, 開始對 I2C Bus 上寫值 等待寫值過程結束 回傳寫值過程的結果 初始化相關變數 I2C 硬體仍忙碌時, 循環等待 設置外部 slave 位址以及寫命令
  • 314. twi.c:中斷副程式 不同的 I2C 硬體狀態 (狀態暫存 器內的值) 掛載中斷副程式 中斷副程式主要運作方式: 發生某種狀態, 就做對應的事情 繼續送下一個 byte 發生錯誤的處理方式 送 stop condition 送 restart condition
  • 315. Wire 函式庫的移植: 以 86Duino 為例
  • 316. Wire 在 86Duino 上的移植 與硬體無關的 code: ◦例如: Wire.cpp ◦可以直接拿來用, 不用修改 (或者做些把 queue buffer 加大等小改進) 與硬體相關 code: ◦例如: twi.c ◦根據硬體暫存器之間的規格差異, 移植難度也不同 ◦86Duino I2C 硬體暫存器設定與 ATmega TWI 頗為 相似, 因此移植時需要修改的地方並不多
  • 317. 86Duino twi.c:中斷副程式 Master 完成 傳送位址、 資料的狀態 取得 I2C 狀態 暫存器的值 假如要從 I2C Bus 上讀值 讀值的 操作 過程 使 I2C 硬體開始 讀值 送 stop condition 等待讀值過程結束 讀最後一筆
  • 318. 86Duino twi.c:中斷副程式 (續) 把 1 byte 寫到 I2C BUS 上 寫值的 操作 過程 其它部分的移植方法都是相同概念: 把硬體暫存器的存取改成 Vortex86EX 的版本 送 stop condition 送 restart condition 假如是最後一筆
  • 320. RC Servo 簡介 Radio Control Servo Servo 是一個整合馬達、減速機、控制 驅動的系統, 可根據外部命令, 控制馬達 轉到目標角度或速度
  • 321. RC Servo 的應用領域 在遙控模型(遙控車、 遙控飛機)上, 用來控制 遙控模型的姿態和移動 方向 RC Servo 目前也廣泛應用在機器 人領域, 做為機器人的 關節致動器
  • 322. RC Servo 的組成 圖片出處:Arduino 開發實戰指南 機械工業出版社 基本功能: 接收主控器傳過來的目標位置信號, 與目前馬達位 置比較後, 以 PID 方式, 控制使馬達轉到目標位置 用來測量馬達 的轉動角度 用來放大直流馬達的扭力
  • 323. 常見的 RC Servo 控制信號 主流為 PWM, 部分機器人專用伺服機則 採用 RS232 或 RS485 Arduino 的 Servo 函式庫只以 PWM 命 令的 RC Servo 為控制對象 生產公司 RC Serco 的通訊方式 Robotics(韓國) RS232、RS485 KONDO (日本) PWM、RS232 祥儀 (台灣) PWM 廣營 (台灣) PWM TOWERPRO (大陸) PWM
  • 324. PWM 信號(Pulse Width Modulation) 全名為脈波寬度調變 如下圖所示: Duty Cycle: 在一個週期中, HIGH 電位的 時間所占的比 例 Period: 即一個 PWM pulse 的週期
  • 325. PWM 信號與 RC Servo 位置關係圖 使用 PWM duty 的寬度來控制 servo 的轉動角度: duty 範圍通常介於 700us ~ 2300us 之間 PWM 週期通常為 20ms 圖片出處:Arduino 開發實戰指南 機械工業出版社
  • 326. 用 Arduino 連接 RC Servo 電源線 接地 PWM 信號線 PWM servo 連接線:
  • 328. Servo.write(angle) 函式功能 ◦輸出指定 duty 寬度的 PWM 信號 ◦參數 angle 可以輸入 0 ~180, 代表轉動角度 也可以輸入實際的 duty 時間值, 例如: 800, 1500 等數值, 單位是 us
  • 329. Servo Lib 使用範例: 讓 RC Servo 來回轉動 實際運行結果影片:
  • 331. Servo 函式庫實作 實作概要: ◦使用軟體設定 I/O pin HIGH/LOW 的方式模擬 PWM 信號 ◦HIGH/LOW 時間長短由 Timer 中斷所控制 ◦Arduino 1 個 Timer 最多控制 12 個 PWM channels ◦超過 12 channels, 則需要用到更多 Timer (某些 Arduino 版子只能支援 12 channels) Servo 函式庫會與 analogWrite() 衝突, 通常不 能同時使用 Servo Lib 每個 channel 結構 Timer 中斷副程式 GPIO 輸出
  • 332. 多個 channels 的 PWM 輸出 你可能以為是這樣: ‧ ‧ ‧ Channel 1 Channel 2 Channel n 20ms (PWM period)
  • 333. 實際上, Arduino 是這樣輸出的: 多個 channels 的 PWM 輸出 ‧ ‧ ‧ 20ms Channel 1 Channel 2 Channel 3
  • 334. 假設平均 duty 是 1500us (Servo 中點), 則有 20ms / (1500us+ISR overhead)  12 如果所有 12 channels 都輸出最大 duty 2400us, 則 PWM period 會超過 12 x 2400us = 28.8ms ◦若你使用的 RC Servo 不允許超過 20ms 的 PWM 週期, 則需注意 Servo 函式庫此特性
  • 335. Servo Lib 的運作架構 建構 Servo 物件 設定 channel Timer 中斷副程式 初始化 Timer Servo.attach() 更新 channel 的 duty 值 Servo.write() 有下一個 channel? 目前時間是 否超過 20ms? 將此 channel 設 HIGH 並且設定下一次進入 中斷的時間 = duty 設定下次進入中斷的 時間為 2us 後 設定下一次進入中斷的 時間 = 20ms – 目前時間 新的 20ms 周期開始? 將原 channel 設 LOW 否 是 否 否 是 是 宣告 Servo
  • 336. Servo Lib 原始碼重要細節 Servo.cpp 中的 attach() 函式 若是第一次使用此 Timer 初始化Timer 中斷 取得 servo pin 對應的 timer 編號
  • 337. Servo Lib 原始碼重要細節 Servo.cpp 中的 write() 函式 若輸入的值小於 544 把值 map 到 544 ~ 2400 調用 writeMicroseconds 把值傳給中斷副程式 中會用到的變數 把 us 轉成 Timer 單位
  • 338. Servo Lib 原始碼重要細節 將原 channel 輸出 LOW 若是新的周期開始, 就重置 Time counter 指向下一個 channel Servo.cpp 中的 Timer 中斷程式碼 將此 channel 設 HIGH 假如沒有可用的 channel 設定 Timer = duty 目前時間超過 20ms, 將下次中斷時間設成 2us 後 若目前時間還小於 20ms, 將下次中斷時間設成 20ms
  • 339. 因為用軟體模擬 PWM, 所以實際輸出的 PWM duty 時間會有抖動現象 (jitter) 當使用的 PWM channel 超過 12 組, Arduino 會啟用更多組 Timer, 多個 Timer 中斷彼此干擾, 有時會惡化 PWM jitter 現象
  • 340. Servo 函式庫的移植: 以 86Duino 為例
  • 341. Servo 函式庫在 86Duino 上的 實作改良 用新的算法在 20ms 內模擬更多 PWM channels 支援硬體 PWM 功能的 I/O pin, 直接以硬體功 能輸出 PWM 信號  以一個 Timer 中斷支持最多 45 個 PWM channels
  • 342. 接上 32 顆 RC Servo 的 Demo + = 32 channels RC Servo Demo 影片: 86Duino ONE Arduino sensor shield 18 channels 14 channels https://www.youtube.com/watch?v=1H72d62AB08
  • 343. 86Duino Servo 函式庫的 PWM 輸出 ‧ ‧ ‧ 20ms Channel 1 Channel 2 Channel 3 Channel n
  • 344. PWM 模擬算法概要 排序所有 channels 的 duty 值 根據 duty 大小的排序, 依序在對應的 I/O pin 上輸出 PWM 同時在兩個 I/O pin 上輸出 PWM 波型 使用 Vortex86EX event trigger 功能縮小由於 interrupt latency 造成的 PWM jitter
  • 345. Servo.cpp 中的 attach() 函式 初始化硬體 PWM pin 初始化以軟體模擬的 PWM pin
  • 346. Servo.cpp 中的 writeMicroseconds() 函式 更新排序內容, 然後把結果複製到 A 排序陣列中 若是第一次更新, 初始 化 B 排序陣列 啟動 Timer
  • 347. Servo.cpp 中的中斷副程式 外部非正在更新排序 排序方式有被更新過 交換排序陣列 A, B 的 指標, 完成資料更新 週期結束 啟動下一個週期
  • 348. Servo.cpp 中的中斷副程式(續) 若是最後的 pin, 將它設定為 LOW, 結束 PWM 週期 若是倒數第二 pin, 將自己設定為 LOW, 不啟動下一個 pin 若都以上條件都不滿足, 就把目前 pin 設定為 LOW, 把下一個 pin 設定為 HIGH
  • 349. PWM Duty 抖動現象 由於在 Servo 函式庫裡 PWM 是用軟體模擬 的方式來實現, 所以實際輸出的 duty 會有抖 動現象 因抖動造成的誤差範圍與 CPU 特性及軟體模 擬算法有關 抖動現象
  • 350. 以 Arduino UNO 為例, 觀察 PWM 抖動情況 + 示波器 Arduino UNO 波型抖動 實況影片:
  • 351. PWM 抖動現象的影響 在命令解析度比較高的 RC Servo 上, 會造成 servo 輸出軸實際的抖動 一般模型用的低價 RC Servo 解析度較低, 受 PWM 抖動現象的影響不大 Arduino UNO + KONDO KRS4014 servo Servo抖動 實況影片
  • 352. 在 Arduino 和 86Duino 上只使用 1 個 servo pin, 並量測輸出的 PWM duty 與目標值的誤 差, 所測得的數據如下表所示: 各板子的 PWM Duty 抖動實測 板子 目標 duty 實際量測值 duty 誤差範圍 最小 最大 Arduino UNO 1000 us 1000.04 us 1006.42 us 約 6 ~ 7 us Arduino Leonardo 1000 us 1000.04 us 1007.92 us 約 7 ~ 8 us Arduino DUE 1000 us 998.200 us 998.280 us 約 1 ~ 2 us Arduino Mega2560 1000 us 1001.12 us 1008.87 us 約 8 ~ 9 us 86Duino 1000 us 998.64 us 1001.1 us 約 1 ~ 2 us ** ** 在 86Duino 有標註硬體 PWM 功能的 I/O pin 上, 誤差則是 0
  • 353. 在 Arduino DUE / Mega2560 和 86Duino 上啟 用 45 組 servo pins, 並量測其中一個 pin 輸出 的 PWM duty 與目標值的誤差, 所測得的數據 如下表所示: 各板子的 PWM Duty 抖動實測 板子 目標 duty 實際量測值 duty 誤差範圍 最小 最大 Arduino DUE 1000 us 998.05 us 1004.68 us 約 2 ~ 5 us Arduino Mega2560 1000 us 1001.09 us 1076.96 us 約 1 ~ 77 us 86Duino 1000 us 998.70 us 1001.31 us 約 1 ~ 2 us Arduino 的 Servo 函式庫在超過 12 組 channels 時, 會啟用 2 組以上 Timer 中斷, 以上表格可以看出多組 Timer 中斷互相影響所造成的 jitter 惡化情形
  • 356. Firmata Examples ◦Simple Analog Firmata ◦Servo Firmata Firmata.h Firmata.cpp Boards.h
  • 357. Firmata •Examples –Simple Analog Firmata –Servo Firmata •Firmata.h •Firmata.cpp •Boards.h
  • 359. Firmata •Examples –Simple Analog Firmata –Servo Firmata •Firmata.h •Firmata.cpp •Boards.h
  • 361. Firmata •Examples –Simple Analog Firmata –Servo Firmata •Firmata.h •Firmata.cpp •Boards.h
  • 366. Firmata •Examples –Simple Analog Firmata –Servo Firmata •Firmata.h •Firmata.cpp •Boards.h
  • 376. Firmata •Examples –Simple Analog Firmata –Servo Firmata •Firmata.h •Firmata.cpp •Boards.h
  • 382. Firmata @ 86Duino •Examples –Simple Analog Firmata –Servo Firmata •Firmata.h •Firmata.cpp •Boards.h
  • 385. SD卡的傳輸模式 SPI ◦Chip Select, Clock, MISO, MOSI 1-bit SD data transfer mode ◦Command, Clock, DATA0 4-bit SD data transfer mode ◦Command, Clock, DATA0, DATA1, DATA2, DATA3
  • 387. SD ./Examples ◦Files.ino ◦Datalogger.ino ./utility →檔案系統 SD.h SD.cpp →開關存取SD卡 File.cpp →開關存取檔案
  • 388. SD •./Examples –Files.ino –Datalogger.ino •./utility •SD.h •SD.cpp •File.cpp
  • 389. #include <SPI.h> // Arduino透過SPI介面連接SD卡 File myFile; //建立一個自己的File物件 SD.begin(); //開啟SD卡
  • 390. SD.open(“example.txt”, FILE_READ); //從頭開始讀 SD.open(“example.txt”, FILE_WRITE); //從尾繼續寫
  • 392. SD •./Examples –Files.ino –Datalogger.ino •./utility •SD.h •SD.cpp •File.cpp
  • 396. SD •./Examples –Files.ino –Datalogger.ino •./utility •SD.h •SD.cpp •File.cpp
  • 397. SdFile.cpp SdVolume.cpp FAT檔案系統 Sd2Card.cpp SD卡讀/寫指令、寫入資料 SPI.cpp 透過SPI模式對SD卡存取
  • 398. SD •./Examples –Files.ino –Datalogger.ino •./utility •SD.h •SD.cpp •File.cpp
  • 404. SD @ 86Duino 86Duino透過作業系統運作,SD卡為系統磁 碟 86Duino的作業系統內就有FAT檔案系統 86Duino利用stdio.h內的FILE structure來存取 檔案 86Duino使用4-bit模式與SD卡連接
  • 405. SD @ 86Duino •File.cpp •SD.h •SD.cpp
  • 409. fseek 移至檔案的某個特定位置 ftell 取得目前在檔案內的位置 fclose 關閉檔案
  • 413. EEPROM 簡介 EEPROM, 或寫作E2PROM, 全稱電子 抹除式可複寫唯讀記憶體, 是一種可以 通過電子方式多次複寫的半導體存儲設 備 Arduino EEPROM 大小: ◦ATmega328 : 1024 Byte ◦ATmega168, ATmega8 : 512 Byte ◦ATmega1280, ATmega2560 : 4K Byte
  • 414. EEPROM 函式 EEPROM.read(address) ◦從 address (位址)讀取值出來  EEPROM.write(addr, val) ◦將 val (數值)寫到 addr (位址)
  • 415. EEPROM 函式庫範例 從EEPROM讀 值 寫值到EEPROM
  • 417. EEPROM 函式庫原始碼重要細節 呼叫 AVR EEPROM 函式庫從 EEPROM 讀值 引用 Atmel 官方提供的 AVR EEPROM 函式庫 呼叫 AVR EEPROM 函式庫寫值到EEPROM EEPROM 是 Arduino 標準函式庫裡實作最簡單的一個  但不代表容易移植
  • 419. 叫我移植這麼簡單的 EEPROM Lib ??? 我覺得我被輕視了… 苦主 RD
  • 420. 什麼! 86Duino 沒有 EEPROM! 這麼爛的板子是誰做的啊! 苦主 RD
  • 421. 開個檔案模擬 EEPROM 讀寫, 十分鐘搞定, 嘿嘿... 苦主 RD 這樣是嚇不倒 我滴!
  • 422. 結果在測試了 EEPROM 的 官方範例之後…86Duino 就葛屁了(DOS 檔案系統損 毀) Orz
  • 423. 以檔案模擬 EEPROM 的問題 若 86Duino 在寫入檔案時, 被斷電或重 置… ◦輕則檔案資料遺失 ◦重則整個檔案系統損毀 需要設計一個不 怕斷電與重置的 演算法… 苦主 RD 嗚嗚, 只好 重寫了~~
  • 424. 86Duino 兩種實現 EEPROM 等價功能的 方法 方法一: 利用板上 CMOS 記憶體 ◦優點: 速度快, 程式簡單, 讀寫時不怕 CPU 斷 電 ◦缺點: 容量只有 200 bytes, 移除 86Duino 板 上 RTC 電池會使資料遺失 方法二: 利用 BIOS flash 的剩餘空間 ◦優點: 容量可達 16 KB, 不需電池仍可保存資 料 ◦缺點: 速度較慢, 需設計容錯算法避免讀寫 時斷電的資料損毀  實作較複雜
  • 426. CMOS 方法原始碼重要細節 切換 CMOS 分頁(分為兩頁各 128 bytes) 設定要讀取的 CMOS 位址 從 CMOS 讀值
  • 427. CMOS 方法原始碼重要細節 切換 CMOS 分頁(分為兩頁各 128 bytes) 設定要寫入的 CMOS 位址 寫值到CMOS
  • 431. EEPROM 初始化 初始化物件 SPI Flash / DRAM SPI Flash (c) 清除 SPI Flash (c) 選擇 SPI Flash (a/b) 將 Flash 資料讀 取到 DRAM 結束 滿 未滿
  • 432. EEPROM write SPI Flash(a /b) 清除 SPI Flash (a/b) 將 DRAM 內容寫回 SPI Flash (a/b) (1k) SPI Flash (c) 清除 SPI Flash (c) 填 1-bit 0 到 SPI Flash (c) 更改 SPI Flash (a/b) 開始寫資料的位置 寫值到 DRAM 寫值到 SPI Flash(a/b) 結束 滿 滿 未滿 未滿
  • 434. Flash 方法原始碼重要細節 宣告 SPI Flash ( a ) 宣告 SPI Flash ( b ) 宣告 SPI Flash ( c ) 宣告 DRAM 4k 判斷 SPI Flash ( c ) 是否 滿了 判斷目前使用 SPI Flash (a/b) 選擇目前使用 SPI Flash (a/b) 將SPI Flash 填到DRAM 計算DRAM 正確的值
  • 435. Flash 方法原始碼重要細節 判斷SPI Flash ( a / b ) 是否滿 了 Reset SPI Flash ( a / b ) 將數值寫回SPI Flash ( a / b ) 前面 1k 部分 寫 0 到 SPI Flash ( c ) 寫入位置回到初始狀態
  • 436. Flash 方法原始碼重要細節 填值到 DRAM 決定填值到哪一組 SPI Flash ( a / b ) 填值到SPI Flash ( a / b )
  • 438. EEPROM 讀取性能測試 板子 平均讀取時間 Arduino Leonardo 實體 EEPROM 1 us 86Duino (CMOS bank) 2 us 86Duino (Flash bank) < 0.1us 測試程式: 連續讀取200 次, 計算平均讀取時間
  • 439. EEPROM 寫入性能測試 板子 平均寫入時間 Arduino Leonardo 實體 EEPROM 3395 us 86Duino (CMOS bank) 3 us 86Duino (Flash bank) 125 us (沒有跨 1K 邊界時的情況) 510 us (跨 1K 邊界時的情況) 測試程式: 連續寫入200 次, 計算平均寫入時間
  • 440. Arduino 原始碼讀書會(V) : Arduino Standard Libraries 重點解析 (下) DMP Electronics Inc. (瞻營全電子) robotics@dmp.com.tw
  • 442. SPI 全名: Serial Peripheral Interface 許多電子裝置都有用到它,例如: ◦SD 記憶卡 ◦數位/類比轉換 IC (例如 AD7928) ◦LED 控制晶片 (例如 MAX7219) ◦還有很多 這裡無法一一列出…
  • 443. SPI 介面 SPI 採用四條線連接主機和周邊設備, 這四條 線的名稱和用途如下: ◦SS:周邊選擇線(Slave Select),指定要連接哪一個 周邊設備。這條線也稱為 CS (Chip Select 晶片選 擇線) 圖片出處:超圖解 Arduino 互動設計入門第一版 旗標出版
  • 444. SPI 介面 (續) ◦MOSI:從主機(master)送往周邊(slave)的資料線, (Master Output Slave Input) ◦MISO:從周邊(slave)送往主機(master)的資料線, (Master Input Slave Output) ◦SCK:序列時脈線 圖片出處:超圖解 Arduino 互動設計入門第一版 旗標出版
  • 445. Arduno UNO 上的 SPI 腳位 有用 UNO 燒錄過 Arduino bootloader 的人,對 SPI 腳位應該 不陌生。如下圖所示: 圖片出處:超圖解 Arduino 互動設計入門第一版 旗標出版
  • 446. UNO 上的 SPI 腳位 (電路圖) 圖片出處:Arduino UNO 官方電路圖 Reset 有 4 支腳 有 3 支腳
  • 447. Arduno Leonardo 上的 SPI 腳位 圖片出處:超圖解 Arduino 互動設計入門第一版 旗標出版 SS pin 為什麼在這裡!? (看下頁)
  • 448. Leonardo 上的 SPI 腳位 (電路圖) 圖片出處:Arduino Leonardo 官方電路圖 SS 與 RXLED 是 共用腳位
  • 449. 電路圖中搜尋 RXLED 關鍵字 心中 OS:或許選一支 GPIO 來當 SS 會比較方便 直接與 LED 相連 一路上都是 SS
  • 450. SPI 的通訊格式 SPI 是一種同步全雙工的序列埠,主機和周邊之間的 資料傳遞,都要跟著時脈的 High、Low 一同進行 SPI 介面沒有強制規範時脈訊號的標準,大部分是由 SPI 介面晶片來決定使用哪一種時脈訊號格式 一般來說,SPI 可以由 CPOL 和 CPHA 來組成四種不 同的格式: ◦CPOL:時脈極性,時脈信號的電位基準 圖片出處:超圖解 Arduino 互動設計入門第一版 旗標出版
  • 451. SPI 的通訊格式 (續) ◦CPHA:時脈相位,資料在時脈的上升階段或者下降階段被讀 取/送出 圖片出處:http://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus 兩個模式的 共同之處: 資料在時脈 上升或下降 階段,同時 收或送資料 SS 要先設為 Low 來啟用裝置 接收與發送 1 個 byte 的過程
  • 452. SPI 的通訊格式 (續) CPOL 和 CPHA 配合後,四種組合如下: 與裝置通訊前的確認事項 ◦資料傳遞的格式 ◦訊號傳遞位元順序 (bit order):分成高位元先傳 (MSBFRIST) 和低位元先傳 (LSBFIRST) 兩種 ◦裝置所能接收的最高時脈頻率 圖片出處:超圖解 Arduino 互動設計入門第一版 旗標出版 Arduino 函 式庫中的 命名
  • 454. SPI.begin() 函式功能: ◦初始化 SPI 硬體 設定為 Master 端 預設資料格式是 CPOL = 0,CPHA = 0 預設傳輸速度是 4MBps 預設傳遞位元順序是高位元先傳 (MSBFIRST)
  • 456. SPI. setBitOrder() 函式功能: ◦設定傳遞位元順序,可輸入兩種參數: MSBFIRST LSBFIRST
  • 457. SPI. setDataMode() 函式功能: ◦設定資料格式,可輸入四種參數: SPI_MODE0 SPI_MODE1 SPI_MODE2 SPI_MODE3
  • 458. SPI. setClockDivider() 函式功能: ◦設定傳輸速度,可輸入七種參數: SPI_CLOCK_DIV2 :8MBps SPI_CLOCK_DIV4 :4MBps SPI_CLOCK_DIV8 :2MBps SPI_CLOCK_DIV16 :1MBps SPI_CLOCK_DIV32 :500KBps SPI_CLOCK_DIV64 :250KBps SPI_CLOCK_DIV128 :125KBps
  • 459. SPI. transfer() 函式功能: ◦傳送並同時接收資料
  • 460. SPI 使用範例 傳送/接收資料 Int data; void setup() { SPI.begin(); } void loop() { digitalWrite(SS, LOW); // 把 SS 設定為 LOW,開始傳送資料 SPI.transfer(0x01); // 送 0x01 給 slave data = SPI.transfer(0x00); // 讀取 slave 回傳的值 digitalWrite(SS, HIGH); // 把 SS 設定為 HIGH,結束資料傳送 Serial.println(data); delay(10); } 這裡傳送的資料是隨便給的 實際要看 slave 晶片而定
  • 461. SPI Library 常常被引用 它們都是 SPI 介面: ◦Ethernet Library ◦TFT Library ◦SD Library ◦Wifi Library ◦SpiderL3S Library Arduino Ethernet shield Arduino TFT SD shield Arduino Wifi shield SpiderL3S (CC3000 Wifi module)
  • 464. SPI 函式庫原始碼重要細節 SPI.cpp:begin() 將 SS pin 設定為 output HIGH 確保等一下 enable SPI 後會是 Master 狀態 將 SPI 設定為 Master 然後 enable SPI enable 後,SCK 和 MOSI pin 的方向需自行定義
  • 465. SPI 函式庫原始碼重要細節 SPI.cpp:end() SPI.cpp:setBitOrder() LSBFIRST MSBFIRST
  • 466. SPI 函式庫原始碼重要細節 SPI.cpp: setDataMode() SPI.cpp: setClockDivider() 設定 divider 暫存器
  • 467. SPI 函式庫原始碼重要細節 SPI.h: transfer() 資料送完的時候,SPIF 會設 1 (設 1 後第一次對它讀取會清 0) 將要送的資料填入 SPDR 暫存器 回傳收到的值
  • 468. SPI 函式庫的移植: 以 86Duino 為例
  • 469. SPI 在 86Duino 上的移植 移植重點: ◦將填 ATmega CPU 內的 SPI 暫存器的行為,改成填 86Duino CPU 內的 SPI 暫存器 ◦其它與硬體無關的程式碼幾乎無需改動,可直接 延用
  • 470. 86Duino spi.cpp:begin() 在 86Duino 中,SPI 是一個 PCI 裝置, 所以需要先取得 I/O address 設定 SPI 為全雙工 預設速度為 4MHz 預設傳輸格式為 SPI_MODE0 開啟 FIFO 功能 將 SS (實際上是 SPICS) 設定為 HIGH
  • 471. 86Duino spi.cpp:end() 86Duino spi.cpp:setBitOrder() 設定為 LSBFIRST 設定為 MSBFIRST
  • 472. 86Duino spi.cpp:setDataMode() 86Duino spi.cpp:setClockDivider() 限制值的範圍在 1 ~ 4095,因 為 divider register 只有 12 bit 設定 SPI 傳輸模式
  • 473. 86Duino spi.cpp:transfer() 檢查 Output FIFO 是否為空 檢查 Input FIFO 是否為空 回傳收到的值 否 是 是 否 送出值
  • 474. 不同 Arduino 板子的 SPI 速度差異 在 Arduino UNO 上,SPI 速度只有固定那七 種 在 Arduino Due 及 86Duino 上,可允許更快 的 SPI 速度 ◦在新版的 Arduino IDE 1.5.x 新增了beginTransaction() 來使用更快的 SPI 速度 但目前 Arduino 網站尚未提供關於此函式的使用文件~冏rz ◦另一種使用更快 SPI 速度的方式是直接對 setClockDivider() 輸入對應的 divider 數值 (而不是 像 SPI_CLOCK_DIV2 這樣的常數) 但使用此法需要先知道不同 Arduino 板子上 SPI 速度的計 算方式
  • 475. 86Duino SPI clock 的計算方式 在 86Duino 上,計算 SPI 速度的公式如下: 當 div 設成 1 時,86Duino 最快可輸出的 SPI clock 速度:50MHz 100MHz / (2  div) div 是 divider 值,範圍:1 ~ 4095
  • 477. Arduino Ethernet shield 簡介 操作電壓:5V 控制晶片:W5100 速度:10/100 Mbps 通訊介面:SPI WIZnet W5100 datasheet: http://www.wiznet.co.kr/UpLoad_Files/ReferenceFiles/W5100_Datasheet_v1.2.2.pdf Ethernet shield 外觀 WIZnet W5100
  • 478. Arduino Ethernet shield 電路 對 Arduino 的通 訊介面:SPI 輸出:LAN 的 差動信號 圖片出處:http://arduino.cc/en/uploads/Main/arduino-ethernet-shield-06-schematic.pdf
  • 479. Arduino Ethernet shield 工作原理 OSI 模型: http://linux.vbird.org/linux_server/0110network_basic.php#route_route 將每個 frame 轉換為 0、1 信號 網路接頭 使用 IEEE 802.3 封包協議 來傳送 MAC 支援的通訊協定 軟體處理部分 硬體處理部分
  • 480. Ethernet 使用範例:ChatServer 把 Arduino 當作 WebServer,等待 client 連線 設定網路卡實 體位址、IP位 址、子網路遮 罩和閘道器位 址 設定伺服器的 port 為 23,預 設使用 Telnet 服務 啟動乙太網路連線 啟動伺服器
  • 481. ChatServer:loop() 聆聽用戶的連線請求 如果收到用戶的連線 請求 第一個用戶連線,送出 Hello 字串 檢查用戶是否有送字 元過來,如果有,則 返回相同的字元給所 有已連結上的用戶
  • 482. ChatServer 執行結果 PC:putty.exe 86Duino :Serial Monitor Server 端 Client 端
  • 484. 由於 Ethernet Library 相當龐大,這裡 不深入討論上面每個 .cpp 裡的函式細 節 只討論和移植有關的大架構
  • 485. Ethernet 資料夾 從 DHCP 伺服器取得動態 IP 從 DNS 伺服器將網址轉換成實際位址 Ethernet 初始化函式 建立 client 端,以 TCP/IP 方式連線 建立 server 端,以 TCP/IP 方式連線 以 UDP 方式連線 https://github.com/arduino/Arduino/tree/master/libraries/Ethernet
  • 486. Ethernet / utility 資料夾 https://github.com/arduino/Arduino/tree/master/libraries/Ethernet/utility 透過 SPI 介面將命令送給 W5100 晶片 Arduino 提供的底層 API (部分遵循 BSD Socket 標準,但沒有完全相容)
  • 487. Arduino Ethernet Library 的架構 Socket W5100 命令 Arduino Ethernet Shield Server Client UDP Ethernet SPI Bus 初始化函式 呼叫 取得/設定 IP、子網 路遮罩、閘道器位 址等等
  • 488. Ethernet Library 在 86Duino 上的移植
  • 489. 86Duino 內建的 Ethernet 電路 網路卡內建在 CPU 中 (含 PHY) Vortex86EX CPU LAN 差動信號輸出 Transformer 86Duino 底板 (PCI 裝置) 網路接頭
  • 490. DOS 下的網路驅動程式 內建在 86Duino 韌體裡的 NDIS driver NDIS: Network Driver Interface Specification, 參考資料: ◦http://en.wikipedia.org/wiki/Network_Driver_Interface_Specification
  • 491. DOS 下的 Socket Library BSD Socket 規範: http://web.mit.edu/macdev/Development/MITSupportLib/SocketsLib/Documentation/sockets.html DOS 下常用的 Socket Library: ◦Watt32: http://www.watt-32.net/ ◦SwsSock (86Duino 使用的 Socket Library): http://www.softsystem.co.uk/products/swssock.htm ◦…
  • 492. Ethernet Library 移植方式 Socket W5100 命令 Ethernet Shield Server Client UDP Ethernet 沿用大部分 Arduino 的 API 名稱,但內容 全部用標準 Socket API (SwsSock library 提供) 來實作 虛擬層 (NDIS to Package) NDIS driver 86Duino LAN Arduino Ethernet Library 86Duino Ethernet Library 移植 替換
  • 493. 移植後的差異: 以 Ethernet Server:begin() 為例 86Duino Arduino 呼叫 Socket API
  • 495. WiFi shield 簡介 工作電壓:3.3V 控制晶片:AT32UC3A1256 無線模組:HDG104 無線網路通訊標準:802.11/g 資料加密方式:WEP 或 WPA2 與 Arduino 的通訊介面:SPI WiFi shield 外觀 AT32UC3A1256 datasheet: http://www.gaw.ru/pdf/Atmel/AVR_32/AT32UC3A0512_0256_0128_1512_1256_1128s.pdf HDG104 datasheet: http://datasheet.octopart.com/HDG104-DN-3-H%26D-Wireless-datasheet-11793609.pdf AT32UC3A1256 HDG104
  • 496. Arduino WiFi shield 電路 圖片出處:http://arduino.cc/en/uploads/Main/arduino-wifi-shield-schematic.pdf AT32UC3A1256 電壓準位從 5V 轉成 3.3V 對 Arduino 的通訊介 面:SPI 透過內部 第二組 SPI Bus 和無線模 組通訊 無線模組 HDG104
  • 497. WiFi 使用範例:WifiCharSever 輸入你的 SSID 輸入 WEP/WAP2 形式的密碼 檢查 WiFi shield 是否存在
  • 498. WifiCharSever:setup() begin() 會不斷嘗試連線 假如尚未連線成功 連線成功後,啟動伺服器 印出目前的 SSID,取得 的 IP,以及訊號強度
  • 499. WifiCharSever:loop() 聆聽用戶的連線請求 如果收到用戶的連線 請求 第一個用戶連線,送出 Hello 字串 檢查用戶是否有送字 元過來,如果有,則 返回相同的字元給所 有已連結上的用戶
  • 500. WifiChatServer 執行結果 PC:putty.exe 86Duino :Serial Monitor Server 端 Client 端
  • 501. WiFi 原始碼概觀 功能皆類似 Ethernet Library https://github.com/arduino/Arduino/tree/master/libraries/WiFi Ethernet
  • 502. WiFi 原始碼概觀 https://github.com/arduino/Arduino/tree/master/libraries/WiFi/utility Ethernet/utility 底層的 SPI driver 底層的 SPI driver Socket Interface Socket Interface
  • 503. WiFi Library 在 86Duino 上的移植 移植重點:WiFi Library 與硬體相關的 只有 SPI 的部分,其它部分程式碼與硬 體無關,可以在 86Duino 上直接延用 ◦將 spi_drv.cpp 存取方式換成 86Duino SPI 的 存取方式 ◦上層的 wifi_drv、server_drv、WIFIClient 等等都不用動
  • 504. 移植後的 spi_drv.cpp 差異 86Duino Arduino 替換 替換
  • 506. GSM 簡介 GSM 全名 Global System for Mobile Communications (全球行動通訊系統) 在台灣,GSM 的頻段是 900、1800MHz,由 於在同一頻段內要讓多人使用又要抗干擾, 所以實際上傳送數據的速度只達到 9.6Kbps( 相當於看一個 200KB 的網頁要需要等 20 幾 秒)
  • 507. GPRS 簡介 GPRS 全名 General Packet Radio Service,在 現有 GSM 技術上,加上數據交換節點(具有 處理封包的能力),配合動態分配頻段來增 加使用率,在連線人數不多的情況下,速度 可達 56Kbps ~ 100多Kbps,用來看網頁和圖 片,已經綽綽有餘。
  • 508. Arduino GSM shield 簡介 使用 M10 晶片: 有 GSM + GPRS 功能 支援 4 種頻段: GSM850MHz GSM900MHz DCS1800MHz DCS1900MHz 支援 TCP/UDP 和 HTTP 網路通訊協定 上傳和下載的速度 最高可達 85.6Kbps Arduino 透過 AT command 控制 GSM shield GSM shield 外觀 圖片出處: http://arduino.cc/en/Main/ArduinoGSMShield
  • 509. Arduino GSM shield 電路 使用 PIN2 和 PIN3 做為 Serial 腳位 增加訊號的 驅動能力 M10 圖片出處:http://arduino.cc/en/uploads/Main/arduino-gsm-shield-schematic.pdf
  • 510. 使用 GSM shield 前應注意的事項 GSM Library 中預設使用 software serial 來傳送 AT command: ◦M10 晶片支援的 AT command: http://arduino.cc/en/uploads/Main/Quectel_M10_AT_commands. pdf ◦GSM shield 使用 PIN2 和 PIN3 做為預設的 software serial 輸 出腳位,不使用 hardware serial (PIN0 和 PIN 1) 來傳輸資料, 因為這會與 Arduino 燒錄程式的腳位衝突。 GSM shield 在使用 modem 傳送資料的時候用電量稍 大,建議接上外部電源 (700mA ~ 1A),而不要只使 用 USB 供電。 需要一張 SIM 卡才能撥打電話、發簡訊以及上網( 必須先向電信業者開通上網功能)
  • 511. 使用 GSM shield 前應注意的事項(續) 在 Atmega 2560 上,GSM shield 需要額外的跳線: 第一步:把 PIN2 的腳往外扳 第二步:將 PIN2 與 PIN10 相連 第三步:插上 GSM shield 這是因為具有 toggle trigger 的中斷腳位,在 UNO 上是 PIN2 ,在 2560 上是 PIN10 的緣故。(在 Leonardo 上則要換成 PIN8) 圖片出處: http://arduino.cc/en/Main/ArduinoGSMShield
  • 512. 用 Arduino + GSM shield 打電話和接電話
  • 513. 準備 首先,拿一張可用的 SIM 卡,插入 GSM shield 圖片出處: http://arduino.cc/en/Guide/ArduinoGSMShield#toc4 用的是 mini SIM 卡,手機 用的是 micro SIM 卡,需要 使用轉卡才不 會掉出來
  • 514. MakeVoiceCall 範例程式 使用者可透過 Serial monitor 輸入電話 號碼來撥打給對方 #include <GSM.h> #define PINNUMBER “" GSM gsmAccess; GSMVoiceCall vcs; String remoteNumber = “"; char charbuffer[20]; void setup() { Serial.begin(9600); while (!Serial) { ; // wait for serial port to connect. Needed for Leonardo only } 如果已經在手機上已取消 PIN 碼,這 裡就不用輸入 PIN 碼 初始化 GSMAccessProvider class 初始化 GSMVoiceProvider class
  • 515. MakeVoiceCall:setup() … // Start GSM shield // If your SIM has PIN, pass it as a parameter of begin() in quotes while(notConnected) { if(gsmAccess.begin(PINNUMBER)==GSM_READY) notConnected = false; else { Serial.println("Not connected"); delay(1000); } } Serial.println("GSM initialized."); Serial.println("Enter phone number to call."); … begin() 完成基本的初始化 回傳結果都沒問題,就可 以開始打電話了
  • 516. 上傳 MakeVoiceCall 之後… 3. 撥出電話 4. 對方接通,開始通話 5. 對方掛斷電話,結束通話 1.打開 serial monitor 2.輸入要撥打的電話 (前面需要加上台灣區碼:+886),輸 入完後按 Send
  • 517. 用 GSM shield 接電話 ReceiveVoiceCall 範例程式 (內容與 MakeVoiceCall 類似,所以 略過) 上傳後打開 serial monitor: 接到一通電話,並顯示電話號碼 雙方通話中 初始化完成,等待別人撥電話進來 Send ‘n’ 後結束通話
  • 519. GSM Library 到 Arduino 的 GitHub 網站,看看 GSM 資料 夾內的檔案: ◦https://github.com/arduino/Arduino/blob/master/libraries/GSM