Arduino互換ボード『Waffle』にGroveのシリアルカメラキットをつなごうとしているがうまくいかないので、その奮闘記をログとして残しておきます。
【注意】うまくいく方法がわかりました。こちらの記事を参照してください。(以下の情報には間違いがあります)
Waffleとは
こちらを参照のこと。
シリアルカメラモジュールとは
こちらを参照のこと。
接続ポート
使用するケーブルは、シリアルカメラキットに含まれているものではなく、ストレートです。
この件に関してはこちらを参照してください。
プログラム
カメラとの接続は、ハードウェアリシアルではなくて、ソフトウェアシリアルを使用します。
#include <SoftwareSerial.h>
#define PIC_FMT_VGA 7
#define PIC_FMT_CIF 5
#define PIC_FMT_OCIF 3
#define CAM_ADDR 0
#define CAM_SERIAL softSerial
#define PIC_FMT PIC_FMT_VGA
SoftwareSerial softSerial(5, 6); //rx,tx
const byte cameraAddr = (CAM_ADDR << 5); // addr
WaffleのD5ポートは、D5がPD5に、D6がPD6につながっていますので、カメラ側の「送信」「受信」に合わせて、受信をD5、送信をD6とします。
次に、初期化(setup())で、カメラの初期化を行います。
/*********************************************************************/
void setup() {
Serial.begin(115200);
CAM_SERIAL.begin(9600); //cant be faster than 9600, maybe difference with diff board.
initialize();
}
まず、PCへのモニター出力の通信速度を115,200bpsで設定しています。(これは特に意味はありません)
次に、カメラと接続しているソフトウェアシリアルの通信速度を9,600bpsに設定しています。
カメラの仕様上は115,200bpsまで行けそうですが、今回の接続はUARTではない(RS-232を使用)ので9,600bpsにしておきます。
/*********************************************************************/
void sendCmd(char cmd[], int cmd_len)
{
for (char i = 0; i < cmd_len; i++) CAM_SERIAL.write(cmd[i]);
}
/*********************************************************************/
int readBytes(char *dest, int len, unsigned int timeout)
{
int read_len = 0;
unsigned long t = millis();
while (read_len < len)
{
while (CAM_SERIAL.available()<1)
{
if ((millis() - t) > timeout)
{
return read_len;
}
}
*(dest+read_len) = CAM_SERIAL.read();
//Serial.write(*(dest+read_len));
read_len++;
}
return read_len;
}
/*********************************************************************/
void initialize()
{
char cmd[] = {0xaa,0x0d|cameraAddr,0x00,0x00,0x00,0x00} ;
unsigned char resp[6];
Serial.print("initializing camera...");
while (1)
{
// Send "SYNC"
sendCmd(cmd,6);
// Read "ACK"
if (readBytes((char *)resp, 6,1000) != 6)
{
Serial.print(".");
continue;
}
if (resp[0] == 0xaa && resp[1] == (0x0e | cameraAddr) && resp[2] == 0x0d && resp[4] == 0 && resp[5] == 0)
{
// Read "SYNC"
if (readBytes((char *)resp, 6, 500) != 6){
continue;
}
if (resp[0] == 0xaa && resp[1] == (0x0d | cameraAddr) && resp[2] == 0 && resp[3] == 0 && resp[4] == 0 && resp[5] == 0) break;
}
}
// Send "ACK"
cmd[1] = 0x0e | cameraAddr;
cmd[2] = 0x0d;
sendCmd(cmd, 6);
//Serial.println("\nCamera initialization done.");
}
初期化の関数内で、カメラとハンドシェイクを行っています。
Waffle「SYNC」→カメラ「ACK」→カメラ「SYNC」→Waffle「ACK」
となっています。
問題発生
残念ながら、現状は、Waffleから「SYNC」を送り、カメラから返事(6バイト)が返ってきているのですが、なぜかすべて0になっています。(0x00が6つ)
これは正式な電文ではないので、どこかでうまく受け取れていないようです。
ただ、ちゃんと6バイト返している(返してきているバイト数は確認済み)ところから考えて、以下の可能性があると予想しています。
- ビットが立っている(5V)はずが立っていなくて(電圧が低くて)、0と判断されている(ハード側の問題)
RS-232
そもそも、カメラ側のインターフェースはRS-232なのですが、こちらの規格は以下のような電圧差でビットのON/OFFを判断しています。
つまり、+3V~+13Vだったら0、-3V~-13Vだったら1ということになります。(※出力の場合は+5V~+15Vが0、-5V~-15Vが1)
ちなみに、Groveは0V~0.8Vが0で+2V~+5Vが1になります。
つまり、Waffleからカメラへの送信信号はなんとかカメラ側で読めるのですが、カメラ側からWaffle側への送信信号は読めないということになります。
この間の変換(RS-232-TTL変換)を行うのがMAX232等のチップになるようです。
結論
ということで、間に変換をかまさないとダメのようです。
※工作は辛いから、こんな感じのものを利用すればいいのかな?