2015年8月1日 星期六

Arduino 之間的 I2C 通訊 (5) master 向 slave 要求不同資料

相關指令:

指令發出耆作用
Wire.begin([<address>]);master / slave啟動 Wire (由於 i2c 是用 Wire 的, 這就等同啟動 i2c 了)
Wire.beginTransmission(<address>);master開始對 <address> 的連線
Wire.endTransmission();master 關閉之前的連線
Wire.requestFrom(<address>,<len>);master在線上向拍定地址發出回傳 <len> bytes 資料的請求
Wire.available();master檢查連線上是否有可接收的資料
Wire.read();master / slave讀取連線上的一個 byte 的資料
Wire.write(<array>,<size>);slave / slave在連線上送出 <size>個 byte 的資料
Wire.onReceive(<function>)slave 設定用來接收資料的函數
Wire.onRequest(<function>)slave 設定函數用來回應線上的請求

這個可以說是之前的一個初步小總結了.

從 (4) 已經說明了 slave 如果把資料回傳, 但大家可能會發覺, 某些 i2c device, 是可以選擇不同的資料的, 在處理請求的函數中, 如何得知 master 想要什麼?

對, 在 request 之中, 是沒有任何有關請求的資料提供的, 就只是一個空白的請求.

但就像 MPU6050 之類的模塊, 不是可以選擇不同的數據嗎?
如果大家有用過 I2CDev 的庫, 或許會發覺 readByte 的函數, 不是有一個 regAddr, 向 slave 要求不同的數據嗎?

    static int8_t readByte(uint8_t devAddr, uint8_t regAddr, uint8_t *data, uint16_t timeout=I2Cdev::readTimeout);

大家有看過之前 (1) - (4) 的話, 難道想不出來嗎?  多思考一下, 把所知道的結合起來.

對了, 說穿了就只是把兩個工序結合起來.

  • master 先向 slave 發送所需資料的指令
  • slave 收到後, 先記下來, 不作處理
  • master 再向 slave 發出傳送資料的請求
  • slave 收到請求後, 先看看 master 剛發過來有關所需資料的指令, 再把相關資料回傳

是否很簡單呢?

master 向 slave 選擇所需資料

明白了原理, 步驟也很簡單, 就是把 (2) + (4) 結合:

  1. 執行 beginTransmission 並指定接收指令的地址
  2. 以 Wire.write 把所需資料的指令發送出去
  3. 執行 endTransmission 完成指令發送
  4. 執行 beginTransmission 並指定連線地址
  5. 以 Wire.requestFrom 發出請求
  6. 不斷以 Wire.available 檢查是否有資源, 並以 Wire.read 把一個 byute 資料提出
  7. 執行 endTransmission 作結束

當中 3. 4. 是否有必要, 我也不肯定.  但為了把 發送 / 接收 可獨立一點, 先把發送完結或者會好一點.  而且, 3. 4. 之後, 有需要或許要加入一點 delay, 好讓 slave 處理資料.  當然, 看實際情況決定, 並不是必須的.

以下是簡單的例子, master 發出請求時, 會先指定所需資料.


#include <Wire.h>

#define SLAVE_ADDRESS 0x12
#define SERIAL_BAUD 57600 
#define DATA_SIZE 8
 
void setup()
{
  Wire.begin();
 
  Serial.begin(SERIAL_BAUD);
  Serial.println("I2C Master.05 started");
  Serial.println();
}
 
 
void loop()
{
  if (Serial.available()) {
    
    Wire.beginTransmission(SLAVE_ADDRESS);
    Wire.write(Serial.read());
    delay(1);
    Wire.endTransmission();

    Wire.beginTransmission(SLAVE_ADDRESS);
    Wire.requestFrom(SLAVE_ADDRESS, DATA_SIZE);
    if (Wire.available()) {
      Serial.print("Data returned: ");
      while (Wire.available()) Serial.print((char) Wire.read());
      Serial.println();
    }
    Wire.endTransmission();
    while(Serial.available()) Serial.read();  // Clear the serial buffer, in this example, just request data from slave

  }
}


salve 向 master 回傳所需資料

跟 master 一樣, 所需步驟, 同樣是把 (3) + (4) 結合起來就可以了.


  • 執行 Wire.onReceive 去設定接收資料的函數
  • 執行 Wire.onRequest 去設定處理請求的函數
  • 在 onRecevie 函數中, 以 Wire.available 檢查是否有資料需要處理.  
  • 要有複雜的程序, 先記下來, 留待主程式去做
  • 在主程序中檢查是否有 接收資料待處理
  • 在 onRequest 函數中, 跟據之前 onReceive 收到的指令, 以 Wire.write 把 所需資料回傳


但這裡有一點要留意, 之前沒提及的.  就是當 master 發出 requestFrom 時, slave 是會觸發一次 onReceive 而當中是沒有資料的.  所以在 onReceive 當中, 必須要先檢查 Wire.available.

以下是一個簡單例子, master 可以選擇 2 種資料, 而回傳結果如下:
0 - 回傳 "Super169"
1 - 回傳 "Apple II"
其他 - 回傳 "WhoAmI"


#include <Wire.h>

#define SLAVE_ADDRESS 0x12
#define SERIAL_BAUD 57600 

uint8_t dataMode = '0';
boolean modeChanged = false;

void setup() {
  Wire.begin(SLAVE_ADDRESS);    // join I2C bus as a slave with address 1
  Wire.onReceive(receiveEvent); // register event
  Wire.onRequest(requestEvent); // register event
 
  Serial.begin(SERIAL_BAUD);
  Serial.println("I2C Slave.05 started\n");
}

void loop() {
  if (modeChanged) {
    Serial.print("Change data mode to ");
    Serial.println((char) dataMode);
    modeChanged = false;
  }
}

void receiveEvent(int count) {
  if (Wire.available()) {
    dataMode = Wire.read();
    modeChanged = true;
    while (Wire.available()) Wire.read();
  }
}

void requestEvent()
{
  switch (dataMode) {
    case '0':
      Wire.write("Super169",8);
      break;
    case '1':
      Wire.write("Apple II",8);
      break;
    default:
      Wire.write("Who am I",8);
  }
}


額外測試項目

大家記得之前 (2) 時提及, 不要把 Serial.print 放在 receiveEvent 當中嗎?
在之前的例子, 由於只要 receiveEvent 在工作, 不會有任何影響.
但在今次的例子中, 大家看到為了把 data mode 的改變顯示出來, Serial.print 的部份放到主程式內.
有興趣的朋友可以試試把它修改一下, 放回 receiveEvent 內, 看看會有什麼結果.


相關程式下載:


Arduino 之間的 I2C 通訊 (4) 由 master 向 slave 要求資料回傳

相關指令:

指令發出耆作用
Wire.begin([<address>]);master / slave啟動 Wire (由於 i2c 是用 Wire 的, 這就等同啟動 i2c 了)
Wire.beginTransmission(<address>);master開始對 <address> 的連線
Wire.endTransmission();master 關閉之前的連線
Wire.requestFrom(<address>,<len>);master在線上向拍定地址發出回傳 <len> bytes 資料的請求
Wire.available();master檢查連線上是否有可接收的資料
Wire.read();master讀取連線上的一個 byte 的資料
Wire.onRequest(<function>)slave 設定函數用來回應線上的請求
Wire.write(<array>,<size>);slave在連線上送出 <size>個 byte 的資料

之前已經試過由 master 向 slave 發送資料, 但對於一些像 傳感器的設備, 反而是需要由 slave 把資料回傳的.  有些傳感器可能需要一段時間去讀取資料 (例如 PM2.5 收集 30 秒數據), 如果在主控中執行, 可能會影響其他工序.  如果加一片 arduino 板子, 以 slave 形式去讀取資料, 當 master 發出請求時, 就可以直接把最後的結果回傳, master 就不用花太多時間了.  再者, 把程序分開後, 每個程序可獨立除錯, 而主程式亦變得簡單了.  就如 PM2.5 的例子, 把當中讀取及計算的部份後 master 中抽走, 就不用考慮因為要讀取連續數據而影響其他程序的問題了.

由於 slave 是不能主動發動連線, 所以只可以等待 master 的請求, 然後把資料送出去.

slave 回應請求

像之前接收資料一樣, slave 會設定一個 函數去回應 master 的請求的.


  • 執行 Wire.onRequest 去設定處理請求的函數
  • 在該函數中, 以 Wire.write 把 資料回傳

以下是一個簡單例子, 當接到請求後, 就回傳一句 "Super169"

#include <Wire.h>

#define SLAVE_ADDRESS 0x12
#define SERIAL_BAUD 57600 

#define I2C_BUFFER_SIZE 32  
uint8_t i2cBuffer[I2C_BUFFER_SIZE];
uint8_t i2cBufferCnt = 0;

void setup() {
  Wire.begin(SLAVE_ADDRESS);    // join I2C bus as a slave with address 1
  Wire.onRequest(requestEvent); // register event
 
  Serial.begin(SERIAL_BAUD);
  Serial.println("I2C Slave.04 started\n");
}

void loop() {
}

void requestEvent()
{
  Wire.write("Super169",8);
}


master 發出請求 並 接收資料


在 master 中發出請求及接收資料, 也只是幾個簡單步驟就可以了:

  1. 執行 beginTransmission 並指定地址
  2. 以 Wire.requestFrom 向指定地址發出請求, 並指定回傳資料的數目
  3. 不斷以 Wire.available 檢查是否有資源, 並以 Wire.read 把一個 byute 資料提出
  4. 執行 endTransmission 作結束

這裡大家可能會對 requestForm 有點疑問:

1. 為什麼 requestForm 要提供地址?
在 beginTransmission 中, 已指定了連線的地址, 其他地址是不能使用的, 為何還要指定地址?
這個本人亦有疑問, 但在網上找不到確實的答案.  以下是本人的推測, 有錯的希望大家指出.
首先, requestForm 是不需要放在 beginTransmission 之後的, 是可以獨立執行的, 所以必須要有地址.
但為什麼又要放入 beginTransmission 之後呢?  可能是為了確保 slave 在回傳資料時, 可以合法使用連線.  
2. 為什麼 requestForm 要提供回傳資料的大小
在之前的通訊中, 大家也看到, slave 發送完畢, 是不需要執行任何指令的.  對於 Wire 而言, 是沒有明確的訊息得知 slave 已發送完畢.  所以只好在發出請求時, 設定回傳資料的數目.  在正常情況下, 一般有特別的通訊協定, 發出請求的一方, 都會知道回傳資料的數目, 所以不會有問題的.  如果真的是沒有限定的話, 例如通訊協定中, 以回傳的第一個 byte 回報資料長度.  這樣只好用盡 Wire 的 buffer 把資料都接回來, 之後再進行分析處理.

以下就是一個前 slave 發出請求回傳資料的例子:

#include <Wire.h>

#define SLAVE_ADDRESS 0x12
#define SERIAL_BAUD 57600 
#define DATA_SIZE 8

void setup()
{
  Wire.begin();
 
  Serial.begin(SERIAL_BAUD);
  Serial.println("I2C Master.04 started");
  Serial.println();
}
 
 
void loop()
{
  if (Serial.available()) {

    Wire.requestFrom(SLAVE_ADDRESS, DATA_SIZE);
    Wire.beginTransmission(SLAVE_ADDRESS);
    if (Wire.available()) {
      Serial.print("Data returned: ");
      while (Wire.available()) Serial.print((char) Wire.read());
      Serial.println();
    }
    Wire.endTransmission();
    while(Serial.available()) Serial.read();  // Clear the serial buffer, in this example, just request data from slave
  }

}



執行後, 在 master 一方的 serial monitor 不論輸入什麼, 都會向 slave 發出回傳資料的請求.  而 slave 回傳的字句, 會在 serial monitor 中顯示出來.


相關程式下載:




Arduino 之間的 I2C 通訊 (3) 由 master 向 slave 發送資料/發出指令 [slave 延遲處理]

相關指令:

指令發出耆作用
Wire.begin([<address>]);master / slave啟動 Wire (由於 i2c 是用 Wire 的, 這就等同啟動 i2c 了)
Wire.beginTransmission(<address>);master開始對 <address> 的連線
Wire.endTransmission();master 關閉之前的連線
Wire.write(<data>);master 在連線上送出 一個 byte 的資料
Wire.onReceive(<function>)slave 設定用來接收資料的函數
Wire.available();slave檢查連線上是否有可接收的資料
Wire.read();slave讀取連線上的一個 byte 的資料


slave 延遲處理

之前的一篇, 不是已經可以由 master 向 slave 發送資料, 而 slave 亦成功收到了, 為什麼又攪個 延遲處理出來?

之前一篇, 處理 master 送來的資料, 都是在接收的函數之內.  但大家不要忘記, arduino 的主線, 是在 loop 之內執行的.  接收函數太大, 或會影響主程式進行, 而且, 有些時候, 主程式或許需要用到接收回來的資料.

延後處理就是把資料放進緩存一樣, 讓主程式去處理.
方法很簡單, 可以直接把資料放有有關變數, 又或用最通用的方式, 先放入一個 buffer 中.

以下例子, 就是用最通用的方式處理,

#include <Wire.h>

#define SLAVE_ADDRESS 0x12
#define SERIAL_BAUD 57600 

#define I2C_BUFFER_SIZE 32  
uint8_t i2cBuffer[I2C_BUFFER_SIZE];
uint8_t i2cBufferCnt = 0;
boolean dataPending = false;

void setup() {
  Wire.begin(SLAVE_ADDRESS);    // join I2C bus as a slave with address 1
  Wire.onReceive(receiveEvent); // register event

  Serial.begin(SERIAL_BAUD);
  Serial.println("I2C Slave.03 started\n");
}

void loop() {
  if (dataPending) {
    Serial.println("Receive Data:");
    for (int idx = 0; idx < i2cBufferCnt; idx++) Serial.print((char) i2cBuffer[idx]);
    Serial.println("\n");   
    dataPending = false;
  }
}

void receiveEvent(int count) {
  i2cBufferCnt = 0;
  while(Wire.available()) {
    i2cBuffer[i2cBufferCnt++] = Wire.read();
  }
  dataPending = true;
}


執行後, 跟之前的是沒分別的.
當然, 你也可以嘗試把 i2c 的 buffer 加大或收細, 看看有什麼影響.


相關程式下載 (master_03 跟 master_02 是一樣的)

Arduino 之間的 I2C 通訊 (2) 由 master 向 slave 發送資料/發出指令 [slave 直接處理]

相關指令:

指令發出耆作用
Wire.begin([<address>]);master / slave啟動 Wire (由於 i2c 是用 Wire 的, 這就等同啟動 i2c 了)
Wire.beginTransmission(<address>);master開始對 <address> 的連線
Wire.endTransmission();master 關閉之前的連線
Wire.write(<data>);master 在連線上送出 一個 byte 的資料
Wire.onReceive(<function>)slave 設定用來接收資料的函數
Wire.available();slave檢查連線上是否有可接收的資料
Wire.read();slave讀取連線上的一個 byte 的資料


通訊也有不同程度的, 先做一個最簡單的單向通訊.
由於只有 master 可以主動發出通訊要求, 最簡單的就是由 master 向 slave 發送資料了.
這個例子是針對一些操控裝置, 例如你做了一個 i2C 的舵機, 由 arduino 發出指令, 要它轉到指定的角度, 而舵機是不會回傳任何資料的

程式同樣分開 mater 及 slave 的部份, master 發送, slave 接收.

master 發送資料

在 master 發送資料, 只有幾個簡單步驟就可以了:

  1. 執行 beginTransmission 並指定接收資料地址
  2. 以 Wire.write 把資料送出去
  3. 執行 endTransmission 作結束

以下是一個簡單的例子, master 把 串口收到的資料, 發送給 slave.

#include <Wire.h>

#define SLAVE_ADDRESS 0x12
#define SERIAL_BAUD 57600 

 
void setup()
{
  Wire.begin();
 
  Serial.begin(SERIAL_BAUD);
  Serial.println("I2C Master.02 started");
  Serial.println();
}
 
 
void loop()
{
  if (Serial.available()) {
    Wire.beginTransmission(SLAVE_ADDRESS);
    while(Serial.available()) {
      Wire.write(Serial.read());
      delay(1);
    }
    Wire.endTransmission();
  }
}


slave 接收資料

而 slave 接收, 是有點像 interrupt driven 的形式去做,  簡單的做法如下.


  1. 執行 Wire.onReceive 去設定接收資料的函數
  2. 在接收資料的函數中, 不斷以 Wire.available 檢查是否有資源, 並以 Wire.read 把一個 byute 資料提出, 直到所有資料提出後, Wire.available 為 false

注意, 因為 Wire 庫的 buffer 只有 32 個 byte, 每次發送的資料應限制在 32 個 byte 之內.
由於 master 進行 write 是沒有限制的, 如果發送超過 32 bytes, 之後的資料就會流失.

以下例子, 是在 接收的函數中, 直接處理接收回來的資料.



#include <Wire.h>

#define SLAVE_ADDRESS 0x12
#define SERIAL_BAUD 57600 

 
void setup() {
  Wire.begin(SLAVE_ADDRESS);    // join I2C bus as a slave with address 1
  Wire.onReceive(receiveEvent); // register event

  Serial.begin(SERIAL_BAUD);
  Serial.println("I2C Slave.02 started\n");
}

void loop() {
}

void receiveEvent(int count) {
  Serial.println("Receive Data:");
  while(Wire.available()) {
    Serial.print((char) Wire.read());
  }
  Serial.println("\n");
}


注意:  
這個例子中在 receiveEvent 中用到 Serial.print, 只是為了簡單展示結果, 雖然這裡沒有問題, 但其實是絕不應該的.
在正常的程式中, 應該盡量避免在 receiveEvent 中放入複雜的程序, 在下一章中會提及正確的做法.


執行程式後, 在 master 板子連線的 serial monitor 輸入資料, 就會發送到 slave 板子, 再在相關的 serial monitor 顯示出來.


相關程式下載:

2015年7月31日 星期五

Arduino 之間的 I2C 通訊 (序) 簡單介紹

一直有興趣用不同的方式把細小的 arduino 系統組成一個大系統, 剛剛看了 幻生幻灭 大大 的 世界最小的Arduino——ATTiny13上手全攻略1A简介, 心思思想買回來試試.
初步的目標, 是用 ATTiny13 把 一般舵機改成 總線舵機.  雖然已有 PCA9685 之顃 經 i2c 通訊的控制板, 但每個舵機還是直接連到控制板上, 接線相對比較長而且混亂.  如果可以做出總線舵機的效果, 每個舵機之間以三根線連上, 可以一個一個連開去, 又可以中途分開幾個, 又或者直接連到主板.  變化比較大, 而且方便很多.  所以, 還是值得嘗試的.

在未有 ATTiny13 之前, 先研究一下 arduino 之間的 I2C 通訊吧.

在網上不難找到教學, 但很多都只是以一個 byte 通訊, 不足以滿足我的要求, 所以嘗試自己做一些簡單的應用例子, 將來或許用得著, 希望對大家有幫助.

由於網上有不少資源, 太深入的未必人人有興趣, 而且我自己也不慬, 所以, 嘗試用簡單的例子把一些重點拿出來討論.  如果說錯了什麼, 還望大家幫忙指證.

I2C 通訊的特性

首先 要了解 I2C 跟其他通訊(例如串口) 的分別

  • I2C 是 master & slave 的設計
  • 整個線路上只有一個 master, 其他的都是 slave
  • 只有 master 可以 向 slave 進行通訊
  • slave 與 slave 之間是不可以通訊的
  • 只有 master 可以主動向 slave 發送資料或提出請求
  • slave 只可因應 master 的請求而回傳資料, 不可以主動發送資料給 master


I2C 通訊有什麼好處?


  • 可以同時以 1 master 連接多個 slave 設備 
  • 速度快
  • 不需另外購買通訊模塊, 可以說是完全免費的
  • 只需三根線連通就可以, 不用複雜的連線


I2C 通訊有什麼缺點?


  • 由於 I2C 是 master 主導, 所有 slave 板子都不能主動提出通訊要求, 亦不能跟其他 slave 通訊.  程式設定上, 就要有一個主控制板, 其他都只是分工.  
  • slave 板子不能用來連接其他 i2c 設備 (除非大神們另外寫一個 Wire 庫, 用其他接口吧)

因此, 分工的時間, slave 只可以分擔非 i2c 的設備, 對於 i2c 的設備, 還是要靠 master 自己負責.
所以 master 除了要管理 slave 的分工外, 還要處理 i2c 設備.



準備功夫:

要做的 I2C 通訊, 只需要 Wire 庫就可以了 (當然, 對於大神來說, Wire 庫也可以不需要, 自己完全做出來也可以.), 所以基本上不需要再找什麼庫.

當然, 如果配合 I2Cdev 之顃的庫, 一定程度上可以簡單一點.  但為了方便大家了解, 還是用最基本的 Wire 指令.   將來大家想用什麼庫也沒限制.

我嘗試做一個 I2C 通訊系統的例子, 由簡單的一步步建立, 每一個段落的例子都可以獨立進行測試, 希望大家可以一步步了解.

由於是通訊系統,  最少要準備 兩塊 arduino 板子, 不需要是相同的, 任何組合也可以 (UNO, Nano, Mini, Mega 也沒關係).
三根杜邦線, 把 GND, A4, A5 都連上.  連接方法就是 相同的連起來.  GND-GND, A4-A4, A5-A5, 有多少塊都是接在一起就可以了.

為了方便之後的討論, 請選定一個作為 master, 其他都是 slave.  以後會用 master 板子, 及 slave 板子作稱呼.


暫定會有以下的題目, 將會一步一步發出, 完成後, 希望大家都可以做出一個簡單的 i2c 通訊系統.

(1) I2C 地址設定 及 I2C 地址掃瞄
(2) 由 master 向 slave 發送資料/發出指令 [slave 直接處理]
(3) 由 master 向 slave 發送資料/發出指令 [slave 延遲處理]
(4) 由 master 向 slave 要求資料回傳
(5) master 向 slave 要求不同資料
(6) 由 master 提供參數, 再由 slave 作出相應的回復
(7) 單片機有效傳送數據的選擇
(8) 浮點的傳送
(9) I2C 通訊實例(一) 簡單傳感數據收集 (把非 i2c 傳感變成 i2c)
(10) I2C 通訊實例(二) PM2.5 數據收集 (把較長時間的收集由 slave 完成)
(11) I2C 通訊實例(三) 總線舵機 (由 master 向 slave 發送指令)


以上只耍 (1) -  (4) 就可以了作出基本通訊, 而 (5), (6) 是加入一些簡單通訊協定, 讓 slave 有更多功能, 之後是一些實例, 用來演示 i2c 通訊的應用.

相關程式只在演示通訊的功能, 對 Wire 的錯誤完是沒有處理的, 有興趣可自己加入錯誤處理的程序.

Arduino 之間的 I2C 通訊 (1) I2C 地址設定 及 I2C 地址掃瞄

相關指令:

指令發出耆作用
Wire.begin([<address>]);master / slave啟動 Wire (由於 i2c 是用 Wire 的, 這就等同啟動 i2c 了)
Wire.beginTransmission(<address>);master開始對 <address> 的連線
Wire.endTransmission();master 關閉之前的連線



i2c 地址設定

i2c address 就像是你家中的地址, 每個 slave 都有自己的地址, 由於線路上只有一個 master, 加上 slave 只可以向 master 通訊, 所以 master 是不需地址的.

設定 i2c 地址, 基本上是沒有限制的, 只要同一線路上, 沒有重複就可以了.
要設定 slave 板子的地址, 只需要執行 Wire.begin(<地址>); 而 master 因為不需要地址, 只要 Wire.begin() 就可以了,.

以下是一個 slave 設定的例子, 把 slave 板子的地址設定為 0x12, 上載到 slave 板子上去執行就可以了.

#include <Wire.h>

#define SLAVE_ADDRESS 0x12

void setup() {
  Wire.begin(SLAVE_ADDRESS);    // join I2C bus as a slave with address 0x12
}

void loop() {
}


i2c 地址掃瞄

slave 建立後, 就要看看 master 如果找到它了.
i2c scanner 可以說是 master 板子的最基本例子, 可以用作測試線路上連接了的設備的存在 (只測試存在性, 並非測試其功能).
i2c_scanner 其實也很簡單, 由 master 向所有地址發出 beginTransmission 再 endTransmission, 嘗試建立連線.  在 beignTransmission 中輸入 slave 的地址, 就可以測試該地址的裝置了.

如果 error = 0 (沒 error), 即代表這個地址有設備登記
如果 error = 4 (這是 Wire 庫的設定, 不要問我為什麼是 4), 即代表這個地址可能有設備, 但有錯誤.
否則, 就代表該地址沒有設備使用了.

以下是一個簡單的 i2c scanner 程式:

#include <Wire.h>

#define SERIAL_BAUD 9600 

void setup()
{
  Wire.begin();
 
  Serial.begin(SERIAL_BAUD);
  Serial.println("I2C Scanner started");
  Serial.println();
}
 
 
void loop()
{
  uint8_t error, i2cAddress, devCount, unCount;
 
  Serial.println("Scanning...");
 
  devCount = 0;
  unCount = 0;
  for(i2cAddress = 1; i2cAddress < 127; i2cAddress++ )
  {
    Wire.beginTransmission(i2cAddress);
    error = Wire.endTransmission();
 
    if (error == 0)
    {
      Serial.print("I2C device found at 0x");
      if (i2cAddress<16) Serial.print("0");
      Serial.println(i2cAddress,HEX);
      devCount++;
    }
    else if (error==4)
    {
      Serial.print("Unknow error at 0x");
      if (i2cAddress<16) Serial.print("0");
      Serial.println(i2cAddress,HEX);
      unCount++;
    }    
  }

  if (devCount + unCount == 0)
    Serial.println("No I2C devices found\n");
  else {
    Serial.println();
    Serial.print(devCount);
    Serial.print(" device(s) found");
    if (unCount > 0) {
      Serial.print(", and unknown error in ");
      Serial.print(unCount);
      Serial.print(" address");
    }
    Serial.println();
  }
  delay(5000);
}

在這個例子中, 應該可以得到以下的結果:
I2C Scanner started

Scanning...
I2C device found at 0x12
1 device(s) found

 I2C Scanner 是非常有用的, 當你買了一個新裝置, 如果送來的程式不成功, 先看看相關地址是否可找到裝置, 可簡單測試裝置是否有問題.


相關程式下載:


2015年7月18日 星期六

SD Card 模塊

SD Card 模塊, 都無乜特別, 咪就係用黎讀寫 SD Card 咁大把.
有時用黎做下 logging 都幾好既, 又或者可以用黎放歌仔去播.


睇睇樣先:



基本資料:


電壓:5V/3.3V
接口:SPI


相關資料下載:




接線方法:


UNOSD Module
D4 / D10CS
D11MOSI
D12MISO
SCKD13
5V/3.3V5V/3.3V
GNDGND

注意:
一般 CS 係接 D10 既, 不過官網上既例子係用左 D4.  所以要睇清楚去接.
呢塊野可以用 5V 或 3.3V 既, 如果 UNO 就無所謂, 無樣都有, 否則就跟番你塊板有乜接乜.



測試程式:

基本上 Arduino IDE 本身已有唔少 (File->Examples->SD), 我都唔想多講.
不過就左方便對比, 做左幾個測試結果出黎.

首先搵左張 2GB 既 SD card (注意, 佢唔支援 SDHC 的, 一定要最弱既 SD).
Format 用 FAT16, 再整左一個 ReadMe.Txt, 一個 Arduino 既 Folder, 入面有個 Dummy.Txt.
全部 file 都係吉既, 只係為左測試用.

注意, 因為部份 example 會寫 file, 呢個結果係由 吉card 順住做的.
而當中有幾個會不斷 write 野, 中途停佢好似會出事.  個 Example 應該加個位比人 quit.

執行 CardInfo 既結果:



執行 Datalogger 既結果:
(注意, 因為一 upload 完佢就行, 係咁 send 野, 有可能你一開始仲有幾個數字的)


執行 Datalogger 既結果:
(注意, 同樣一 upload 完佢就行, 係咁 send 野, 有可能你一開始仲有幾個數字的)


執行 Files 既結果:


執行 listfiles 既結果:
玩完上面幾個 examples, 因為經常會 write 緊果下停, 有機會出現呢個 error, 今次剛好在測試 listfiles 時出現.  


只好再 format 佢一次, create 番之前講既 file 再行.

最後係執行埋 ReadWrite...好不幸, 出 error:

抽出黎再試左幾次都係一樣.  開番張 card 黎睇, 無哂我之前 create 既野, 得番一個 TEST.TXT, 入面吉既.   咁又試下再 format 張 card, 吉既比佢行.  結果都係一樣, 放棄了.

最後提提大家, 今次 Arduino IDE 入面既 Example, 真係好差.  SD card 既 read / write, 除非你做 自動系統, 否則 read / write SD card 最好有少少 UI, 避免 read / write 過程中 SD card 被拔走.

之前自己做既 logging, 一個自動化系統, 每次 write 緊都會亮燈, write 完即 close file 等一等就熄燈.  而且每次再 write 都會有一定時間分隔.  除非死機, 否則自己見到亮燈就唔會停佢.




2015年7月13日 星期一

32路舵機控制板 (TOROBOT Robot Kits)

呢塊 32路舵機控制板 (TOROBOT Robot Kits) 絕對係山寨廠既經典, 功能超強勁.

本來我仲有埋佢既細佬, 16路舵機控制板,  點知比我一野唔小心, short 左線即燒.
以後都唔敢開哂電攪 D 線, 話哂 16路都要百幾蚊, 一秒就 KO 左.

官方網站:   TOROBOT Robot Kits
淘寶連結:   史上最强 Arduino USB 32路 舵机控制板 控制器 驱动 支持PS2手柄


相關資料:
官網既資料包, 一舊包哂以下既野 
(有中又有英, 招呼周到.  鐘意可以一個個 download, 不過下面係官網連結, 可能會死 link)
官方更新包包 (2017-05-19)

32路舵機控制板 SSC-32U

今次介紹既係 32路舵機控制板



當然, 我唔係買左呢塊喇, 我買既只係 山寨板32路舵機控制板:



有關資料:


16 路舵機控制板 PCA9685

呢塊野都幾得意, 但係D資料好散, 自己放埋一齊方便搵.

1) 相關網站


2) 相關資料下截
3) 連線

UNOServo Driver
A4SDA
A5SCL
5vVCC
GNDGND

另外要接 5-6V 既電源去比舵機用

詳情可以睇 https://learn.adafruit.com/16-channel-pwm-servo-driver?view=all
(或者上面個 16-channel-pwm-servo-driver.pdf)


2015年7月6日 星期一

Arduino 基本資料

硬件資料:


開發環境

建構中........諗到再加

步進電機 (三) : TPS20U + EasyDriver (A3967 驅動板)

唔係呀, 又黎 A3967?  TPS20U 有乜特別?
好老實講, 真係完全無特別.  問題係, TPS20U 搵唔到資料, 今次主要講對住隻唔知既電機點算.




從佢個 pat pat 可以知道, 佢係用 12V 電, 同埋係 1:30 既, 即係轉一圈步數既比例應該係 30 既倍數.
之前隻 28BYJ-48, 轉一圈就 16384 steps, 諗住差唔多就比 15000 試下, 點知一野就轉左 2 個半圈.  就係咁, 15000 / 2.5 = 6000, 用 6000 steps 肉眼睇應該係一圈了.
至於點解會係 6000 = 30 * 200, 真係要慢慢研究下了.

玩左一排 CNC, 對步進了解多左少少, 番黎補充下:
初步估計, 呢隻步進應該係 1.8度 角, 30 細分.  所以轉一個圈就係 (360 / 1.8) * 30 = 6000 格了.
點解會係 30 細分呢?  可能上面既 1/30 就係咁解掛.
咁點解又係 1.8 度?  我叫 D 42 步進, 多數係 1.8 度, 有 D 0.9度, 當左係掛.
唔理得咁多了, 最後結果做到就當係先喇.

之後就係認番 D 線出黎, 唔係點接..
呢隻網上講係 4 相既, 點都係搵番條中線出黎.
容易喇, 先固定一條, 同其他四條度下電阻, 如果四條一樣, 呢條就係中線.
如果三條一樣, 有一條唔同, 咁果條就係中線, 再用果條同其他三條度下, 應該全部一樣.
咁就可以肯定, 呢條係中線了.

結果....藍色果條就係中線 (...其實唔駛度, 藍色本身就係插頭既中線.)
之後, 通常會係 AB中AB 去排既 (唔係就 AA中BB), 咁就用 1-4, 2-5 兩組接 EasyDriver.
A[紅,黃], B[黑,白] - 結果好好彩一野就中.


基本資料:

等我搵下先, 遲下 update 番.


接線方法:


UNOEasyDriver
D2STEP
D3DIR
GNDGND

測試程式:
SM_TPS20U_A3967.ino


2015年7月4日 星期六

步進電機 (二) : 28BYJ-48 + EasyDriver (A3967 驅動板)

睇到個標題, 係咪好怪呢.  通常用得 EasyDriver, 都唔會玩隻 cheap cheap 步進.
偏偏我呢個 cheap 佬, 家陣初學玩 步進電機, 手頭接好哂線就係得呢隻.
已經網上淘緊幾隻 39 同 42 (1.8 度同 0.9度都買定) 既步進番黎了.
家陣玩用住隻 cheap 野, 試下點用張 EasyDriver 先.

隻步進之前都介紹過, 今次主要試下點用張 EasyDriver.

淘番黎既板, 本身無焊針腳既.  為左方便插麵包板試, 我焊左去板背.
前面好多野, 焊到好驚, 唔知有無焊死D乜野.


基本資料:

太複雜了, 可以去參考以下網站資料:


簡單講下張卡既接口資料, 用黎測試步進, 基本上只需要用到以下接口:

DIR連接 MPU, 控制轉動方向
STEP連接 MPU, 改善電壓發出轉動的指令 (一次 High/Low = 一步)
GND連接 MPU, 接地
PWR IN (M+)連接 電機電源 (+) ; 6 - 30V, 2A+
PWR IN (GND)連接 電機電源 (-)
MOTOR - A(L)連接 電機 A+
MOTOR - A(R)連接 電機 A-
MOTOR - B(L)連接 電機 B+
MOTOR - B(R)連接 電機 B-

注意, 雖然 28BYJ-48 只係 DC 5V, 但如果輸入 5V 電源, 電流唔夠, 未必可以推動的.
而且, 用 EasyDriver, 你可以用好大既電壓比佢, 問題只係你隻電機可能會好熱.
如果太熱既, 可以嘗試調較 EasyDriver 上面既 CUR Adj.
我既測試係用 7.4V 輸入, 一切都正常, 電機係會熱少少.
但速度上比用 ULN2003 接 arduino 取 5V 電快少少.


相關資料下載:
Allegro A3967 Datasheet

接線方法:

UNOULN2003
D2STEP
D3DIR
GNDGND



測試程式:
SM_28YBJ48_A3967.ino


2015年7月1日 星期三

Arduino 之間的溝通 (一) 通訊方式

在 arduino 上, 雖然都算有十幾個 I/O, 但係左接右接, 有時都唔係好夠用.
特別係如果想 arduino 板之間要傾計, 就更加有問題了.

如果只係兩塊, 最簡單就係用串口, 或者 經 softwareSerial 都 OK.  RX 接 TX, 詳情唔駛講了.

不過, 如果有幾塊 arduino 板想傾計, 就唔同咁講了, 呢個 Topic 主要都係想講呢樣.
基本上我聽過又或者識既, 有以下既方法:

1. 串口通訊

優點: 簡單, 不用太多資源, 支援任何兩片之間通訊
缺點: 發送時間比較慢, 由於每片 arduino 有自己的工作, 如果由第 n 塊發給第 n-1 塊, 就要浪費很多次通訊了.

如果用 Serial, 由於 Serial 係點對點連線, 要串通哂都唔係易.
加上每塊 arduino 既串口有限, mega 都係得 4 個, 一般只係得一個, 點連?
最簡單可以用 ring 既連接, 當每塊板有編號, 第 n 塊既 RX 接 第 n-1 塊既 TX, 一直串落去, 最後一塊接番上第一塊.
而每個 request 都有發送同接收地址, 收到唔係自己既就 pass 比下一位, 如此類推.
當收到比自己既就處理並停止發送, 如果收番自己發出既就當無人又停止.


詳情請看.....(未發表, 老作中, 遲下更新)

2. i2c (Inter-Integrated Circuit, I2C or IIC)

優點: 速度快
缺點: 一切通訊由 master 發起, slave 只可以跟 master 通訊, 只有一個 master 可以接其他 i2c device,

呢個係我自己比較喜歡既方式, 優點係速度快同簡單. 暫時仲未研究到一塊 arduino 點樣可以接上兩個 i2c bus, 所以當某塊 arduino 以 slave 身份加入 i2c 後, 就唔可以用佢去接其他 i2c device 了.
如果有需要分開去接唔同既 i2c device, 就用唔到呢個方法了.
詳情請看.....(未發表, 老作中, 遲下更新)


3. SPI (Serial Peripheral Interface)

優點: 未知
缺點: 未知

有點似 i2c, 但仲未掌握到, 知道有咁既野先, 又遲下再研究.

4. Network IP (by network module, e.g W5100)

優點: 支援任何兩片之間通訊
缺點: 另購硬件, 網路的庫比較大, 耗資源, 需要額外的網路裝置

如果話用 IP (玩開PC, 最簡單就係 IP 了), 每塊 arduino 板都有裝埋 network.
而且, 個 network 既 library 都唔細, 唔化算.  呢個我都無去研究了.

5. Network IP (by serial connection, e.g.ESP8266)

優點: 支援任何兩片之間通訊, 相對簡單, 無線通訊
缺點: 另購硬件, 需要無線網路配合

我都唔知應該點叫, 由於 ESP8266 之類既 card, network 部份在 module 之內, 對 arduino 而言, 只係 serial communization.
呢個可能係一個幾好既方案, 而且仲要係無線通訊.
但係家陣 ESP8266 既庫未算完善, 而且仲要有一個 wireless 既 router 配合, 都係遲下再研究.

6. 藍牙

優點: 點對點無線通訊
缺點: 另購硬件, (未試過, 唔知得唔得)

藍牙基本上又係無線既 serial 連綠, 但手上無咁多藍牙模塊可以試, 不知是否可以 pair 多個 device...
如果可以, 不知如何分辨了...


7. (見到有新既就再加)

步進電機 (一) : 28BYJ-48 + ULN2003 驅動板

用 Arduino 玩 步進電機, 最基本套餐應該係 28BYJ-48 配合 ULN2003 驅動板了.


28BYJ-48 5V DC 步進電機

ULN2003 步進電機驅動板


電機跟驅動板的連接, 不會有難度吧, 直接把 5-pin 頭插到驅動板上就可以了.
28BYJ-48 連接 ULN2003


基本資料:

電壓:5V



相關資料下載:
28BYJ-48 (簡體)
ULN2003

接線方法:

UNOULN2003
D8IN1
D9IN2
D10IN3
D11IN4
5V+
GND-

雖然 28BYJ-48 只係 5V, 但係可以既話, 最好都係用番外接電源.  記得共地.


測試程式:
SM_28YBJ48_ULN2003.ino

Arduino 既 IDE, 本身已有 4 個 Stepper 既測試程式:
File->Examples->Stepper->
1. MotorKnob
2. stepper_oneRevolution
3. stepper_oneStepAtATime
4. stepper_speedControl

不過, 我試既時候, 反時針轉都係出順時針, 仲研究緊.
而網上 instructables.com 有比較詳細既介紹, 而且佢入面既 sample 係可以正反都無問題.
http://www.instructables.com/id/BYJ48-Stepper-Motor/?ALLSTEPS

呢隻係 4相步進電機, IDE example 入面只有 4 個 steps, 而 instructables 果個有 7 個 steps.
而 instructables.com 條 link 入面, 亦有講下點計數既.
不過, 就算跟佢計算, 改左 stepsPerRevolution 做 4096, 結果仲連行都唔行添.
可能真係同佢既幾個steps 有關,

Arduino IDE 既 example:
StepsPIN (1-2-3-4)
0H-L-H-L
1L-H-H-L
2L-H-L-H
3H-L-L-H

Instructables 既 example:
StepsPIN (1-2-3-4)
0L-L-L-H
1L-L-H-H
2L-L-H-L
3L-H-H-L
4L-H-L-L
5H-H-L-L
6H-L-L-L
7H-L-L-H

而我個測試程式, 就係基於 instructables 上面既例子, 作左少少改動.
主要係可以設定 轉一個圈既時間, 程式會自己轉番每一格既時間.
而結果會顯示設定既時間, 同實際執行時量度出既時間, 有少少出入.
由於有一定既 overhead, 一般量度出既時間, 會比預設既多左 0.02s 左右.
所以設定為 6 秒時, 執行結果每 round 大約係 6.02 秒.




有一點要提提, 大家可能發覺, 每個 step 順住或者反方向行, 同之前既 step 實際變化只有一個, 如果計埋反方向都係得兩個變化, 咁每次輸出兩個就夠了.

我嘗試過咁樣改, 每次只係出兩條 pin, 初時行無問題, 但試過行行下中途停下再開, 有機會進入左一個唔知點解再行唔到既狀態.  呢樣野可能要再研究下, 但如果每次都出哂四條 pin 既變化, 就肯定無問題.

2015年3月23日 星期一

Arduino 測距系列 (五) Sharp GP2D12

之前既都係用超聲波, 今次講隻貴野, 用紅外線測距既 GP2D12



基本資料:

電壓:4-5.5V
電流消耗:33-50mA
感應角度:不大於 15度
探測距離:10 - 80 cm
探測精度:0.1cm+1%
分辨率:高於 1mm (可達 0.5mm)


相關資料下載:
GP2D12
GP2D12 使用說明書
GP2D12 Data Sheet

接線方法:

呢度要小心, 因為佢D針腳無名, 用番上圖咁放, 由左至右分別係 Vo, GND, Vcc



UNOGP2D12
A0Vo
5VVcc
GNDGND


測試程式:

呢舊野真係玩死人, 由於佢條曲線無一個好既轉換公式, 基本上只係用比較接近既方法去轉換成真實距離.



比較多見既兩條公式:
(1) http://www.geek-workshop.com/forum.php?mod=viewthread&tid=734&highlight=gp2d12 :

distance = 2547.8 / (0.49 * val - 10.41) - 0.42;

(2) http://playground.arduino.cc/Main/ReadGp2d12Range :
(Manning 本 Arduino in action 既例子都係用呢個計)

distance = (6787.0 / (val - 3.0)) - 4.0;

兩條公式都幾唔同下, 當中差距都幾大下, 只係有部份會比較接近.
如果要兩條公式既差距在 5% 內的話, 只可以接受 val 大約為在 80 - 450 之間.
即距離大約在 10 - 80 cm 之間, 亦配合 GP2D12 的探測距離.
所以, 用以上兩條公式去計算, 差距在 5% 以內.  用邊條都可以.


Arduino 測距系列 (三) US-015

今次要講既係同之前 HC-SR04, HY-SRF05 有 D 唔同既 US-015



基本資料:

電壓:5V
靜態電流:2.2mA
感應角度:不大於 15度
探測距離:2 - 400 cm
探測精度:0.1cm+1%
分辨率:高於 1mm (可達 0.5mm)


相關資料下載:
US-015
US-015-V2.0


接線方法:


UNOUS-015
D2Echo
D3Trig
5VVCC
GNDGND


測試程式:

unsigned int EchoPin = 2;           // connect Pin 2(Arduino digital io) to Echo at US-015
unsigned int TrigPin = 3;           // connect Pin 3(Arduino digital io) to Trig at US-015
unsigned long Time_Echo_us = 0;
unsigned long Len_mm  = 0;
void setup()
{  //Initialize
    Serial.begin(9600);                        //Serial: output result to Serial monitor
    pinMode(EchoPin, INPUT);                    //Set EchoPin as input, to receive measure result from US-015
    pinMode(TrigPin, OUTPUT);                   //Set TrigPin as output, used to send high pusle to trig measurement (>10us)
}

void loop()
{
    digitalWrite(TrigPin, HIGH);              //begin to send a high pulse, then US-015 begin to measure the distance
    delayMicroseconds(20);                    //set this high pulse width as 20us (>10us)
    digitalWrite(TrigPin, LOW);               //end this high pulse
    
    Time_Echo_us = pulseIn(EchoPin, HIGH);               //calculate the pulse width at EchoPin, 
    if((Time_Echo_us < 60000) && (Time_Echo_us > 1))     //a valid pulse width should be between (1, 60000).
    {
      Len_mm = (Time_Echo_us*34/100)/2;      //calculate the distance by pulse width, Len_mm = (Time_Echo_us * 0.34mm/us) / 2 (mm)
      Serial.print("Present Distance is: ");  //output result to Serial monitor
      Serial.print(Len_mm, DEC);            //output result to Serial monitor
      Serial.println("mm");                 //output result to Serial monitor
    }
    delay(1000);                            //take a measurement every second (1000ms)
}

Arduino 測距系列 (四) US-016

今次要講既係 US-015 既兄弟 US-016



基本資料:

電壓:5V
靜態電流:2.2mA
感應角度:不大於 15度
探測距離:2 - 400 cm
探測精度:0.1cm+1%
分辨率:高於 1mm (可達 0.5mm)

US-016 既強項係唔駛再計算, analogRead 既數值就係距離既比.
而且, 佢自己不斷量度, 唔駛係叫佢 send 再等 receive.
對於某 D 要後應快既程式, 咁樣一野讀 analog reading 係最正既.
因為唔需要 delay, 甚至可以放入 ISR 入面用 (不過, 都唔太建議).

當量程為 1m 時, analogRead 既值就是距離 (cm).
當量程為 3m 時, 只需將 analogRead 既值 X3 就是距離 (cm).

相關資料下載:
US-016-1.1


接線方法:


UNOUS-016
A0Out
空置  - 3m
GND - 1m
Range
5VVCC
GNDGND


測試程式:

1m 量程 (Range 為低電平)
unsigned int ADCValue;
void setup()
{
    Serial.begin(9600);
}

void loop()
{

    ADCValue = analogRead(0);
    Serial.print("Present Length is: ");
    Serial.print(ADCValue, DEC);
    Serial.println("mm");
    delay(1000);//delay 1S
}


3m 量程 (Range 為空置或接高電平)
unsigned int ADCValue;
void setup()
{
    Serial.begin(9600);
}

void loop()
{

    ADCValue = analogRead(0);
    ADCValue *= 3;
    Serial.print("Present Length is: ");
    Serial.print(ADCValue, DEC);
    Serial.println("mm");
    delay(1000);//delay 1S
}

Arduino 測距系列 (二) HY-SRF-05

今次要講既係同 HC-SR04 差唔多既 HY-SRF05




基本資料:

電壓:5V
靜態電流:小於 2mA
電平輸出:高 5V; 低 0V
感應角度:不大於 15度
探測距離:2 - 450 cm
精確度:可達 0.3 cm

相關資料下載:
HY-SRF05


接線方法:

呢塊同 HC-SR04 好相似, 雖然有 5 隻支腳, 但都係用番果四支.  同樣以 D4, D5 接訊號線做例子.

UNOHY-SRF05
D4Echo
D5Trig
5VVCC
GNDGND

OUT 為開關量輸出, 當報警模塊使用 (未詳細研究, 遲下補上)

測試程式 (跟 HC-SR04 相同):

enum {
  SERIAL_BAUD = 9600,
  ECHO_PIN    = 4,
  TRIG_PIN    = 5
};


void setup() 
{
 Serial.begin(SERIAL_BAUD);
 Serial.println("HC-SR04 Tester");

 pinMode(ECHO_PIN, INPUT);
 pinMode(TRIG_PIN, OUTPUT);

}

void loop() 
{
  long duration, distance;
  digitalWrite(TRIG_PIN, LOW); 
  delayMicroseconds(2); 
  digitalWrite(TRIG_PIN, HIGH); // Pulse for 10ms to trigger ultrasonic detection 
  delayMicroseconds(10); 
  digitalWrite(TRIG_PIN, LOW); 
  duration = pulseIn(ECHO_PIN, HIGH); // Read receiver pulse time 
  distance = (duration / 2) / 29.1;
  if ((distance >= 200) || (distance <=0)) {
    Serial.println("Out of range");
  } else {
    Serial.print(distance); //Ourput distance
    Serial.println(" cm");
  }
  delay(500);
}

Arduino 測距系列 (一) HC-SR04

Arduino 用黎測距既模塊多 D 是, 手頭上都有幾塊唔同既, 方便自己, 遂一記低點用.

首先係 HC-SR04


基本資料:

電壓:5V
靜態電流:小於 2mA
電平輸出:高 5V; 低 0V
感應角度:不大於 15度
探測距離:2 - 450 cm


相關資料下載:
HC-SR04


接線方法:

呢個模塊主要得四支針, Vcc, Trig, Echo 同埋 Gnd, 兩條訊號線接乜野 I/O 無所謂, 暫時以 D4, D5 做例子.

UNOHS-SR04
D4Echo
D5Trig
5VVCC
GNDGND


測試程式:

enum {
  SERIAL_BAUD = 9600,
  ECHO_PIN    = 4,
  TRIG_PIN    = 5
};


void setup() 
{
 Serial.begin(SERIAL_BAUD);
 Serial.println("HC-SR04 Tester");

 pinMode(ECHO_PIN, INPUT);
 pinMode(TRIG_PIN, OUTPUT);

}

void loop() 
{
  long duration, distance;
  digitalWrite(TRIG_PIN, LOW); 
  delayMicroseconds(2); 
  digitalWrite(TRIG_PIN, HIGH); // Pulse for 10ms to trigger ultrasonic detection 
  delayMicroseconds(10); 
  digitalWrite(TRIG_PIN, LOW); 
  duration = pulseIn(ECHO_PIN, HIGH); // Read receiver pulse time 
  distance = (duration / 2) / 29.1;
  if ((distance >= 200) || (distance <=0)) {
    Serial.println("Out of range");
  } else {
    Serial.print(distance); //Ourput distance
    Serial.println(" cm");
  }
  delay(500);
}

2015年1月30日 星期五

重燒 Bootloader

無事無幹, 無端端燒乜鬼 Bootloader 喎. 不過衰起上黎, 避都避唔到既.
為免次次都要四圍搵番點燒, 不如自己記低佢, 方便搵.

為免攪錯, 用兩塊唔同既板, 由 UNO 幫 Pro Mini 燒 Bootloader.

(1) 首先, 將 UNO 變身成為 Programmer.

  1. 將 UNO 連接電腦, 打開 Arduino IDE, 選好有關既 Port 同 UNO 連接既 Port
  2. 打開 ArduinoISP 的 sketch 
  • File->Examples->ArduinoISP
  1. 當然係將 ArduinoISP 既 sketch upload 去 UNO 度喇.


(2) 當 UNO 裝左 ArduinoISP 後, 就可以同 ProMini 連接 (連線前最好先拔走 USB 線斷電)
再提醒一次, 唔好攪錯, 呢個例子係當 Pro Mini 死左 Bootloader, 由 UNO 幫佢燒.

接腳: (記住 check 清楚比人燒果張係用 3.3V 定係 5V, 自己執生)

UNO Pro Mini
D10RST
D11D11
D12D12
D13D13
3.3V / 5VVCC
GNDGND



(3) 可以同 UNO 接番 USB 線 (唔好接錯, 係接 UNO, 即係 Programmer), 然後選 Board.
注意, 今次係選要燒 Bootloader 果塊, 所以今次係 ProMini 而唔係 UNO.

  • Tools->Board->Arduino Pro or Pro Mini

有 D board 可能要選埋 Processor 既, 例如 ProMini 就係了, 我果塊要再選

  • Tools->Processor->ATmega328 (5V, 16MHz)


之後再選 Programmer

  • Tools->Programmer->Arduino as ISP


(4) 一切準備好, 就可以開始燒 Bootloader 了:

  • Tools->Burn Bootloader


見到呢句就攪掂哂了.







在 Blogger 中使用 SyntaxHighlighter

緊急事故: 
唔知乜事, alexgorbatchev.com 突然 connection refused.
都係想辦法將 syntax highlighter 放去自己既 web site 好 D.
syntax highlighter 既 source 仲可以去 GitHub 下載: https://github.com/syntaxhighlighter/syntaxhighlighter



由於諗住記低 D program, 如果無 SyntaxHighligh 真係幾難睇.
第一時間網上搵下點樣夾到 SyntaxHighlighter 入黎.


(1) 去到自己既 blogger, click [設計]


(2) 入左去範本既網頁, 就選 [編輯 HTML]


(3) 然後就 copy 段 code 去 <head> 同 </head> 之間

 
 <script src="http://alexgorbatchev.com/pub/sh/current/scripts/shCore.js" type="text/javascript" />
 <script src="http://alexgorbatchev.com/pub/sh/current/scripts/shBrushCpp.js" type="text/javascript" />
 <script src="http://alexgorbatchev.com/pub/sh/current/scripts/shBrushJScript.js" type="text/javascript" />
 <script src="http://alexgorbatchev.com/pub/sh/current/scripts/shBrushJava.js" type="text/javascript" />
 <script src="http://alexgorbatchev.com/pub/sh/current/scripts/shBrushSql.js" type="text/javascript" />
 <script src="http://alexgorbatchev.com/pub/sh/current/scripts/shBrushVb.js" type="text/javascript" />
 <script src="http://alexgorbatchev.com/pub/sh/current/scripts/shBrushXml.js" type="text/javascript" />
 <link href="http://alexgorbatchev.com/pub/sh/current/styles/shCoreDefault.css" rel="stylesheet" type="text/css" />
 < type="text/javascript">
  SyntaxHighlighter.config.bloggerMode = true; 
  SyntaxHighlighter.all();
 </script>
 
一點遺憾: 
SyntaxHighlighter 提供了 <pre /> 及 <script /> 兩種方法, 但都無法直接貼出上面的 code.
<pre />: 要把當中 < 改成 &lt; , 否則會出問題。
<script />: 本來是最接近成功的, 但最後一段的 </script> 還是會出事.
詳情請看: http://alexgorbatchev.com/SyntaxHighlighter/manual/installation.html
.

我只係加左幾隻 language (JavaScript, Java, SQL, VisualBasic 同埋 XML, 有需要可以自己再加其他 brush 去增加佢 support 既 language.   有關其他可用既 brush, 可以去呢度睇:

http://alexgorbatchev.com/SyntaxHighlighter/manual/brushes/


(4) 之後發表文章時, 在中間加入 program code, 只要轉去 HTML 版面, 前後加上 <pre ...> ..</pre> 就可以了. 例如家陣呢個 page, 上面有段 HTML code,  就係用左 <pre class="brush:xml" name="code">:



(*) 既然個 blog 係為 Arduino 而生, 就整番段標準既 empty sketch 結尾喇:


void setup() {
  // put your setup code here, to run once:

}

void loop() {
  // put your main code here, to run repeatedly:

}



無無聊聊, 開篇野試下先

上年手痕買左塊 Arduino UNO, 好似幾好玩, 開番個 blog 去記低D野, 唔駛左搵右搵.
一切由佢開始......


呢個 blogger 有 D 唔方便, 原來只可以上傳 相片, 唔可以上 file, 想用黎放埋 D source 都唔得添.
仲研究緊有無得加入 program source 係有 syntax highlight 既, 如果唔得....可以摺埋算了.