Hello, everyone. I am using an Arduino MEGA 2560 and ArduCAM OV2640 to take a JPEG picture and display it on my PC through a Processing sketch. The current Arduino and Processing sketches let me take single shots only. I am wondering how I can make it so the camera will take pictures continuously and display it on the PC, similar to a video stream. Here are the sketches, courtesy of Vernel. (https://github.com/Vernel/ArduCAM_OV562
Processing sketch:
import processing.serial.*; // import the Processing serial library
Serial myPort; // The serial port
//NEW ADDITIONS
byte rawBytes[];
int sensorNum = 0;
PImage img;
long picNum = 0;
void setup() {
size(640, 480);
// List all the available serial ports
// if using Processing 2.1 or later, use Serial.printArray()
printArray(Serial.list());
// Change the 0 to the appropriate number of the serial port
// that your microcontroller is attached to.
myPort = new Serial(this, Serial.list()[0], 250000);
// read bytes into a buffer until you get a linefeed (ASCII 10):
myPort.bufferUntil('\n');
// draw with smooth edges:
smooth();
img = createImage(320, 240, RGB);
img.loadPixels();
//frameRate(600);
myPort.write(0x10);
}
void draw() {
background(255);
image(img, 0, 0, width, height-100);
fill(0);
text("Help:", 20, height-80);
text("- Press key 1-7 to change image resolution", 30, height-60);
text("- Press key S to capture a still photo", 30, height-40);
text("- Press key C to enable/disable StopMotion capture", 30, height-20);
}
// serialEvent method is run automatically by the Processing applet
// whenever the buffer reaches the byte value set in the bufferUntil()
// method in the setup():
void serialEvent(Serial myPort) {
while (myPort.available() > 0) {
String incoming[];
String myString = myPort.readStringUntil('\n');
myString = trim(myString);
incoming = split(myString, ',');
if (incoming.length > 1) {
if (incoming[0].equals("FifoLength:")) {
//initialize raw data byte array to the size of the picture
rawBytes = new byte[int(incoming[1])];
println("Picture Size: "+incoming[1]+" bytes");
} else if (incoming[0].equals("Image:")) {
int x = 0;
for (int i = 1; i < incoming.length; i++) {
try {
//add raw jpeg incoming bytes to byte array
rawBytes[x]= (byte)int(incoming[i]);
x++;
}
catch(RuntimeException e) {
println(e.getMessage());
}
}
try {
//Save raw data to file
String fname = "capture#"+picNum+"_"+day()+month()+year()+".jpg";
saveBytes("data/capture/"+fname, rawBytes);
// Open saved picture for local display
img = loadImage("/data/capture/"+fname);
picNum++;
}
catch(RuntimeException e) {
println(e.getMessage());
}
} else if (incoming[0].equals("Ready:")) {
myPort.write(0x10);
println("Starting Capture");
}
} else {
println(myString);
}
}
}
void keyPressed() {
switch(key) {
case 's':
myPort.write(0x10);
println("Starting Capture");
break;
case 'c':
myPort.write(7);
break;
case '1':
myPort.write(0);
println("Set Image Resolution: 320x240");
break;
case '2':
myPort.write(1);
println("Set Image Resolution: 640x480");
break;
case '3':
myPort.write(2);
println("Set Image Resolution: 1024x768");
break;
default:
println("Unknown Command: "+key);
break;
}
}
Arduino Sketch:
#include <Wire.h>
#include <ArduCAM.h>
#include <SPI.h>
#include "memorysaver.h"
//This code can only work on OV5642_MINI_5MP_PLUS platform.
#if !(defined (OV2640_MINI_2MP))
#endif
#define FRAMES_NUM 0x00
// set pin 4 as the slave select for SPI:
const int CS1 = 7;
bool CAM1_EXIST = false;
bool stopMotion = false;
ArduCAM myCAM1(OV2640, CS1);
long int streamStartTime;
void setup() {
// put your setup code here, to run once:
uint8_t vid, pid;
uint8_t temp;
Wire.begin();
Serial.begin(250000); //921600
Serial.println(F("ArduCAM Start!"));
// set the CS output:
pinMode(CS1, OUTPUT);
// initialize SPI:
SPI.begin();
//Check if the 4 ArduCAM Mini 5MP PLus Cameras' SPI bus is OK
while (1) {
myCAM1.write_reg(ARDUCHIP_TEST1, 0x55);
temp = myCAM1.read_reg(ARDUCHIP_TEST1);
if (temp != 0x55)
{
Serial.println(F("SPI1 interface Error!"));
} else {
CAM1_EXIST = true;
Serial.println(F("SPI1 interface OK."));
}
if (!(CAM1_EXIST)) {
delay(1000); continue;
} else
break;
}
while (1) {
//Check if the camera module type is OV5642
myCAM1.rdSensorReg8_8(OV2640_CHIPID_HIGH, &vid);
myCAM1.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;
}
}
//Change to JPEG capture mode and initialize the OV2640 module
myCAM1.set_format(JPEG);
myCAM1.InitCAM();
//myCAM1.write_reg(ARDUCHIP_TIM, VSYNC_LEVEL_MASK); //VSYNC is active HIGH
myCAM1.clear_fifo_flag();
//myCAM1.write_reg(ARDUCHIP_FRAMES, FRAMES_NUM);
//myCAM1.OV5642_set_JPEG_size(OV5642_640x480); delay(1000);
myCAM1.OV2640_set_JPEG_size(OV2640_320x240); delay(1000);
delay(1000);
myCAM1.clear_fifo_flag();
Serial.println("Ready:,1");
}
void loop() {
if (CAM1_EXIST && stopMotion) {
streamStartTime = millis();
myCAMSendToSerial(myCAM1);
double fps = ((millis() - streamStartTime) / 1000);
Serial.println("fps: " + String(1 / fps ));
}
}
void myCAMSendToSerial(ArduCAM myCAM) {
char str[8];
byte buf[5];
static int i = 0;
static int k = 0;
uint8_t temp = 0, temp_last = 0;
uint32_t length = 0;
bool is_header = false;
myCAM.flush_fifo(); //Flush the FIFO
myCAM.clear_fifo_flag(); //Clear the capture done flag
myCAM.start_capture();//Start capture
while (!myCAM.get_bit(ARDUCHIP_TRIG , CAP_DONE_MASK));
length = myCAM.read_fifo_length();
Serial.print(F("FifoLength:,"));
Serial.print(length, DEC);
Serial.println(",");
if (length >= MAX_FIFO_SIZE) //8M
{
Serial.println(F("Over size."));
return ;
}
if (length == 0 ) //0 kb
{
Serial.println(F("Size is 0."));
return ;
}
myCAM.CS_LOW();
myCAM.set_fifo_burst();
Serial.print("Image:,");
while ( length-- )
{
temp_last = temp;
temp = SPI.transfer(0x00);
//Read JPEG data from FIFO
if ( (temp == 0xD9) && (temp_last == 0xFF) ) //If find the end ,break while,
{
buf[i++] = temp; //save the last 0XD9
//Write the remain bytes in the buffer
myCAM.CS_HIGH();
for (int i = 0; i < sizeof(buf); i++) {
Serial.print(buf[i]); Serial.print(",");
}
Serial.println();
Serial.println(F("Image transfer OK."));
is_header = false;
i = 0;
}
if (is_header == true)
{
//Write image data to buffer if not full
if (i < 5) {
buf[i++] = temp;
} else
{
//Stream 5 bytes of raw image data to serial
myCAM.CS_HIGH();
for (int i = 0; i < sizeof(buf); i++) {
Serial.print(buf[i]); Serial.print(",");
}
i = 0;
buf[i++] = temp;
myCAM.CS_LOW();
myCAM.set_fifo_burst();
}
}
else if ((temp == 0xD8) & (temp_last == 0xFF))
{
is_header = true;
buf[i++] = temp_last;
buf[i++] = temp;
}
}
}
void serialEvent() {
if (Serial.available() > 0) {
uint8_t temp = 0xff, temp_last = 0;
uint8_t start_capture = 0;
temp = Serial.read();
switch (temp)
{
case 0:
temp = 0xff;
myCAM1.OV2640_set_JPEG_size(OV2640_320x240);
Serial.println(F("OV2640_320x240")); delay(1000);
myCAM1.clear_fifo_flag();
break;
case 1:
temp = 0xff;
myCAM1.OV2640_set_JPEG_size(OV2640_640x480);
Serial.println(F("OV2640_640x480")); delay(1000);
myCAM1.clear_fifo_flag();
break;
case 2:
temp = 0xff;
myCAM1.OV2640_set_JPEG_size(OV2640_1024x768);
Serial.println(F("OV2640_1024x768")); delay(1000);
myCAM1.clear_fifo_flag();
break;
case 3:
{
if (stopMotion)
stopMotion = false;
else
stopMotion = true;
Serial.println("Stop Motion Enabled: " + String(stopMotion));
}
break;
case 0x10:
if (CAM1_EXIST) {
streamStartTime = millis();
myCAMSendToSerial(myCAM1);
double fps = ((millis() - streamStartTime) / 1000);
Serial.println("Total Time: " + String(fps));
}
break;
default:
break;
}
}
}
Thanks in advance!