Arduino 底層原始碼解析心得

  • 7,057 views
Uploaded on

投影片講解視訊影片網址: …

投影片講解視訊影片網址:
http://www.youtube.com/playlist?list=PLFL0ylDooClTXfy-cFbq7rV1iwP57JFaF

This slide is made by the RoBoard team of DMP Electronics Inc.:
https://www.facebook.com/roboard.fans

More in: Technology
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
7,057
On Slideshare
0
From Embeds
0
Number of Embeds
2

Actions

Shares
Downloads
362
Comments
0
Likes
61

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. Arduino 原始碼讀書會 (I) : Overview
  • 2. 簡單複習 Arduino
  • 3. Arduino 硬體配置
  • 4. 開啟 .ino 程式檔 Arduino IDE 的使用
  • 5. 編輯程式
  • 6. 編譯
  • 7. 燒錄到 Arduino 上執行
  • 8. 複習完畢! 收工…(毆)
  • 9. 進入 Arduino 原始碼的世界
  • 10. Q: Arduino 0023、1.0.5、1.5.2 原始碼, 要 推倒哪一個? A: 我們將以 Arduino 1.0.5 為主要推倒對 象
  • 11. 原始碼住哪裡? https://github.com/arduino/Arduino
  • 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… 目前還沒時間試… (哭~~~)
  • 21. .ino 程式的編譯原理概觀
  • 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, 修改暫存器設定
  • 42. wiring_digital.c
  • 43. 硬體相關函式實作解析 digitalWrite (pin, value) ◦函式功能: 設定腳位輸出電位為 HIGH/LOW ◦函式實作內容: 1. 由指定的 pin 編號來取得對應的 port 2. 檢查指定 pin 上的硬體 PWM 是否正在被使用, 如果是則停止它 3. 由 port 找到對應的暫存器 4. 依照輸入的 value, 修改暫存器設定
  • 44. wiring_digital.c
  • 45. 硬體相關函式實作解析 digitalRead (pin) ◦函式功能: 讀取指定腳位的輸入電位, 回傳 HIGH/LOW ◦函式實作內容: 1. 由指定的 pin 編號來取得對應的 port 2. 檢查指定 pin 的硬體 PWM 是否正在被使用, 如 果是則停止它 3. 由 port 找到對應的暫存器, 讀取並判斷暫存器 值, 回傳 HIGH/LOW
  • 46. wiring_digital.c
  • 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. 回傳轉換後的值
  • 49. wiring_analog.c
  • 50. wiring_analog.c
  • 51. 硬體相關函式實作解析 analogWrite (pin, val) ◦函式功能: 使用 Arduino 的 PWM 硬體送出指定 duty 的 PWM ◦函式實作內容: 1. 先將指定 pin 切成 OUTPUT 2. 再從指定 pin 編號, 找到相對應的 timer 3. 把 val 設定到 timer 暫存器 (藉由 timer 和 PWM generator 的硬體行為輸出指定 duty 的 PWM)
  • 52. wiring_analog.c
  • 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 輸出
  • 54. Tone.cpp
  • 55. … Tone.cpp
  • 56. 硬體相關函式實作解析 noTone (pin) ◦函式功能: 停止指定 pin 的 pulse 輸出 ◦函式實作內容: 1. 依據輸入的 pin 編號, 取得正在使用中的 timer 2. 關閉 timer 中斷 3. 將輸出 pin 的電位設定為 0
  • 57. Tone.cpp
  • 58. 硬體相關函式實作解析 shiftOut (datapin, clockpin, bitorder, val) ◦函式功能: 選用兩個 pin 作為 datapin 與 clockpin, 將 8-bit val 用指定的 bitorder 送出 ◦函式實作內容: 1. 依照指定的 bitorder 將 val 從 datapin 輸出 2. 改變 clockpin 電位, 使其 high、low 各一次
  • 59. wiring_shift.c
  • 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 次
  • 61. wiring_shift.c
  • 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 持續的總時間
  • 63. wiring_pulse.c
  • 64. 硬體相關函式實作解析 millis ( ) ◦函式功能: 回傳 Arduino 運行後所經過的時間, 單位是 millisencond, resolution 是 1ms ◦函式實作內容: 1. 關中斷 2. 讀取目前的 timer0_millis 變數值 3. 開中斷 4. 回傳其值
  • 65. wiring.c
  • 66. 硬體相關函式實作解析 micros ( ) ◦函式功能: 回傳 Arduino 運行後所經過的時間, 單位是 microsencond, resolution 是 4us (for 16MHz) ◦函式實作內容: 1. 關中斷 2. 先讀取 timer overflow 的次數 3. 判斷此時 timer 是否 overflow, 若是則加一次 4. 讀取目前的 timer counter 5. 開中斷 6. 計算 timer overflow 次數與 counter 值 7. 將計算結果回傳
  • 67. wiring.c
  • 68. 硬體相關函式實作解析 delay (ms) ◦函式功能: 延長一段指定的時間, 單位是 ms, resolution 是 1ms ◦函式實作內容: 1. 調用 micros ( ) 得到目前的時間 count 值 2. 每經過 1ms 後把指定的 ms 值減一, 直到 ms 等於 0 為止
  • 69. wiring.c
  • 70. 硬體相關函式實作解析 delayMicroseconds (us) ◦函式功能: 延長一段指定的時間, 單位是 us, resolution 是 1us ◦函式實作內容: 1. 依據 CPU 時脈與輸入的 us, 算出需要的 count 總數 2. 將 count 減一, 直到 0 為止
  • 71. wiring.c
  • 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, 啟用可作為外部觸發功能 的腳位
  • 75. WInterrupts.c
  • 76. 硬體相關函式實作解析 detachInterrupt(intnum) ◦函式功能: 卸載指定 intnum 的外部中斷功能 ◦函式實作內容: 依據使用的 Arduino 版本, 關閉指定的外部中斷
  • 77. WInterrupts.c
  • 78. 硬體相關函式實作解析 Serial.begin (baud) ◦函式功能: 設定串列傳輸的 buadrate ◦函式實作內容: 依據使用的 Arduino 版本, 把指定的 baudrate 設 定到 baudrate 暫存器中 啟用 RX、 TX、RX complete 中斷、Data Register Empty 中斷
  • 79. HardwareSerial.cpp
  • 80. 硬體相關函式實作解析 Serial.available ( ) ◦函式功能: 判斷 COM port 是否收到數據 ◦函式實作內容: 回傳 rx buffer 中的 data 個數 HardwareSerial.cpp
  • 81. 硬體相關函式實作解析 Serial.read ( ) ◦函式功能: 讀取 COM port 讀到的數據 ◦函式實作內容: 判斷 rx buffer 是否為空, 如果是則回傳 -1, 如果 不是則讀取一個 data, 回傳給使用者
  • 82. HardwareSerial.cpp
  • 83. 硬體相關函式實作解析 Serial.write ( ) ◦函式功能: 寫入 data 到 COM port ◦函式實作內容: 判斷 tx buffer 是否為已滿, 如果是, 則等到有空 間時把一個 data 丟進 tx buffer, 如果不是則立 刻把一個 data 丟進去
  • 84. HardwareSerial.cpp
  • 85. 下一個推倒對象: 86Duino
  • 86. 86Duino硬體配置 多功能 外部中 斷 I/O USB 2.0 Arduino Leonardo 相容 I/O Arduino Leonardo 相容 I/O Arduino Leonardo 相容 I/O
  • 87. 86Duino硬體配置 MicroSD LAN PCI-e target
  • 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 自己的暫存器
  • 93. wiring_digital.cpp
  • 94. 硬體相關 API 在 86Duino 上的實作 digitalWrite (pin, value) ◦函式功能: 設定腳位輸出電位為 HIGH/LOW ◦函式實作內容: 1. 檢查指定 pin 上的硬體 PWM 是否正在被使用, 如果是則停止它 2. 由 pin 編號找到對應的暫存器 3. 依照輸入的 value, 修改暫存器設定
  • 95. wiring_digital.cpp
  • 96. digitalRead (pin) ◦函式功能: 讀取指定腳位的輸入電位, 回傳 HIGH/LOW ◦函式實作內容: 1. 檢查指定 pin 的硬體 PWM 是否正在被使用, 如 果是則停止它 2. 由 pin 編號找到對應的暫存器, 讀取並判斷暫存 器值後, 回傳 HIGH/LOW 硬體相關 API 在 86Duino 上的實作
  • 97. wiring_digital.cpp
  • 98. 硬體相關 API 在 86Duino 上的實作 analogRead (pin) ◦函式功能: 讀取 A/D 的電壓數值 ◦函式實作內容: 1. 初始化 A/D 2. 設定 PIN 3. 開始做 A/D 轉換 4. 回傳轉換後的值
  • 99. wiring_analog.cpp
  • 100. 硬體相關 API 在 86Duino 上的實作 analogWrite (pin, val) ◦函式功能: 使用 86duino 中的 MCM 之 PWM 硬體送出指定 duty 的 PWM ◦函式實作內容: 1. 從指定 pin 編號, 找到相對應的 MCM 2. 將指定 pin 切成 PWM 輸出 3. 把 val 設定至 PWM 相關暫存器 4. Enable PWM
  • 101. wiring_analog.cpp
  • 102. wiring_analog.cpp
  • 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
  • 104. Tone.cpp
  • 105. Tone.cpp
  • 106. 硬體相關 API 在 86Duino 上的實作 noTone (pin) ◦函式功能: 停止指定 pin 的 pulse 輸出 ◦函式實作內容: 1. 關閉 MCM PWM 2. 將輸出 pin 的電位設定為 0
  • 107. Tone.cpp
  • 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. 計算時間並回傳數值
  • 111. wiring_pulse.cpp
  • 112. 硬體相關 API 在 86Duino 上的實作 millis ( ) ◦函式功能: 回傳 86duino 運行後所經過的時間, 單位是 millisencond, resolution 是 1ms ◦函式實作內容: 回傳 timer_nowtime ( ) 的值 timer_nowtime() 函式實作內容: 在 DOS DJGPP 環境底下調用 uclock(), 取得的時間換算成 millisecond 後回傳
  • 113. wiring.cpp common.cpp
  • 114. 硬體相關 API 在 86Duino 上的實作 micros ( ) ◦函式功能: 回傳 86duino 運行後所經過的時間, 單位是 microsencond, resolution 是 1us ◦函式實作內容: 1. 取得 CPU clock count 2. 將 count 以 CPU 時脈換算後回傳
  • 115. wiring.cpp common.cpp
  • 116. 硬體相關 API 在 86Duino 上的實作 delay (ms) ◦函式功能: 延長一段指定的時間, 單位是 ms, resolution 是 1ms ◦函式實作內容: 1. 將 timer_nowtime ( ) 得到的數值加上輸入的 ms 計算出目標時間 2. 無限等待, 直到超過/到達目標時間
  • 117. wiring.cpp common.cpp
  • 118. 硬體相關 API 在 86Duino 上的實作 delayMicroseconds (us) ◦函式功能: 延長一段指定的時間, 單位是 us, resolution 是 1us ◦函式實作內容: 將目前時間減去進入此 function 的時間, 將結果 轉換成 microsecond 單位後與輸入的 us 值比較, 直到值大於 us 為止
  • 119. wiring.cpp common.cpp
  • 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, 啟用可作為外部觸發功能 的腳位
  • 123. WInterrupts.cpp
  • 124. 硬體相關 API 在 86Duino 上的實作 detachInterrupt(intnum) ◦函式功能: 卸載指定 intnum 的外部中斷功能 ◦函式實作內容: 關閉指定的 intnum 中斷
  • 125. WInterrupts.cpp
  • 126. 硬體相關 API 在 86Duino 上的實作 Serial.begin (baud) ◦函式功能: 設定串列傳輸的 buadrate ◦函式實作內容: 1. 設定鮑率。 2. 設定傳輸資料長度、同位元檢查、停止位元。 3. 清空 TX、RXQueue。 4. 設定 timeout。
  • 127. HardwareSerial.cpp
  • 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 解析
  • 132. 找出 bootloader 原始碼
  • 133. 讓我們再次回到熟悉的地方 https://github.com/arduino/Arduino
  • 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 燒錄
  • 164. 接線路(Arduino to Arduino)
  • 165. 接線路(Arduino to MCU)
  • 166. 開啟 ArduinoISP程式檔
  • 167. 將程式上傳到Arduino板子上
  • 168. 選擇板子種類
  • 169. 開始燒錄bootloader
  • 170. 86Duino 的 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 的記憶體陣列
  • 176. Bootloader 原始碼重要細節 Bootloader main loop 開始
  • 177. Bootloader 原始碼重要細節 讀取要燒錄的 86Duino F/W 大小
  • 178. Bootloader 原始碼重要細節 從 USB 接收 86Duino F/W 檔案
  • 179. Bootloader 原始碼重要細節 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 解析
  • 184. 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
  • 189. Setup steps(2) 控制台所有控制台項目系統進階系統設定 進階環境變數
  • 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變 數值中
  • 192. Setup steps(5) 開啟cmd,移至Arduino底下的build >ant >ant run
  • 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
  • 199. 讓我們再次回到熟悉的地方 https://github.com/arduino/Arduino
  • 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 編譯相關程式碼
  • 205. 語言設定 如何客製化呢?
  • 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 即可看到效果
  • 221. 第一道主菜: Sketch 編譯機制
  • 222. Arduino 編譯流程
  • 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
  • 243. 86Duino 編譯流程
  • 244. 86Duino原始碼重要細節 如果使用者選的板子是 86Duino, 則跳到 duinocompiler.java 編譯 Compiler.java - compile( )
  • 245. 86Duino原始碼重要細節 設定所需程式的路徑參數 DuinoCompiler.java - compile( )
  • 246. 86Duino原始碼重要細節 Makefile 檔案路徑、編譯出檔案路徑 設定 DuinoCompiler.java - compile( )
  • 247. 86Duino原始碼重要細節 Dosbox config設定 Makefile 設定 設定 DOSBox 執行命令 將編譯訊息寫到 MESSAGE.TXT DuinoCompiler.java - compile( )
  • 248. 86Duino原始碼重要細節 Dosbox參數設定 Dosbox執行編譯參數設定 DuinoCompiler.java - writeDosboxconf( )
  • 249. 86Duino原始碼重要細節 設定編譯命令參數 將之前Makefile設定 讀取進來並編譯 DuinoCompiler.java - writeMakefile( )
  • 250. 第二道主菜: Arduino 程式的燒錄機制
  • 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
  • 262. Avrdude 程式放在哪? Linux : hardwaretools
  • 263. Arduino 燒錄機制原始碼重點講解
  • 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 所做的修改
  • 270. 加入 86Duino 板子的資料夾結構
  • 271. 建立 boards.txt
  • 272. 建立 platform.txt
  • 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 重點解析 (上)
  • 282. Wire 函式庫
  • 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 互動設計入門 旗標出版
  • 290. Wire 函式功能與使用範例
  • 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 互動設計入門 旗標出版
  • 303. Wire 函式庫原始碼解析
  • 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 假如是最後一筆
  • 319. Servo 函式庫
  • 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 連接線:
  • 327. Servo.attach(pin) 函式功能: ◦指定要做為輸出 PWM 信號的 pin 編號
  • 328. Servo.write(angle) 函式功能 ◦輸出指定 duty 寬度的 PWM 信號 ◦參數 angle 可以輸入 0 ~180, 代表轉動角度 也可以輸入實際的 duty 時間值, 例如: 800, 1500 等數值, 單位是 us
  • 329. Servo Lib 使用範例: 讓 RC Servo 來回轉動 實際運行結果影片:
  • 330. 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 惡化情形
  • 354. FIRMATA
  • 355. Command Message
  • 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
  • 358. Firmata.attach(); //掛載要執行的函式 Firmata.processInput(); //接收並執行來自HOST的指令
  • 359. Firmata •Examples –Simple Analog Firmata –Servo Firmata •Firmata.h •Firmata.cpp •Boards.h
  • 360. Firmata •Examples –Simple Analog Firmata –Servo Firmata •Firmata.h •Firmata.cpp •Boards.h
  • 361. #include “Boards.h” //依照不同晶片,套用不同的腳位定義
  • 362. Firmata •Examples –Simple Analog Firmata –Servo Firmata •Firmata.h •Firmata.cpp •Boards.h
  • 363. Firmata.begin(); //即為Serial.begin()
  • 364. Firmata.available(); // 即為Serial.available()
  • 365. 將一包訊息接收完成後,依照不同的command做不同的處理
  • 366. 利用function pointer來執行先前attach的function
  • 367. switch依照不同的command來做不同的設定
  • 368. 回傳至HOST的訊息也用相同的格式
  • 369. Firmata •Examples –Simple Analog Firmata –Servo Firmata •Firmata.h •Firmata.cpp •Boards.h
  • 370. 不同的晶片有不同的腳位定義,利用Boards.h來設定
  • 371. readPort();
  • 372. writePort();
  • 373. Firmata @ 86Duino
  • 374. Firmata @ 86Duino •Examples –Simple Analog Firmata –Servo Firmata •Firmata.h •Firmata.cpp •Boards.h
  • 375. SD CARD
  • 376. 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
  • 377. FAT檔案系統
  • 378. SD ./Examples ◦Files.ino ◦Datalogger.ino ./utility →檔案系統 SD.h SD.cpp →開關存取SD卡 File.cpp →開關存取檔案
  • 379. SD •./Examples –Files.ino –Datalogger.ino •./utility •SD.h •SD.cpp •File.cpp
  • 380. #include <SPI.h> // Arduino透過SPI介面連接SD卡 File myFile; //建立一個自己的File物件 SD.begin(); //開啟SD卡
  • 381. SD.open(“example.txt”, FILE_READ); //從頭開始讀 SD.open(“example.txt”, FILE_WRITE); //從尾繼續寫
  • 382. SD •./Examples –Files.ino –Datalogger.ino •./utility •SD.h •SD.cpp •File.cpp
  • 383. dataFile.println(dataString); //將字串寫入檔案 dataFile.close(); //儲存並關閉檔案
  • 384. SD •./Examples –Files.ino –Datalogger.ino •./utility •SD.h •SD.cpp •File.cpp
  • 385. SdFile.cpp SdVolume.cpp FAT檔案系統 Sd2Card.cpp SD卡讀/寫指令、寫入資料 SPI.cpp 透過SPI模式對SD卡存取
  • 386. SD •./Examples –Files.ino –Datalogger.ino •./utility •SD.h •SD.cpp •File.cpp
  • 387. SD @ 86Duino
  • 388. SD @ 86Duino 86Duino透過作業系統運作,SD卡為系統磁 碟 86Duino的作業系統內就有FAT檔案系統 86Duino利用stdio.h內的FILE structure來存取 檔案 86Duino使用4-bit模式與SD卡連接
  • 389. SD @ 86Duino •File.cpp •SD.h •SD.cpp
  • 390. fwrite 寫入檔案
  • 391. fgetpos 取得目前在檔案內的位置 fread 從檔案讀出
  • 392. fflush 寫入檔案
  • 393. fseek 移至檔案的某個特定位置 ftell 取得目前在檔案內的位置 fclose 關閉檔案
  • 394. fopen 開啟檔案 (r,w,a為開啟模式)
  • 395. EEPROM Library
  • 396. EEPROM 簡介 EEPROM, 或寫作E2PROM, 全稱電子 抹除式可複寫唯讀記憶體, 是一種可以 通過電子方式多次複寫的半導體存儲設 備 Arduino EEPROM 大小: ◦ATmega328 : 1024 Byte ◦ATmega168, ATmega8 : 512 Byte ◦ATmega1280, ATmega2560 : 4K Byte
  • 397. EEPROM 函式 EEPROM.read(address) ◦從 address (位址)讀取值出來  EEPROM.write(addr, val) ◦將 val (數值)寫到 addr (位址)
  • 398. EEPROM 函式庫範例 從EEPROM讀 值 寫值到EEPROM
  • 399. EEPROM 函式庫原始碼解析
  • 400. EEPROM 函式庫原始碼重要細節 呼叫 AVR EEPROM 函式庫從 EEPROM 讀值 引用 Atmel 官方提供的 AVR EEPROM 函式庫 呼叫 AVR EEPROM 函式庫寫值到EEPROM EEPROM 是 Arduino 標準函式庫裡實作最簡單的一個  但不代表容易移植
  • 401. EEPROM 函式庫的移植: 以 86Duino 為例
  • 402. 叫我移植這麼簡單的 EEPROM Lib ??? 我覺得我被輕視了… 苦主 RD
  • 403. 什麼! 86Duino 沒有 EEPROM! 這麼爛的板子是誰做的啊! 苦主 RD
  • 404. 開個檔案模擬 EEPROM 讀寫, 十分鐘搞定, 嘿嘿... 苦主 RD 這樣是嚇不倒 我滴!
  • 405. 結果在測試了 EEPROM 的 官方範例之後…86Duino 就葛屁了(DOS 檔案系統損 毀) Orz
  • 406. 以檔案模擬 EEPROM 的問題 若 86Duino 在寫入檔案時, 被斷電或重 置… ◦輕則檔案資料遺失 ◦重則整個檔案系統損毀 需要設計一個不 怕斷電與重置的 演算法… 苦主 RD 嗚嗚, 只好 重寫了~~
  • 407. 86Duino 兩種實現 EEPROM 等價功能的 方法 方法一: 利用板上 CMOS 記憶體 ◦優點: 速度快, 程式簡單, 讀寫時不怕 CPU 斷 電 ◦缺點: 容量只有 200 bytes, 移除 86Duino 板 上 RTC 電池會使資料遺失 方法二: 利用 BIOS flash 的剩餘空間 ◦優點: 容量可達 16 KB, 不需電池仍可保存資 料 ◦缺點: 速度較慢, 需設計容錯算法避免讀寫 時斷電的資料損毀  實作較複雜
  • 408. CMOS bank 方法的實作
  • 409. CMOS 方法原始碼重要細節 切換 CMOS 分頁(分為兩頁各 128 bytes) 設定要讀取的 CMOS 位址 從 CMOS 讀值
  • 410. CMOS 方法原始碼重要細節 切換 CMOS 分頁(分為兩頁各 128 bytes) 設定要寫入的 CMOS 位址 寫值到CMOS
  • 411. Flash bank 方法的實作
  • 412. 算法原理
  • 413. 算法原理
  • 414. EEPROM 初始化 初始化物件 SPI Flash / DRAM SPI Flash (c) 清除 SPI Flash (c) 選擇 SPI Flash (a/b) 將 Flash 資料讀 取到 DRAM 結束 滿 未滿
  • 415. 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) 結束 滿 滿 未滿 未滿
  • 416. 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 正確的值
  • 417. Flash 方法原始碼重要細節 判斷SPI Flash ( a / b ) 是否滿 了 Reset SPI Flash ( a / b ) 將數值寫回SPI Flash ( a / b ) 前面 1k 部分 寫 0 到 SPI Flash ( c ) 寫入位置回到初始狀態
  • 418. Flash 方法原始碼重要細節 填值到 DRAM 決定填值到哪一組 SPI Flash ( a / b ) 填值到SPI Flash ( a / b )
  • 419. Flash 方法原始碼重要細節 從DRAM 讀值
  • 420. EEPROM 讀取性能測試 板子 平均讀取時間 Arduino Leonardo 實體 EEPROM 1 us 86Duino (CMOS bank) 2 us 86Duino (Flash bank) < 0.1us 測試程式: 連續讀取200 次, 計算平均讀取時間
  • 421. EEPROM 寫入性能測試 板子 平均寫入時間 Arduino Leonardo 實體 EEPROM 3395 us 86Duino (CMOS bank) 3 us 86Duino (Flash bank) 125 us (沒有跨 1K 邊界時的情況) 510 us (跨 1K 邊界時的情況) 測試程式: 連續寫入200 次, 計算平均寫入時間
  • 422. Arduino 原始碼讀書會(V) : Arduino Standard Libraries 重點解析 (下) DMP Electronics Inc. (瞻營全電子) robotics@dmp.com.tw
  • 423. SPI 函式庫
  • 424. SPI 全名: Serial Peripheral Interface 許多電子裝置都有用到它,例如: ◦SD 記憶卡 ◦數位/類比轉換 IC (例如 AD7928) ◦LED 控制晶片 (例如 MAX7219) ◦還有很多 這裡無法一一列出…
  • 425. SPI 介面 SPI 採用四條線連接主機和周邊設備, 這四條 線的名稱和用途如下: ◦SS:周邊選擇線(Slave Select),指定要連接哪一個 周邊設備。這條線也稱為 CS (Chip Select 晶片選 擇線) 圖片出處:超圖解 Arduino 互動設計入門第一版 旗標出版
  • 426. SPI 介面 (續) ◦MOSI:從主機(master)送往周邊(slave)的資料線, (Master Output Slave Input) ◦MISO:從周邊(slave)送往主機(master)的資料線, (Master Input Slave Output) ◦SCK:序列時脈線 圖片出處:超圖解 Arduino 互動設計入門第一版 旗標出版
  • 427. Arduno UNO 上的 SPI 腳位 有用 UNO 燒錄過 Arduino bootloader 的人,對 SPI 腳位應該 不陌生。如下圖所示: 圖片出處:超圖解 Arduino 互動設計入門第一版 旗標出版
  • 428. UNO 上的 SPI 腳位 (電路圖) 圖片出處:Arduino UNO 官方電路圖 Reset 有 4 支腳 有 3 支腳
  • 429. Arduno Leonardo 上的 SPI 腳位 圖片出處:超圖解 Arduino 互動設計入門第一版 旗標出版 SS pin 為什麼在這裡!? (看下頁)
  • 430. Leonardo 上的 SPI 腳位 (電路圖) 圖片出處:Arduino Leonardo 官方電路圖 SS 與 RXLED 是 共用腳位
  • 431. 電路圖中搜尋 RXLED 關鍵字 心中 OS:或許選一支 GPIO 來當 SS 會比較方便 直接與 LED 相連 一路上都是 SS
  • 432. SPI 的通訊格式 SPI 是一種同步全雙工的序列埠,主機和周邊之間的 資料傳遞,都要跟著時脈的 High、Low 一同進行 SPI 介面沒有強制規範時脈訊號的標準,大部分是由 SPI 介面晶片來決定使用哪一種時脈訊號格式 一般來說,SPI 可以由 CPOL 和 CPHA 來組成四種不 同的格式: ◦CPOL:時脈極性,時脈信號的電位基準 圖片出處:超圖解 Arduino 互動設計入門第一版 旗標出版
  • 433. SPI 的通訊格式 (續) ◦CPHA:時脈相位,資料在時脈的上升階段或者下降階段被讀 取/送出 圖片出處:http://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus 兩個模式的 共同之處: 資料在時脈 上升或下降 階段,同時 收或送資料 SS 要先設為 Low 來啟用裝置 接收與發送 1 個 byte 的過程
  • 434. SPI 的通訊格式 (續) CPOL 和 CPHA 配合後,四種組合如下: 與裝置通訊前的確認事項 ◦資料傳遞的格式 ◦訊號傳遞位元順序 (bit order):分成高位元先傳 (MSBFRIST) 和低位元先傳 (LSBFIRST) 兩種 ◦裝置所能接收的最高時脈頻率 圖片出處:超圖解 Arduino 互動設計入門第一版 旗標出版 Arduino 函 式庫中的 命名
  • 435. SPI 函式功能與使用範例
  • 436. SPI.begin() 函式功能: ◦初始化 SPI 硬體 設定為 Master 端 預設資料格式是 CPOL = 0,CPHA = 0 預設傳輸速度是 4MBps 預設傳遞位元順序是高位元先傳 (MSBFIRST)
  • 437. SPI.end() 函式功能: ◦關閉 SPI 硬體功能
  • 438. SPI. setBitOrder() 函式功能: ◦設定傳遞位元順序,可輸入兩種參數: MSBFIRST LSBFIRST
  • 439. SPI. setDataMode() 函式功能: ◦設定資料格式,可輸入四種參數: SPI_MODE0 SPI_MODE1 SPI_MODE2 SPI_MODE3
  • 440. 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
  • 441. SPI. transfer() 函式功能: ◦傳送並同時接收資料
  • 442. 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 晶片而定
  • 443. 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)
  • 444. SPI 函式庫原始碼解析
  • 445. SPI 函式庫資料夾內容 https://github.com/arduino/Arduino/tree/master/libraries/SPI
  • 446. SPI 函式庫原始碼重要細節 SPI.cpp:begin() 將 SS pin 設定為 output HIGH 確保等一下 enable SPI 後會是 Master 狀態 將 SPI 設定為 Master 然後 enable SPI enable 後,SCK 和 MOSI pin 的方向需自行定義
  • 447. SPI 函式庫原始碼重要細節 SPI.cpp:end() SPI.cpp:setBitOrder() LSBFIRST MSBFIRST
  • 448. SPI 函式庫原始碼重要細節 SPI.cpp: setDataMode() SPI.cpp: setClockDivider() 設定 divider 暫存器
  • 449. SPI 函式庫原始碼重要細節 SPI.h: transfer() 資料送完的時候,SPIF 會設 1 (設 1 後第一次對它讀取會清 0) 將要送的資料填入 SPDR 暫存器 回傳收到的值
  • 450. SPI 函式庫的移植: 以 86Duino 為例
  • 451. SPI 在 86Duino 上的移植 移植重點: ◦將填 ATmega CPU 內的 SPI 暫存器的行為,改成填 86Duino CPU 內的 SPI 暫存器 ◦其它與硬體無關的程式碼幾乎無需改動,可直接 延用
  • 452. 86Duino spi.cpp:begin() 在 86Duino 中,SPI 是一個 PCI 裝置, 所以需要先取得 I/O address 設定 SPI 為全雙工 預設速度為 4MHz 預設傳輸格式為 SPI_MODE0 開啟 FIFO 功能 將 SS (實際上是 SPICS) 設定為 HIGH
  • 453. 86Duino spi.cpp:end() 86Duino spi.cpp:setBitOrder() 設定為 LSBFIRST 設定為 MSBFIRST
  • 454. 86Duino spi.cpp:setDataMode() 86Duino spi.cpp:setClockDivider() 限制值的範圍在 1 ~ 4095,因 為 divider register 只有 12 bit 設定 SPI 傳輸模式
  • 455. 86Duino spi.cpp:transfer() 檢查 Output FIFO 是否為空 檢查 Input FIFO 是否為空 回傳收到的值 否 是 是 否 送出值
  • 456. 不同 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 速度的計 算方式
  • 457. 86Duino SPI clock 的計算方式 在 86Duino 上,計算 SPI 速度的公式如下: 當 div 設成 1 時,86Duino 最快可輸出的 SPI clock 速度:50MHz 100MHz / (2  div) div 是 divider 值,範圍:1 ~ 4095
  • 458. Ethernet 函式庫
  • 459. 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
  • 460. Arduino Ethernet shield 電路 對 Arduino 的通 訊介面:SPI 輸出:LAN 的 差動信號 圖片出處:http://arduino.cc/en/uploads/Main/arduino-ethernet-shield-06-schematic.pdf
  • 461. Arduino Ethernet shield 工作原理 OSI 模型: http://linux.vbird.org/linux_server/0110network_basic.php#route_route 將每個 frame 轉換為 0、1 信號 網路接頭 使用 IEEE 802.3 封包協議 來傳送 MAC 支援的通訊協定 軟體處理部分 硬體處理部分
  • 462. Ethernet 使用範例:ChatServer 把 Arduino 當作 WebServer,等待 client 連線 設定網路卡實 體位址、IP位 址、子網路遮 罩和閘道器位 址 設定伺服器的 port 為 23,預 設使用 Telnet 服務 啟動乙太網路連線 啟動伺服器
  • 463. ChatServer:loop() 聆聽用戶的連線請求 如果收到用戶的連線 請求 第一個用戶連線,送出 Hello 字串 檢查用戶是否有送字 元過來,如果有,則 返回相同的字元給所 有已連結上的用戶
  • 464. ChatServer 執行結果 PC:putty.exe 86Duino :Serial Monitor Server 端 Client 端
  • 465. Ethernet Library 原始碼概觀
  • 466. 由於 Ethernet Library 相當龐大,這裡 不深入討論上面每個 .cpp 裡的函式細 節 只討論和移植有關的大架構
  • 467. Ethernet 資料夾 從 DHCP 伺服器取得動態 IP 從 DNS 伺服器將網址轉換成實際位址 Ethernet 初始化函式 建立 client 端,以 TCP/IP 方式連線 建立 server 端,以 TCP/IP 方式連線 以 UDP 方式連線 https://github.com/arduino/Arduino/tree/master/libraries/Ethernet
  • 468. Ethernet / utility 資料夾 https://github.com/arduino/Arduino/tree/master/libraries/Ethernet/utility 透過 SPI 介面將命令送給 W5100 晶片 Arduino 提供的底層 API (部分遵循 BSD Socket 標準,但沒有完全相容)
  • 469. Arduino Ethernet Library 的架構 Socket W5100 命令 Arduino Ethernet Shield Server Client UDP Ethernet SPI Bus 初始化函式 呼叫 取得/設定 IP、子網 路遮罩、閘道器位 址等等
  • 470. Ethernet Library 在 86Duino 上的移植
  • 471. 86Duino 內建的 Ethernet 電路 網路卡內建在 CPU 中 (含 PHY) Vortex86EX CPU LAN 差動信號輸出 Transformer 86Duino 底板 (PCI 裝置) 網路接頭
  • 472. DOS 下的網路驅動程式 內建在 86Duino 韌體裡的 NDIS driver NDIS: Network Driver Interface Specification, 參考資料: ◦http://en.wikipedia.org/wiki/Network_Driver_Interface_Specification
  • 473. 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 ◦…
  • 474. 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 移植 替換
  • 475. 移植後的差異: 以 Ethernet Server:begin() 為例 86Duino Arduino 呼叫 Socket API
  • 476. WiFi 函式庫
  • 477. 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
  • 478. Arduino WiFi shield 電路 圖片出處:http://arduino.cc/en/uploads/Main/arduino-wifi-shield-schematic.pdf AT32UC3A1256 電壓準位從 5V 轉成 3.3V 對 Arduino 的通訊介 面:SPI 透過內部 第二組 SPI Bus 和無線模 組通訊 無線模組 HDG104
  • 479. WiFi 使用範例:WifiCharSever 輸入你的 SSID 輸入 WEP/WAP2 形式的密碼 檢查 WiFi shield 是否存在
  • 480. WifiCharSever:setup() begin() 會不斷嘗試連線 假如尚未連線成功 連線成功後,啟動伺服器 印出目前的 SSID,取得 的 IP,以及訊號強度
  • 481. WifiCharSever:loop() 聆聽用戶的連線請求 如果收到用戶的連線 請求 第一個用戶連線,送出 Hello 字串 檢查用戶是否有送字 元過來,如果有,則 返回相同的字元給所 有已連結上的用戶
  • 482. WifiChatServer 執行結果 PC:putty.exe 86Duino :Serial Monitor Server 端 Client 端
  • 483. WiFi 原始碼概觀 功能皆類似 Ethernet Library https://github.com/arduino/Arduino/tree/master/libraries/WiFi Ethernet
  • 484. WiFi 原始碼概觀 https://github.com/arduino/Arduino/tree/master/libraries/WiFi/utility Ethernet/utility 底層的 SPI driver 底層的 SPI driver Socket Interface Socket Interface
  • 485. WiFi Library 在 86Duino 上的移植 移植重點:WiFi Library 與硬體相關的 只有 SPI 的部分,其它部分程式碼與硬 體無關,可以在 86Duino 上直接延用 ◦將 spi_drv.cpp 存取方式換成 86Duino SPI 的 存取方式 ◦上層的 wifi_drv、server_drv、WIFIClient 等等都不用動
  • 486. 移植後的 spi_drv.cpp 差異 86Duino Arduino 替換 替換
  • 487. GSM 函式庫
  • 488. GSM 簡介 GSM 全名 Global System for Mobile Communications (全球行動通訊系統) 在台灣,GSM 的頻段是 900、1800MHz,由 於在同一頻段內要讓多人使用又要抗干擾, 所以實際上傳送數據的速度只達到 9.6Kbps( 相當於看一個 200KB 的網頁要需要等 20 幾 秒)
  • 489. GPRS 簡介 GPRS 全名 General Packet Radio Service,在 現有 GSM 技術上,加上數據交換節點(具有 處理封包的能力),配合動態分配頻段來增 加使用率,在連線人數不多的情況下,速度 可達 56Kbps ~ 100多Kbps,用來看網頁和圖 片,已經綽綽有餘。
  • 490. 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
  • 491. Arduino GSM shield 電路 使用 PIN2 和 PIN3 做為 Serial 腳位 增加訊號的 驅動能力 M10 圖片出處:http://arduino.cc/en/uploads/Main/arduino-gsm-shield-schematic.pdf
  • 492. 使用 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 卡才能撥打電話、發簡訊以及上網( 必須先向電信業者開通上網功能)
  • 493. 使用 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
  • 494. 用 Arduino + GSM shield 打電話和接電話
  • 495. 準備 首先,拿一張可用的 SIM 卡,插入 GSM shield 圖片出處: http://arduino.cc/en/Guide/ArduinoGSMShield#toc4 用的是 mini SIM 卡,手機 用的是 micro SIM 卡,需要 使用轉卡才不 會掉出來
  • 496. 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
  • 497. 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() 完成基本的初始化 回傳結果都沒問題,就可 以開始打電話了
  • 498. 上傳 MakeVoiceCall 之後… 3. 撥出電話 4. 對方接通,開始通話 5. 對方掛斷電話,結束通話 1.打開 serial monitor 2.輸入要撥打的電話 (前面需要加上台灣區碼:+886),輸 入完後按 Send
  • 499. 用 GSM shield 接電話 ReceiveVoiceCall 範例程式 (內容與 MakeVoiceCall 類似,所以 略過) 上傳後打開 serial monitor: 接到一通電話,並顯示電話號碼 雙方通話中 初始化完成,等待別人撥電話進來 Send ‘n’ 後結束通話
  • 500. GSM Library 原始碼概觀
  • 501. GSM Library 到 Arduino 的 GitHub 網站,看看 GSM 資料 夾內的檔案: ◦https://github.com/arduino/Arduino/blob/master/libraries/GSM
  • 502. GSM Library 檔案 GSM Library 裡面的檔案很多,我們可以大致 分類如下: 負責管理 SoftSerial 使用的 buffer 負責送出 PIN 碼、偵 測 GPRS 網路等等 負責撥號和建立語音連 線
  • 503. GSM Library 檔案 (續) 負責收發簡訊 在 GPRS 網路上,建 立 server/client 端 以 Software Serial 的方式收 送 AT command
  • 504. GSM Library 檔案 (續) PIN 碼管理工具 Modem 測試工具 GPRS 網路掃描工具
  • 505. GSM Library 架構 GSM class (負責送出初始化命令) GSM Soft Serial class GSM Shield GSM_SMS class GSMClient Class GPRS class (負責送出初始化命令) GSMClient class GSMServer class 1. 每個 class 包含 自己專用的 AT command 2. 當使用者呼叫 GSM API 時,該 API 會把自己的處 理程序註冊到一個 特殊列表中,讓 SoftSerial 中斷副 程式以 callback 的 方式來呼叫
  • 506. GSM Library 運作方式: 以 GSM.begin() 為例 Begin() ModemConfiguration() ModemConfigurationContinue() manageResponse() GSM3AccessProvider.cpp GSM3SoftSerial.cpp Recv() 呼叫 callback 函式 openCommand() GSM3ShieldV1ModemCore.cpp manageMsgNow() 中斷副程式 API 其他功能的運作方式皆大同小異
  • 507. ModemConfigurationContinue() 在其他功能的 .cpp 中,看到以 Continue 結尾的函式,函式內容 都差不多,只差在 AT command 不同 第一個 AT 指令 檢查回傳結果 第二個 AT 指令 檢查回傳結果 第三個指令 檢查回傳結果 第四個指令 此函式內容可以說是 AT command 的腳本。 它最後會被 SoftSerial 的中斷副 程式呼叫。
  • 508. GSM Soft Serial 運作方式:recv() GSM 以既有的 lib 為基礎,再寫一個新的 SoftSerial 用 digitalRead() + delay() 讀取 8bit 值 假如 buffer 滿了 就送 XOFF 回去 請對方暫緩傳送 檢查是不是特殊字元 ‘w’ 假如不是,就放入 buffer 中 這部分是 新增的
  • 509. GSM Soft Serial 運作方式 (續) buffer 滿了,則呼叫 callback 處理函式 收到 LF 符號,則呼叫 callback 處理函式 收到 space 符號,則呼叫 callback 處理函式 這部分是 新增的
  • 510. GSM Library 在 86Duino 上的移植
  • 511. GSM Library 在 86Duino 上的移植 移植重點: GSM Library 與硬體相關的只有 SoftSerial 的部分,其它部分程式碼與硬 體無關,可以在 86Duino 上直接延用
  • 512. GSM Library 在 86Duino 上的移植 GSM3SoftSerial.cpp ◦直接套用 86Duino softserial Library 的實作方式, 然後再加入 GSM SoftSerial 新增的那些 code ◦預設的腳位更動,RX 是用 PIN42 (有 attachInterrupt 功能的),TX 是用 PIN3 小改進: ◦新增 Hardware Serial 的通訊方式,可以選用 COM1 ~ COM3 其中一組來通訊。 ◦使用 Hardware Serial 可以保證 GSM Library 工作更 穩定
  • 513. 加入 Hardware Serial 功能 不使用中斷 ◦因為 SoftSerial 已經與各項功能的 callback function 和軟體 flow control 寫在一起,為了實現相同的功 能,可能要大改既有的 Hardware Serial library。 改用 polling ◦經過觀察,主要 class 在運行過程中,都會持續呼 叫名為 ready 的函式,用來得到送出 AT command 的回傳結果 ◦因此就把 hardware serial 函式加入 ready(),實現 原來 SoftSerial 會做的事
  • 514. GSM3ShieldV1ModemCore.cpp : manageReceivedData() GSM3SoftSerial.cpp:recv() 添加的 Hardware Serial code 呼叫 行為相同 原來的 Software Serial code GSM3ShieldV1BaseProvider.cpp:ready()
  • 515. 小插曲-遇到 Arduino GSM Library 的 Bug GSM3VoiceCallService.cpp GSM3ShieldV1VoiceProvider.cpp 呼叫建構子
  • 516. 小插曲-遇到 Arduino GSM Library 的 Bug Bug 來由: ◦靜態物件 GSM3VoiceCallService 的實作方式要求另 一個靜態物件 GSM3MobileVoiceProvider 先被初始 化 ◦但這兩個物件的初始化順序與編譯器有關,不同 平台的編譯器會得到不一樣的結果 ◦錯誤的初始化順序會造成 GSM3VoiceCallService 使 用到尚未給定初值的 theGSM3MobileVoiceProvider 變數而當機
  • 517. SoftwareSerial 函式庫
  • 518. SoftwareSerial 簡介 簡單的說,就是用 GPIO 來模擬硬體 UART 的 TX、RX 行為 在 Arduino UNO 上,預設使用 PIN2 和 PIN3 做為 RX 和 TX。 SoftwareSerial 函式庫不允許隨意指定腳位, 因為 RX 的行為需要由具有 toggle 中斷的 PIN 腳來模擬。
  • 519. 具有 toggle 中斷的 PIN 腳 Arduino UNO ◦PIN2 Arduino Mega2560: ◦PIN10 ~ 15,PIN50 ~ 53,A8 ~ A15 Leonardo: ◦PIN8 ~ 11,PIN14 ~16
  • 520. Start bit Stop bit 8 bits data Arduino 上,RX 行為的模擬方法: 中斷觸發, 進入中斷副 程式 delay digitalRead() delay delay delay delay delay …… delay delay digitalRead() digitalRead() delay
  • 521. SoftwareSerial 函式庫原始碼解析
  • 522. SoftwareSerial 函式庫資料夾內容 https://github.com/arduino/Arduino/tree/master/libraries/SoftwareSerial
  • 523. 鮑率延遲時間表 這些數值在不同的 CPU 都不一樣, 需要實際 tune 過才能確定 SoftwareSerial.cpp: SoftwareSerial() Start bit 的 delay 資料和 Stop bit 的 delay TX 的 delay
  • 524. SoftwareSerial 函式庫原始碼重要細節 SoftwareSerial.cpp: SoftwareSerial() 初始化數值 設定 Tx, Rx 腳位
  • 525. SoftwareSerial 函式庫原始碼重要細節 設定鮑率 設定傳輸, 接收 延遲時間 等待中斷發生 開始接收資料 SoftwareSerial.cpp: begin()
  • 526. SoftwareSerial 函式庫原始碼重要細節 等待接受訊號觸發中斷 觸發中斷執行 recv() SoftwareSerial.cpp: ISR() SoftwareSerial.cpp: handle_interrupt()
  • 527. SoftwareSerial 函式庫原始碼重要細節 SoftwareSerial.cpp: available() SoftwareSerial.cpp: read() 回傳 buffer 資料數量 接收資料
  • 528. SoftwareSerial 函式庫原始碼重要細節 傳送資料 傳送延遲 傳送延遲 傳送延遲 SoftwareSerial.cpp: write()
  • 529. SoftwareSerial 函式庫原始碼重要細節 讀取 8bit 資料 Start bit 延遲 Stop bit 延遲 SoftwareSerial.cpp: recv ()
  • 530. SoftwareSerial 函式庫原始碼重要細節 判斷 buffer 是否滿了 將資料丟進 buffer SoftwareSerial.cpp: recv ()
  • 531. SoftwareSerial 函式庫的移植: 以 86Duino 為例
  • 532. SoftwareSerial在 86Duino 上的移植 移植重點: ◦在 86Duino 上,要使用具有 attachInterrupt() 功能 的 PIN 腳來模擬 RX(TX 與原來一樣),掛中斷 的方式與 Arduino 不同 ◦鮑率延遲的時間表需要實際 tune 過一次 ◦其餘部分不用動到
  • 533. 86Duino 的鮑率延遲時間表
  • 534. SoftwareSerial函式庫原始碼重要細節 SoftwareSerial.cpp: listen() 中斷觸發, 執行 handle_interrupt 判斷中斷觸發腳位
  • 535. SoftwareSerial函式庫原始碼重要細節 SoftwareSerial.cpp: write() 傳送資料 傳送延遲 傳送延遲 傳送延遲
  • 536. SoftwareSerial函式庫原始碼重要細節 SoftwareSerial.cpp: recv () 將腳位切換成Encoder 判斷 buffer 是否滿了 將資料丟進 buffer
  • 537. TFT 函式庫
  • 538. TFT shield 簡介 工作電壓:5V 螢幕解析度:160 x 128 pixels 色彩深度:16bit (R-5bit, G-5bit, B-6bit) 通訊介面:SPI 附帶 microSD 插槽 TFT 外觀
  • 539. TFT 函式庫原始碼概觀 https://github.com/arduino/Arduino/tree/master/libraries/TFT 畫圖函式 (點、線、圓等 等) 初始化函式
  • 540. TFT函式庫原始碼重要細節 TFT.h 初始化自定義腳位 初始化 TFT 螢幕 高階的畫圖函式 低階的繪圖函式 (含初始化命令)
  • 541. TFT 函式庫原始碼重要細節 設定螢幕寬 設定螢幕高 初始化 TFT (送出連續的初始化命令) 設定畫面旋轉方向 TFT.cpp 初始化自定義腳位
  • 542. TFT 函式庫原始碼重要細節 以 drawFastVLine() 為例: 透過 SPI 函式送命令,其 它函式也是一樣 CS 設為 LOW,RS 設為 HIGH CS 設為 HIGH utility / Adafruit_ST7735.cpp
  • 543. TFT Library 在 86Duino 上的移植 移植重點: ◦將直接存取 ATmega 暫存器的程式,用 digitalWrite()、 digitalRead() 函式替換 ◦延用 86Duino 既有的 SPI 函式庫,相關的 函式如 SPI.write() 不需要改動
  • 544. TFT Library 在 86Duino 上的移植 86Duino: Ada_ST77.cpp Arduino: Adafruit_ST7735.cpp 移植
  • 545. TFT demo 影片 https://www.youtube.com/watch?v=eZefqL6FtOE
  • 546. Thank You 感謝大家來參與 Arduino 原始碼讀書會 接下來問題討論時間 DMP Electronics Inc. (瞻營全電子) robotics@dmp.com.tw