Back to photostream

COMedia C328-7640 Serial Camera Arduino "self portrait"

 

UPDATE: You can still find the Arduino Library here: arms22.googlecode.com/files/CameraC328R.zip

 

// C328R_with_I2C_flash_LCD

// by s_p_e_x, some rights reserved

//

// Based on work by Sean Voisen

 

// (gizmologi.st/2009/04/taking-pictures-with-arduino/)

// and Ryan Detzel

// (10kohms.com/arduino-external-eeprom-24lc256)

//

// I converted Seans code to use I2C EEPROM instead of SPI

// Flash. Also I wrote A base64 encoder in an attempt to dodge

// problems with escape codes messing up terminal programs. I'm

 

// still having issues. But it does work and opens the door to

// a direct interface via Ethernet and a web browser.

 

// Oh, and I added LCD support to have some clue about what is

// going on. Without having access to the serial interface I

// was really puzzled by why it wasn't working.

 

// After struggling with getting a proper 3.3V source

// (I finally switched to a "real" Arduino with a built in

 

// 3.3 regulator) and with iffy contacts on the camera cable

// I was totally thrown by the long delay to write the image to

// the I2C flash. Having an LCD took much of the guess work out.

//

// My I2C EEPROM is a 24LC256, and I use the highest two bytes

// to hold the picture size so when you reset it knows how much

// to read back.

 

// Unforunately the I2C EEPROM is SLOW, so if you can't monitor

 

// the progress via an LCD, be very patient waiting for the

// lights to blink and tell you setup() is over. ~5 minutes

 

// Here's a Function Map which helped me figure out the example:

 

//setup(){

//  if A0 is HIGH

  //  camera.sync()

  //  camera.initial()

 

  //  camera.setPackageSize()

  //  camera.setLightFrequency()

  //  camera.snapshot()

  //  camera.getJPEGPicture()

  //    fillPageBuffer()

  //      writeBuffer() -- for loop

 

  //        writeEEPROM() -- write bytes to EEPROM

  //    getJPEGPicture_callback()

  //    camera.poweroff()

// if A0 is LOW

  //    transferPicture() -- print bytes from EEPROM

  //      bintoascii() -- base64 encoder not perfect but works

 

  //      readEEPROM() -- for loop read bytes from EEPROM

//}

//loop(){

//  blink LED

//}

 

// wire A0 HIGH or LOW to take a picture or to extract a picture

 

// HIGH will guide the camera through init and a photograph and

 

// transferring to flash before exiting setup().

 

// LOW will read back the flash and send the data base64 encoded to

// the console. I added a header and footer to take advantage of the

// URI data scheme:

//   secure.wikimedia.org/wikipedia/en/wiki/Data_URI_scheme

 

// On my Mac I extracted the picture with screen:

 

 

//   screen /dev/tty.usbmodemfd551 38400

 

// This was on a Mac with an Arduino Uno. The device name may vary.

 

// Very quickly turn on the logging ^aH (control-A and then shift-H).

 

// Once the image is done dumping, exit screen completely: ^a^\

 

// rename the logfile to a .html file:

 

 

//    mv ~/screenlog.0 image.html

 

// You should now be able to view your image directly with FireFox.

 

#include "CameraC328R.h"

#include

#include

 

 

#define LED_PIN 13

#define PAGE_SIZE 64

#define BAUD 38400

 

#define eeprom1 0x50    //Address of 24LC256 eeprom chip

 

// Buffer for EEPROM data

 

byte pageBuffer[PAGE_SIZE];

 

CameraC328R camera;

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);  

 

 

static uint16_t pictureSizeCount = 0;

static uint16_t pageBufferIndex = 0;

static uint16_t currentAddress = 0;

 

bool dirtyBuffer = false;

 

int capture_mode_switch = A0; //HIGH => take picture; LOW => extract picture

int CaptureMode;

 

 

byte readEEPROM(int deviceaddress, unsigned int eeaddress ) {

  byte rdata = 0xFF;

 

  Wire.beginTransmission(deviceaddress);

  Wire.send((int)(eeaddress >> 8));   // MSB

 

  Wire.send((int)(eeaddress & 0xFF)); // LSB

  Wire.endTransmission();

 

  Wire.requestFrom(deviceaddress,1);

 

  if (Wire.available()) rdata = Wire.receive();

 

 

  return rdata;

}

 

void writeEEPROM(int deviceaddress, unsigned int eeaddress, byte data ) {

  Wire.beginTransmission(deviceaddress);

 

  Wire.send((int)(eeaddress >> 8));   // MSB

  Wire.send((int)(eeaddress & 0xFF)); // LSB

 

  Wire.send(data);

  Wire.endTransmission();

 

//yes you need this delay, and yes it makes flashing take 5 minutes or so

  delay(5);

}

 

 

/**

 

 * Writes the data in the buffer to the EEPROM at the page

 * starting at the given address.

 */

void writeBuffer( int deviceaddress, uint16_t address, uint16_t bufferSize )

{

 

  // Send the data

  for( uint16_t i = 0; i < bufferSize; i++ )

  {

    writeEEPROM(deviceaddress, address+i, pageBuffer[i]);

  }

 

 

  //digitalWrite( SS_PIN, HIGH );

}

 

/**

 * Fills the page buffer for the EEPROM with data.

 */

void fillPageBuffer( byte* data, uint16_t dataSize )

 

{

  for( uint16_t i = 0; i < dataSize; i++ )

  {

    pageBuffer[pageBufferIndex] = data[i];

    dirtyBuffer = true;

 

    pageBufferIndex++;

 

    if( pageBufferIndex == PAGE_SIZE && dirtyBuffer )

    {

      pageBufferIndex = 0;

      writeBuffer(eeprom1, currentAddress, PAGE_SIZE );

      currentAddress += PAGE_SIZE;

 

      dirtyBuffer = false;

      delay( 50 );

    }

  }

}

 

void bintoascii(char * outstring, byte byte0, byte byte1, byte byte2, uint16_t count)

 

{

  //outstring points to 4char string

  // byteX are the three possible input bytes

  // count marks the number of input bytes, this should

  //       always be 0 unless it is the last one or two input bytes

 

  byte temp1, temp2, temp0;

  char base64chars[]= "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

 

 

  if (count == 0){

  temp0 = byte0;

  temp1 = byte1;

  temp2 = byte2;

  }

  if (count == 1){

 

  temp0 = byte2;

  temp1 = 0;

  temp2 = 0;

  }

   if (count == 2){

 

  temp0 = byte1;

  temp1 = byte2;

  temp2 = 0;

  }

 

  outstring[0]=base64chars[temp0 >> 2];

 

  //Serial.println(base64chars[temp0 >> 2], BYTE);

  outstring[1]=base64chars[((temp0 & 0x03) 4)];

 

  outstring[2]=base64chars[((temp1 & 0x0f) 6)];

  outstring[3]=base64chars[(temp2 & 0x3f)];

 

 

  // add padding

  if (count == 1){

    outstring[2]='=';

    outstring[3]='=';

 

  }

  if (count == 2){

    outstring[3]='=';

  }

 

}

 

 

 

/**

 * Sends a picture to the computer.

 */

void transferPicture( uint16_t startAddress, uint16_t size )

{

 

  char base64text[]="****";

  byte old, older, oldest;

  uint16_t endAddress = startAddress + size;

  uint16_t i;

 

  Serial.println("<img src=\"data:image/jpeg;base64,");    

 

 

  for( i = startAddress; i < endAddress; i++ )

  {

    oldest = older;

    older = old;

    old = readEEPROM( eeprom1, i );

//    Serial.print(i, DEC); Serial.print(": "); Serial.println(old, DEC);

 

 

    if ((i+1) % 3 == 0) { // every 3 bytes you print 4 characters

//      Serial.print(oldest, DEC); Serial.print(" "); Serial.print(older, DEC); Serial.print(" "); Serial.print(old, DEC); Serial.print(" ");

 

      bintoascii(base64text, oldest, older, old, 0);

      Serial.print(base64text);

    }  

    if((i+1) % 57 == 0) { // every 72 characters, you start a new line

 

      Serial.println("");

    }

  }

    //Serial.print( readEEPROM( eeprom1, i ), BYTE );

 

  if ((size % 3) != 0) { //if the image is not a multple of 3 bytes, encode the stragglers

 

    //Serial.print(oldest, DEC); Serial.print(" "); Serial.print(older, DEC); Serial.print(" "); Serial.print(old, DEC); Serial.print(" ");

    bintoascii(base64text, oldest, older, old, i%3);

    Serial.print(base64text);

  }

 

 

  Serial.println("\" />");

 

}

 

/**

 * This callback is called EVERY time a JPEG data packet is received.

 */

void getJPEGPicture_callback( uint16_t pictureSize, uint16_t packageSize, uint16_t packageCount, byte* package )

 

{

 

  // packageSize is the size of the picture part of the package

  pictureSizeCount += packageSize;

 

  // print progress

  lcd.setCursor(0, 1);

  //         0123456789012345

 

  lcd.print("                ");

  lcd.setCursor(0, 0);

  //         0123456789012345

  lcd.print("Camera -> EEPROM");

 

  lcd.setCursor(0, 1);

  lcd.print(pictureSizeCount, DEC);

  lcd.print("/");

  lcd.print(pictureSize, DEC);

 

 

  // package contains everything in the package

 

  fillPageBuffer( package, packageSize );

 

  if( pictureSizeCount == pictureSize )

  {

    // Is there still stuff in the buffer?

    if( dirtyBuffer )

    {

      writeBuffer(eeprom1, currentAddress, pageBufferIndex );

 

    }

    writeEEPROM(eeprom1, 65534, pictureSize & 0xff);

    writeEEPROM(eeprom1, 65535, pictureSize >> 8 & 0xff);

 

 

    camera.powerOff();

    lcd.setCursor(0, 0);

    //         0123456789012345

    lcd.print("Camera OFF.     ");

 

 

    digitalWrite( LED_PIN, HIGH ); // DONE!

//    Serial.flush();

//    delay( 5000 ); // Give us 5 seconds to hit a key ...

//

//    lcd.setCursor(0, 1);

//    //         0123456789012345

 

//    lcd.print("Send over Serial");

//    transferPicture( 0, pictureSize );

  }

}

//***********************************************************

//

//                         S E T U P

 

//

//***********************************************************

 

void setup()

{

  uint16_t storedpicturesize;

  Serial.begin( BAUD );

  Wire.begin();  

 

  pinMode( LED_PIN, OUTPUT );

 

  digitalWrite( LED_PIN, HIGH );

 

  lcd.begin(16, 2);

 

  if (analogRead(capture_mode_switch) > 511) {

 

    CaptureMode = 1;

  } else {

    CaptureMode = 0;

  }

 

  if(CaptureMode == 1) {

 

 

    if( !camera.sync() )

    {

      //Serial.println( "Sync failed." );

      lcd.setCursor(0, 0);

 

      lcd.print("Sync failed.");

      return;

    } else {

      lcd.setCursor(0, 0);

 

      lcd.print("Synced.");

    }

 

    digitalWrite( LED_PIN, LOW );

 

 

    if( !camera.initial( CameraC328R::CT_JPEG, CameraC328R::PR_160x120, CameraC328R::JR_640x480 ) )

    {

 

      //Serial.println( "Initial failed." );

      lcd.setCursor(0, 0);

      lcd.print("Initial failed.");

      return;

 

    } else {

      lcd.setCursor(0, 0);

      lcd.print("Inited.");

    }

 

 

    if( !camera.setPackageSize( 64 ) )

    {

      //Serial.println( "Package size failed." );

      lcd.setCursor(0, 0);

 

      lcd.print("Package size failed.");

     return;

    } else {

      lcd.setCursor(0, 0);

 

      lcd.print("Package sized.");

    }

 

    if( !camera.setLightFrequency( CameraC328R::FT_50Hz ) )

    {

      //Serial.println( "Light frequency failed." );

 

      lcd.setCursor(0, 0);

      lcd.print("Light frequency failed.");

      return;

    } else {

 

      lcd.setCursor(0, 0);

      lcd.print("Light frequenced.");

    }

 

    // Let camera settle, per manual

    delay(2000);

 

 

    digitalWrite( LED_PIN, HIGH );

 

    if( !camera.snapshot( CameraC328R::ST_COMPRESSED, 0 ) )

    {

      //Serial.println( "Snapshot failed." );

      lcd.setCursor(0, 0);

 

      lcd.print("Snapshot failed.");

     return;

    } else {

      lcd.setCursor(0, 0);

 

      lcd.print("Snapshotted.");

    }

 

    digitalWrite( LED_PIN, LOW);

 

    if( !camera.getJPEGPicture( CameraC328R::PT_JPEG, PROCESS_DELAY, &getJPEGPicture_callback ) )

    {

 

      //Serial.println( "Get JPEG failed." );

      lcd.setCursor(0, 0);

      lcd.print("Get JPEG failed.");

      return;

 

    } else {

      lcd.setCursor(0, 0);

      lcd.print("Got JPEG.");

    }

  } else {

 

    lcd.setCursor(0, 0);

    //         0123456789012345

    lcd.print("Send in 5 secs  ");

 

    Serial.flush();    

 

    delay( 5000 ); // Give us 5 seconds to hit a key ...

 

    lcd.setCursor(0, 0);

    //         0123456789012345

    lcd.print("Send over Serial");

 

 

    storedpicturesize = readEEPROM( eeprom1, 65535 );

    storedpicturesize = ((storedpicturesize*256) + readEEPROM( eeprom1, 65534 ) );

    //storedpicturesize = ((storedpicturesize << 8) | readEEPROM( eeprom1, 32766 ) );

    //storedpicturesize = ((storedpicturesize << 8) | readEEPROM( eeprom1, 32767 ) );

 

 

    lcd.setCursor(0, 1);

    //         0123456789012345

    lcd.print("send");

    lcd.print(storedpicturesize, DEC);

 

    lcd.print(" bytes");

 

 

    transferPicture( 0, storedpicturesize );

 

   lcd.setCursor(0, 0);

 

    //         0123456789012345

    lcd.print("send complete   ");

  }

}

 

void loop()

 

{

  digitalWrite( LED_PIN, HIGH ); // DONE!

  delay(100);

  digitalWrite( LED_PIN, LOW ); // DONE!

  delay(100);

}

 

// wow, flickr is not a good place to be sharing code

4,556 views
0 faves
6 comments
Uploaded on December 30, 2010
Taken on December 29, 2010