// ArduCAM demo (C)2017 Lee
// Web: http://www.ArduCAM.com
// This program is a demo of how to use most of the functions
// of the library with a supported camera modules, and can run on any Arduino platform.
//
// This demo was made for Omnivision 2MP/5MP sensor.
// It will run the ArduCAM 2MP/5MP as a real 2MP/5MP digital camera, provide both JPEG capture.
// The demo sketch will do the following tasks:
// 1. Set the sensor to JPEG mode.
// 2. Capture and buffer the image to FIFO every 5 seconds
// 3. Store the image to Micro SD/TF card with JPEG format in sequential.
// 4. Resolution can be changed by myCAM.set_JPEG_size() function.
// This program requires the ArduCAM V4.0.0 (or later) library and ArduCAM 2MP/5MP shield
// and use Arduino IDE 1.6.8 compiler or above
#include <ArduCAM.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include "memorysaver.h"
//This demo can only work on OV2640_MINI_2MP or OV5642_MINI_5MP or OV5642_MINI_5MP_BIT_ROTATION_FIXED platform.
#if !(defined OV5642_MINI_5MP || defined OV5642_MINI_5MP_BIT_ROTATION_FIXED || defined OV2640_MINI_2MP || defined OV3640_MINI_3MP)
#error Please select the hardware platform and camera module in the ../libraries/ArduCAM/memorysaver.h file
#endif
#define SD_CS 9
const int SPI_CS = 10;
ArduCAM myCAM( OV2640, SPI_CS );
// Realtime Clock
#define PIN_CE 2
#define PIN_IO 3
#define PIN_SCLK 4
static char clockTime[19]; // 時刻表示用文字列
static char shortTime[7]; // 撮影用文字列
static char dirTime[9]; // ディレクトリ用文字列
#define LED_PIN 8
#define BTN_PIN 7
boolean writeStatus=false;
String recv;
//SPISettings settingsArduCam(2000000, MSBFIRST, SPI_MODE0);
//SPISettings settingsSDCard(250000, MSBFIRST, SPI_MODE0);
SPISettings settingsArduCam(500000, MSBFIRST, SPI_MODE0);
SPISettings settingsSDCard(4000000, MSBFIRST, SPI_MODE0);
#define LOCK_NONE 0
#define LOCK_ARDUCAM 1
#define LOCK_SDCARD 2
void spi_lock(int lock) {
static int status = -1;
if (lock==LOCK_NONE) {
SPI.endTransaction();
status = -1;
return;
}
if (lock!=status) {
SPI.endTransaction();
if (lock==LOCK_ARDUCAM) {
SPI.beginTransaction(settingsArduCam);
} else if (lock==LOCK_SDCARD) {
SPI.beginTransaction(settingsSDCard);
}
status = lock;
}
}
void myCAMSaveToSDFile(){
byte buf[256];
static int pos = 0;
char filename[20];
char header[7];
uint8_t prev = 0;
uint32_t length = 0;
uint32_t total = 0;
File outFile;
//Flush the FIFO
myCAM.flush_fifo();
//Clear the capture done flag
myCAM.clear_fifo_flag();
//Start capture
myCAM.start_capture();
Serial.println(F("start Capture"));
delay(50);
while(!myCAM.get_bit(ARDUCHIP_TRIG , CAP_DONE_MASK));
Serial.println(F("Capture Done."));
length = myCAM.read_fifo_length();
Serial.print(F("The fifo length is :"));
Serial.println(length, DEC);
if (length >= MAX_FIFO_SIZE) //384K
{
myCAM.clear_fifo_flag();
Serial.println(F("Over size."));
return ;
}
if (length == 0 ) //0 kb
{
myCAM.clear_fifo_flag();
Serial.println(F("Size is 0."));
return ;
}
// JPEG FILE FFD8~FFD9
// skip First Byte 0x00
myCAM.CS_LOW();
myCAM.set_fifo_burst();
buf[0] = SPI.transfer(0x00);
buf[0] = SPI.transfer(0x00);
buf[1] = SPI.transfer(0x00);
myCAM.CS_HIGH();
if ( (buf[0]!=0xFF)||(buf[1]!=0xD8) ) {
Serial.println(F("Irregular JPEG Header"));
sprintf(header,"%02x%02x",buf[0],buf[1]);
Serial.println(header);
return;
}
prev = buf[1];
pos = 2;
total=2;
//ファイル名は8文字、拡張子は3文字までしか対応していない
getDateBurst();
if (!SD.exists(dirTime)) SD.mkdir(dirTime);
sprintf(filename,"%s/%s.jpg",dirTime,shortTime);
//Open the new file
Serial.println(filename);
outFile = SD.open(filename, O_WRITE | O_CREAT | O_TRUNC);
if(!outFile){
Serial.println(F("File open failed"));
return;
}
spi_lock(LOCK_ARDUCAM);
myCAM.CS_LOW();
myCAM.set_fifo_burst();
while ( true ) {
while (true) {
if (total>(length*2)) {
myCAM.CS_HIGH();
spi_lock(LOCK_NONE);
Serial.print(F("Irregular Buffer Data : total size = "));
Serial.println(total, DEC);
sprintf(header,"%02x%02x",buf[pos-2],buf[pos-1]);
Serial.println(header);
return;
}
total++;
buf[pos] = SPI.transfer(0x00);
if ((buf[pos]==0xD9)&&(prev==0xFF)) {
myCAM.CS_HIGH();
spi_lock(LOCK_NONE);
spi_lock(LOCK_SDCARD);
outFile.write(buf,(pos+1));
//Close the file
outFile.close();
spi_lock(LOCK_NONE);
Serial.println(F("Image save OK."));
Serial.print(F("total bytes is :"));
Serial.println((total-1), DEC);
return;
}
prev = buf[pos];
if (++pos==256) break;
}
myCAM.CS_HIGH();
spi_lock(LOCK_SDCARD);
outFile.write(buf, 256);
pos = 0;
spi_lock(LOCK_ARDUCAM);
myCAM.CS_LOW();
myCAM.set_fifo_burst();
}
}
void setup(){
uint8_t vid, pid;
uint8_t temp;
Wire.begin();
Serial.begin(115200);
Serial.println(F("ArduCAM Start!"));
//set the CS as an output:
pinMode(SPI_CS,OUTPUT);
digitalWrite(SPI_CS, HIGH);
// initialize SPI:
SPI.begin();
//Reset the CPLD
myCAM.write_reg(0x07, 0x80);
myCAM.write_reg(0x07, 0x00);
while(1){
//Check if the ArduCAM SPI bus is OK
myCAM.write_reg(ARDUCHIP_TEST1, 0x55);
temp = myCAM.read_reg(ARDUCHIP_TEST1);
if (temp != 0x55){
Serial.println(F("SPI interface Error!"));
delay(1000);continue;
}else{
Serial.println(F("SPI interface OK."));break;
}
}
//Initialize SD Card
while(!SD.begin(SD_CS)){
Serial.println(F("SD Card Error!"));
}
Serial.println(F("SD Card detected."));
while(1){
//Check if the camera module type is OV2640
myCAM.wrSensorReg8_8(0xff, 0x01);
myCAM.rdSensorReg8_8(OV2640_CHIPID_HIGH, &vid);
myCAM.rdSensorReg8_8(OV2640_CHIPID_LOW, &pid);
if ((vid != 0x26 ) && (( pid != 0x41 ) || ( pid != 0x42 ))){
Serial.println(F("Can't find OV2640 module!"));
delay(1000);continue;
}
else{
Serial.println(F("OV2640 detected."));break;
}
}
myCAM.set_format(JPEG);
myCAM.InitCAM();
//myCAM.OV2640_set_JPEG_size(OV2640_176x144);
//myCAM.OV2640_set_JPEG_size(OV2640_352x288);
//myCAM.OV2640_set_JPEG_size(OV2640_320x240);
myCAM.OV2640_set_JPEG_size(OV2640_640x480);
//myCAM.OV2640_set_JPEG_size(OV2640_800x600);
//myCAM.OV2640_set_JPEG_size(OV2640_1600x1200);
//myCAM.OV2640_set_Special_effects(BW);
// Realtime Clock
pinMode(PIN_SCLK,OUTPUT);
pinMode(PIN_CE, OUTPUT);
pinMode(BTN_PIN, INPUT_PULLUP);
pinMode(LED_PIN, OUTPUT);
}
void capture() {
if ( !writeStatus ) {
writeStatus = true;
digitalWrite(LED_PIN, HIGH);
myCAMSaveToSDFile();
writeStatus = false;
digitalWrite(LED_PIN, LOW);
}
}
// 整数値をBCDに変換
byte dec2bcd(int x) {
return ((x/10)<<4)+(x%10);
}
uint8_t bcd2dec(const uint8_t bcd) {
return (10*((bcd&0xF0)>>4)+(bcd&0x0F));
}
uint8_t shiftInEx() {
uint8_t input_value=0;
uint8_t bit=0;
pinMode(PIN_IO,INPUT);
for (int i=0; i<8; ++i) {
digitalWrite(PIN_SCLK,HIGH);
delayMicroseconds(1);
digitalWrite(PIN_SCLK,LOW);
delayMicroseconds(1);
bit = digitalRead(PIN_IO);
input_value |= (bit<<i); // Bits are read LSB first.
}
return input_value;
}
void shiftOutEx(const uint8_t value) {
bool pinModeFlag = false;
pinMode(PIN_IO, OUTPUT);
for (int i=0;i<8;++i) {
digitalWrite(PIN_IO, (value>>i)&1);
delayMicroseconds(1);
digitalWrite(PIN_SCLK,HIGH);
delayMicroseconds(1);
// We're about to read data -- ensure the pin is back in input mode
// before the clock is lowered
if (i==7) {
if (value==0xBF) pinModeFlag=true; // clock Burst Read
if ((value>=0x80)&&(value<=0x8D)&&(value%2)) pinModeFlag=true;
}
if (pinModeFlag) {
pinMode(PIN_IO,INPUT);
} else {
digitalWrite(PIN_SCLK,LOW);
delayMicroseconds(1);
}
}
}
void getDateBurst() {
digitalWrite(PIN_SCLK,LOW);
digitalWrite(PIN_CE,HIGH);
delayMicroseconds(4);
shiftOutEx(0xBF); //clock Burst Read
uint8_t ss = bcd2dec(shiftInEx() & 0x7F);
uint8_t ii = bcd2dec(shiftInEx());
uint8_t hh = bcd2dec(shiftInEx());
uint8_t dd = bcd2dec(shiftInEx());
uint8_t mm = bcd2dec(shiftInEx());
uint8_t day = bcd2dec(shiftInEx());
uint8_t yy = bcd2dec(shiftInEx());
digitalWrite(PIN_CE, LOW);
delayMicroseconds(4);
sprintf(clockTime,"%02d%02d%02d%02d%02d%02d",yy,mm,dd,hh,ii,ss);
sprintf(shortTime,"%02d%02d%02d",hh,ii,ss);
sprintf(dirTime, "20%02d%02d%02d",yy,mm,dd);
}
void loop(){
while (Serial.available()) {
char data = Serial.read();
if (data == '\n') {
if (recv.substring(0, 2) == "on") {
capture();
} else if (recv.substring(0, 4) == "time") {
getDateBurst();
Serial.println("$ time");
Serial.println(clockTime);
}
recv = "";
} else {
recv += data;
}
}
if ( digitalRead(BTN_PIN)==LOW ) {
capture();
}
}