今回はGroveシリアルカメラのサンプルコードを簡単に解説したいと思います。
以下の記事でGroveシリアルカメラを使ったときにサンプルコードがうまく動作しなかったので中身がどのようになっているかざっくりと調べてみました。
今後Groveシリアルカメラを使う人の役に立てばよいかなと思います。
サンプルコードの概要について
Groveシリアルカメラのサンプルコードでは以下の構成になっています。
①「void loop」で処理が繰り返され、ボタンを押すとキャプチャ取得処理「void Capture」とSDカードに保存する処理「void GetData」が順次呼び出される。
②キャプチャ取得処理「void Capture」では、コマンド送信処理「void sendCmd」を呼び出して配列に格納されたコマンドをGroveシリアルカメラへと送信している。
③SDカードに保存する処理「void GetData」では、キャプチャ取得処理からデータを受け取りSDカードに保存している。
以下、処理ごとにコメントを追記しています。
void setupについて
void setupには通信速度などを設定します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
void setup() { Serial.begin(115200); // ←通信速度を指定します pinMode(buttonPin, INPUT); // 押しボタンを入力に設定します Serial.println("Initializing SD card...."); pinMode(10,OUTPUT); // CS pin of SD Card Shield if (!SD.begin(10)) { Serial.print("sd init failed"); return; } Serial.println("sd init done."); initialize(); } |
void loopについて
void loopではボタンを押下すると写真撮影が始まるようになっています。まず、「Capture()」でキャプチャ取得処理が呼ばれ、次に「GetData()」で写真がSDカードに保存されます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
void loop() { int n = 0; while(1){ Serial.println("\r\nPress the button to take a picture"); while (digitalRead(buttonPin) == LOW); if(digitalRead(buttonPin) == HIGH){ //←ボタンを押すと撮影が始まります delay(20); if (digitalRead(buttonPin) == HIGH) { Serial.println("\r\nbegin to take picture"); delay(200); if (n == 0) preCapture(); Capture(); //←キャプチャ取得処理を呼ぶ GetData(); //←SDカード保存処理を呼ぶ } Serial.print("\r\nTaking pictures success ,number : "); Serial.println(n); n++ ; } } } |
void clearRxBufについて
バッファの中身をクリアする処理です。コマンド送信前に呼ばれています。
1 2 3 4 5 6 7 |
void clearRxBuf() //←バッファのクリア { while (Serial.available()) { Serial.read(); } } |
void sendCmdについて
コマンドの送信処理です。コマンドの中身は呼び出し元で格納されています。コマンドは配列「cmd」に格納されています。
1 2 3 4 |
void sendCmd(char cmd[], int cmd_len) //←コマンドの送信 { for (char i = 0; i < cmd_len; i++) Serial.print(cmd[i]); } |
void initializeについて
void initializeでは、初期化処理を行っています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
void initialize() //←初期化処理 { char cmd[] = {0xaa,0x0d|cameraAddr,0x00,0x00,0x00,0x00} ; unsigned char resp[6]; Serial.setTimeout(500); while (1) { //clearRxBuf(); sendCmd(cmd,6); //←コマンド送信処理の呼び出し if (Serial.readBytes((char *)resp, 6) != 6) { continue; //←繰返し処理の次の処理をスキップ } if (resp[0] == 0xaa && resp[1] == (0x0e | cameraAddr) && resp[2] == 0x0d && resp[4] == 0 && resp[5] == 0) { if (Serial.readBytes((char *)resp, 6) != 6) continue; if (resp[0] == 0xaa && resp[1] == (0x0d | cameraAddr) && resp[2] == 0 && resp[3] == 0 && resp[4] == 0 && resp[5] == 0) break; } } cmd[1] = 0x0e | cameraAddr; cmd[2] = 0x0d; sendCmd(cmd, 6); //←コマンド送信処理の呼び出し Serial.println("\nCamera initialization done."); } |
void preCaptureについて
プレキャプチャを取得しています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
void preCapture() //←プレキャプチャ { char cmd[] = { 0xaa, 0x01 | cameraAddr, 0x00, 0x07, 0x00, PIC_FMT }; //↑配列にコマンドを格納 unsigned char resp[6]; Serial.setTimeout(100); while (1) { clearRxBuf(); //バッファのクリア sendCmd(cmd, 6); //コマンド送信処理の呼び出し if (Serial.readBytes((char *)resp, 6) != 6) continue; if (resp[0] == 0xaa && resp[1] == (0x0e | cameraAddr) && resp[2] == 0x01 && resp[4] == 0 && resp[5] == 0) break; } } |
void Captureについて
void Captureでは段階を踏んでカメラにコマンドを送信し、キャプチャを取得しています。void Captureは「void loop」から呼び出されています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 |
void Capture() //←キャプチャ取得処理 { char cmd[] = { 0xaa, 0x06 | cameraAddr, 0x08, PIC_PKT_LEN & 0xff, (PIC_PKT_LEN>>8) & 0xff ,0}; //↑配列にコマンドを格納 unsigned char resp[6]; Serial.setTimeout(100); while (1) { clearRxBuf(); //バッファのクリア sendCmd(cmd, 6); //コマンド送信処理の呼び出し if (Serial.readBytes((char *)resp, 6) != 6) continue; if (resp[0] == 0xaa && resp[1] == (0x0e | cameraAddr) && resp[2] == 0x06 && resp[4] == 0 && resp[5] == 0) break; } cmd[1] = 0x05 | cameraAddr; //配列「cmd[1]~cmd[5]」に次のコマンドを格納していく cmd[2] = 0; cmd[3] = 0; cmd[4] = 0; cmd[5] = 0; while (1) { clearRxBuf(); //バッファのクリア sendCmd(cmd, 6); //コマンド送信処理の呼び出し if (Serial.readBytes((char *)resp, 6) != 6) continue; if (resp[0] == 0xaa && resp[1] == (0x0e | cameraAddr) && resp[2] == 0x05 && resp[4] == 0 && resp[5] == 0) break; } cmd[1] = 0x04 | cameraAddr; //配列「cmd[1]~cmd[2]」に次のコマンドを格納していく cmd[2] = 0x1; while (1) { clearRxBuf(); //バッファのクリア sendCmd(cmd, 6); //コマンド送信処理の呼び出し if (Serial.readBytes((char *)resp, 6) != 6) continue; if (resp[0] == 0xaa && resp[1] == (0x0e | cameraAddr) && resp[2] == 0x04 && resp[4] == 0 && resp[5] == 0) { Serial.setTimeout(1000); if (Serial.readBytes((char *)resp, 6) != 6) { continue; } if (resp[0] == 0xaa && resp[1] == (0x0a | cameraAddr) && resp[2] == 0x01) { picTotalLen = (resp[3]) | (resp[4] << 8) | (resp[5] << 16); Serial.print("picTotalLen:"); Serial.println(picTotalLen); //picTotalLenを出力します break; //ここまでくると繰返し処理を抜けます } } } } |
void GetDataについて
SDカードに写真を保存します。SDカードに保存される1枚目のファイル名は「pic00.jpg」となります。2枚目以降からは「pic01.jpg」、「pic02.jpg」というように保存されていきます。SDカードに写真を保存できなかったときはシリアルモニタに「”myFile open fail…”」と表示され、成功した場合はSDカードに写真が保存されます。
なお、void GetDataは「void loop」から呼び出されています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
void GetData() //←SDカードに保存する処理 { unsigned int pktCnt = (picTotalLen) / (PIC_PKT_LEN - 6); if ((picTotalLen % (PIC_PKT_LEN-6)) != 0) pktCnt += 1; char cmd[] = { 0xaa, 0x0e | cameraAddr, 0x00, 0x00, 0x00, 0x00 }; unsigned char pkt[PIC_PKT_LEN]; char picName[] = "pic00.jpg"; //←初期のファイル名 picName[3] = picNameNum/10 + '0'; //←ファイル名の左から4番目の文字が動的に変わる picName[4] = picNameNum%10 + '0'; //←ファイル名の左から5番目の文字が動的に変わる if (SD.exists(picName)) { SD.remove(picName); } myFile = SD.open(picName, FILE_WRITE); if(!myFile){ Serial.println("myFile open fail..."); //←SDカードのファイルが開けなかった場合(失敗した場合) } else{ //←SDカードのファイルが開けた場合(成功した場合) Serial.setTimeout(1000); for (unsigned int i = 0; i < pktCnt; i++) { cmd[4] = i & 0xff; cmd[5] = (i >> 8) & 0xff; int retry_cnt = 0; retry: delay(10); clearRxBuf(); //バッファのクリア sendCmd(cmd, 6); //コマンド送信処理の呼び出し uint16_t cnt = Serial.readBytes((char *)pkt, PIC_PKT_LEN); unsigned char sum = 0; for (int y = 0; y < cnt - 2; y++) { sum += pkt[y]; } if (sum != pkt[cnt-2]) { if (++retry_cnt < 100) goto retry; else break; } myFile.write((const uint8_t *)&pkt[4], cnt-6); //if (cnt != PIC_PKT_LEN) break; } cmd[4] = 0xf0; cmd[5] = 0xf0; sendCmd(cmd, 6); } myFile.close(); picNameNum ++; } |
以上、今回はGroveシリアルカメラのサンプルコードを簡単に解説させていただきました。
コメントを残す