As computing becomes more ubiquitous in our objects, designers need to be more aware of how to design meaningful interactions into electronically enhanced objects. At the University of Washington, a class of junior Interaction Design majors is exploring this question. These pages chronicle their efforts.

Thursday, June 13, 2013

Trash Talk | Game On | Sam + Willie

Welcome to the final Trash Talk blog post.

Over 10 weeks Willie and I were able to get more or less up to speed on Arduino code, source and construct an Arduino enabled recycling bin, and get it to respond to a situation in the environment. Trash Talk is designed to make the mundane activity of recycling more surprising and delightful. And we've succeeded. Trash Talk can detect when you make a basket, and play a randomized sound effect from NBA Jams. Unfortunately we weren't able to resolve the code enough to include wiichuck shaking functionality, due to the limited scope of our knowledge and time. But all in all, we're extremely proud of what we've accomplished and learned over the course of this project.

Here's our short film about Trash Talk:


Introducing Trash Talk from Sam Cook on Vimeo.




Here's a list of sources and resources that we used in our project:

WAVE Shield - http://www.ladyada.net/make/waveshield/
IR Sensing - http://forum.arduino.cc/index.php?topic=94690.0
MP3 Player Shield - https://www.sparkfun.com/products/10628
WiiChuck - http://todbot.com/blog/2008/02/18/wiichuck-wii-nunchuck-adapter-available/
WiiChuck + Arduino Mega - http://forum.arduino.cc/index.php/topic,21723.0.html

Here's our (delightful) code:

// this is an LED blink sketch with calibration for all 3 Sensors
// hopefully it works

#include <SPI.h>
#include <SdFat.h>
#include <SdFatUtil.h> 
#include <SFEMP3Shield.h>

SdFat sd;
SFEMP3Shield MP3player;

const int sensor1 = A0; // analog input pin -- Detector (clear)
const int sensor2       = A1;
const int sensor3       = A2;
const int emitterPin = 14; // digital output pin -- Emitter/dark)
const int signalPin     = A15;   // signal pin setup

// variables:
int sensor1Val   = 0;         // the sensor value
int sensor1Max   = 0;         // maximum sensor value

int sensor2Val   = 0; 
int sensor2Max   = 0;

int sensor3Val   = 0;
int sensor3Max   = 0;



// a function for making the signalPin blink
void blink() {
  digitalWrite(signalPin, HIGH);
  delay(200);
  digitalWrite(signalPin, LOW);
}

void success() {
  int x = random(1, 5);
  switch (x) {
    case 1:
      MP3player.playTrack(1);
      break;
    case 2:
      MP3player.playTrack(2);
      break;
    case 3:
      MP3player.playTrack(3);
      break;
    case 4:
      MP3player.playTrack(4);
      break;
    case 5:
      MP3player.playTrack(5);
      break;
  }
}



// Sets up the Calibrations
void setup() {
  
  Serial.begin(19200);
  
  //gets the MP3 Shield Fired Up
  sd.begin(SD_SEL, SPI_HALF_SPEED);
  MP3player.begin();
  MP3player.setVolume(0,0);
  
  // turn on LED to signal the start of the calibration period:
  pinMode(signalPin, OUTPUT);
  digitalWrite(signalPin, HIGH);
  
  // Turns on my IR emitters
  pinMode( emitterPin, OUTPUT );
  digitalWrite( emitterPin, HIGH );
  
  Serial.println("beginning calibration");
  // calibrate Sensors during the first three seconds 
  while (millis() < 3000) {
    
    sensor1Val = analogRead(sensor1);
    //Serial.println(sensor1Val);
    sensor2Val = analogRead(sensor2);
    //Serial.println(sensor2Val);
    sensor3Val = analogRead(sensor3);
    //Serial.println(sensor3Val);
    
    // records the maximum sensor value
    if (sensor1Val > sensor1Max) {
      sensor1Max = sensor1Val;
    }
    
    if (sensor2Val > sensor2Max) {
      sensor2Max = sensor2Val;
    }
    
    if (sensor3Val > sensor3Max) {
      sensor3Max = sensor3Val;
    }
  }
  
  Serial.print("Sensor1 Max: ");
  Serial.println(sensor1Max);
  Serial.print("Sensor2 Max: ");
  Serial.println(sensor2Max);
  Serial.print("Sensor3 Max: ");
  Serial.println(sensor3Max);
  Serial.println("Done Calibrating");
  
  // signal the end of the calibration period
  digitalWrite(signalPin, LOW);
  
}


//where the magic happens
void loop() {
  
  
  
  // read the sensors
  sensor1Val = analogRead(sensor1);
  Serial.println(sensor1Val);
  sensor2Val = analogRead(sensor2);
  Serial.println(sensor2Val);
  sensor3Val = analogRead(sensor3);
  Serial.println(sensor3Val);
  
  
  
  //IR sensing Action Statement
  if(sensor1Val <= (sensor1Max - 4)) {
    blink();
    success();
    Serial.println("sensor1 actuation");
  }
  
  if(sensor2Val <= (sensor2Max - 4)) {
    success();
    Serial.println("sensor2 actuation");
  }
  
  if(sensor3Val <= (sensor3Max - 4)) {
    success();
    Serial.println("sensor3 actuation");
  }
  
  //Serial.print("sensor values = ");
  //Serial.print(sensor1Val + ", ");
  //Serial.print(sensor2Val + ", ");
  //Serial.println(sensor3Val);
  delay(5);
}

Tuesday, June 11, 2013

PlantBob - Enrique D. & Karin H.

Although full of colorful and often expensive electronics, the modern child’s toy chest lacks an important teaching component. The ability to grow and care for a plant can be a valuable and entertaining experience for any child. All the child may need is a little help.   PlantBob is the Squarepants’d gardening toy that helps kids grow and maintain a plant by reminding them when it is time to water their plant. Using a moisture and motion sensor, PlantBob keeps an eye on the soil’s water content and notifies you when he’s getting thisty!

With some help from an Arduino One, a few sensors, and a long code, we were able to build a toy that could sense when a person was in proximity, would then take a moisture reading of the soil, and provide auditory and light feedback. This was all housed inside a small plush toy.





Our final product demonstration and prototype was a short video describing the situation in which PlantBob would be used and two posters that illustrated the features and functions of our projects:





We found a variety of sources that had completed similar projects, and were able to use their examples as guides for writing our code and completing our project:



The final code used to run PlantBob can be found below:
/*
  PLANT BOB 2013
  - By Karin Hellman & Enrique Dominguez  */

/*
  # the sensor value description
  # 0  ~500     in water
  # 500~700     humid soil
  # 700~1000     dry soil
 */
 
 /*
 SCK: pin 13
 MOSI: pin 11
 MISO: pin 12
 CS: pin 4
 */
 
/*LIBS*/
#include <SD.h>             // need to include the SD library for reading from the card
#define SD_ChipSelectPin 4  //using digital pin 4 on our arduino uno, can use other pins
#include "TMRpcm.h"         //  also need to include this library for the music playback

/*PINS*/
int motionPin = 7; //Connected to the motion sensor
int moisturePin = 0; //Connected to the moisture sensor
int moistureValue; //moisture sensor value
int motionValue; // Motion or no motion
int green = 8; //green LED on pin 8
TMRpcm tmrpcm;   // create an object for use in this sketch

/*SETUP*/
void setup() {
  Serial.begin(9600);
   pinMode(green, OUTPUT); //make the green pin an output for lighting up our led  
   
   tmrpcm.speakerPin = 9; //5,6,11 or 46 on Mega, 9 on Uno, Nano, etc

  if (!SD.begin(SD_ChipSelectPin)) {  // see if the card is present and can be initialized:
    Serial.println("SD fail");  
    return;   // don't do anything more if not
  }
  tmrpcm.play("MidWater.wav"); //the sound file will play each time the arduino powers up, or is reset
 
}

/*LOOP*/
void loop() {
    motionValue = digitalRead(motionPin);
    moistureValue = analogRead(moisturePin);
    int del = 200;
   
    Serial.print("Moition Sensor Value: ");
    Serial.println(motionValue);
    Serial.print("Moisture Sensor Value: ");
    Serial.println(moistureValue, DEC);
     
    //CHECK THE PLANT's STATUS:
    /* DRY*/
    if (moistureValue>700){          
      digitalWrite(green, LOW);   // turn the LED off
      //If there is motion, play sound
      if(motionValue == HIGH){
        //play sound 1 - dry sound  
        Serial.println("Playing sound 1");
        tmrpcm.play("LowWater.wav");
        delay(5000);
      }
    }
   
    /*WET*/    
    else if(moistureValue < 600){
      digitalWrite(green, LOW);   // turn the LED off
      //If there is motion, play sound
      if(motionValue == HIGH){
        //Play sound 2 - wet sound
        tmrpcm.play("HiWater.wav");
        Serial.println("Playing sound 3");
        delay(4000);
      }
    }
    
    /*GOOD*/
    else{
      digitalWrite(green, HIGH);   // turn the LED on (HIGH is the voltage level)
      //If there is motion, play sound
      if(motionValue == HIGH){
        //Play sound 3 - good sound
        tmrpcm.play("MidWater.wav");
        Serial.println("Playing sound 2");
        delay(3000);
      }
    }
  delay(200);
}






Nick and Mason Final































Ever leave the house in shorts and a T-shirt only to get soaked by a torrential downpour in the afternoon? Wouldn't it be nice if you knew to bring gear for a rainy day? Weathermate solves this problem by letting you know what you need.

Weathermate uses a online resource called If This Than That which is able to take the daily weather report and send it to a drop box folder. This file is then moved and renamed by Hazel so that Processing can read the file and send the necessary instructions to the Arduino, which are the the brains of Weathermate


The Arduino Code:

#include "Servo.h"

Servo motor;
Servo motor2;
Servo motor3;

int x;
int r;


void setup() {
  //Set up for Sensor
  pinMode(3, INPUT);


  // Set up for Sun
  pinMode(6, OUTPUT);
  motor.attach(6);
  pinMode(7, OUTPUT);

  //Set up for Rain
  pinMode(9, OUTPUT);
  motor2.attach(9);
  motor2.write(90);
  pinMode(8, OUTPUT);

  //Set up for Snow
  pinMode(11, OUTPUT);
  motor3.attach(11);
  pinMode(12, OUTPUT);

  Serial.begin(9600);

}

void loop() {

  //this was for testing purposes so that we could see where the what instruction the Arduino had.
  Serial.println(r);

  //Senses if a person is there
  if(digitalRead(3) == HIGH){

    //If it is going to rain
    if (r == 1) {
      
      Serial.println("Rain");

      digitalWrite(8, HIGH);

      motor2.write(180);
      delay(2000);

      Serial.println("180");
    
      motor2.write(90);
      Serial.println("90");
      delay(5000);

      motor2.write(0);
      delay(600);
      Serial.println("0");

      motor2.write(90);
      Serial.println("90");

      delay(5000);
      digitalWrite(8, LOW);
      
      Serial.println("Rain");
    }



    //if it is going to be sunny 
    if (r == 2) {

      //we only had one srvo mottor so  the code for it was simple for this one.
      motor.write(0);
      digitalWrite(7, HIGH);
      Serial.println("Sunnnnnnnnn");
      delay(5000);
      motor.write(180);
      digitalWrite(7, LOW);  

    }




    //If it was going to snow / the weather was going to be cold
    if (r == 3) {
      Serial.println("Rain");

      digitalWrite(12, HIGH);

      motor3.write(180);
      delay(2000);

      Serial.println("180");
    
      motor3.write(90);
      Serial.println("90");
      delay(5000);

      motor3.write(0);
      delay(600);
      Serial.println("0");

      motor3.write(90);
      Serial.println("90");

      delay(5000);
      digitalWrite(12, LOW);
     


    }
  }






  
// This was the basic function we used to take the incoming information and 
// translate it to a variable that Arduino could use. 

  if (Serial.available()) {
    x = Serial.read();
    x  = x-48 ;
    Serial.println(x);


    if (x == 1 || x == 2 || x==3 || x==4) {
      r= x;
    }


  }
}




The Processing code

String[] lines;
String[] today;
String[] possible;
String[] numb;


String str1 = "CCCP";
String str2 = "CCCP";
String str3 = "CCCP";
String str4 = "CCCP";
String str5 = "CCCP";


int x = 2;

///
import processing.serial.*;
Serial comPort;


///
void setup() {
  
//For processing to be able to communicate with the Arduino we needed to initialize a connection 
//The 6 that you see there is telling the computer which port(usb) to look at.

  comPort = new Serial(this, Serial.list()[6], 9600);
}

void draw() {
  
  
// text file for the weather of the day
  today = loadStrings("Weather.txt");
  
  // the instructions that will be sent
  numb = loadStrings("2.txt");
  
  // the possible out comes that the forecast will be compared to
  possible = loadStrings("possible.txt");


  str1 = today[0];
  str2 = possible[0];
  str3 = possible[1];
  str4 = possible[2];
  str5 = possible[3];

//for testing
  println(str1);
  println(str2);
  println(str3);
  println(str4);
  println(str5);


//looks for rain
  if (str1.equals(str2) == true  ) {
    println("Rainnnnnnn");
    comPort.write(numb[0]);

    delay(500);
    comPort.write("6");
    delay(6000);

  }
  
  //looks for sun
    if (str1.equals(str3) == true ) {
    println("Sunnnnnnnn");
    comPort.write(numb[1]);

    delay(500);
    comPort.write("6");
    delay(6000);
  }
  
  
  // Looks for snow
    if (str1.equals(str4) == true) {
    println("Snowwwwwwww");
    comPort.write(numb[3]);

    delay(500);
    comPort.write("6");
    delay(6000);
  }
}

















Working Rough Prototype [Maddie and Candice]

Motion is sensed. Bubbles are triggered. Happiness is had by all.



// Customized code based on http://stratigrafia.org/blog/entries/2012-09-01.html

int pirPin = 4; // digital pin 4 for PIR; put a 10k Ohm resistor between pin 4 and OUT on PIR
int ledPin = 7; // digital pin 13 for LED; put a 220 Ohm resistor between pin 13 and the LED
int noMotion = 1;
int TIP120pin = 9; //for this project, I pick Arduino's PMW pin 11

void setup() {
  pinMode(pirPin, INPUT); // set PIR pin as input
  pinMode(ledPin, OUTPUT); // set LED pin as output
  pinMode(TIP120pin, OUTPUT); // Set pin for output to control TIP120 Base pin
}

void loop() {
  int movementSensor=digitalRead(pirPin);

  if(movementSensor == HIGH) {
  // motion detected
    if (noMotion == 0) {
  // make bubbles only if coming from a state of no motion
      digitalWrite(TIP120pin, HIGH);
      digitalWrite(ledPin, HIGH);
 
      noMotion=1;
    }
  } else {
    // No motion
    digitalWrite(TIP120pin, LOW);
    digitalWrite(ledPin, LOW);
    noMotion=0;
  }
}

Sensor + Actuator Combo [Maddie and Candice]

Maddie and I kept trying to figure out why our code wasn't working. We kept getting the error "avrdude: stk500_getsync(): not in sync: resp=0x00".

We realized after asking Matt from Metrix Create Space that the reason we were getting this error was because we had the TXD and RXD pins plugged in as we were trying to upload the code into Arduino, and we had to disconnect it before uploading and connect it back after the upload was complete.

After fixing this problem, we were able to get the camera board to take a picture and the system to write a file on the SD Card. This happened a total of at least 5 times. However, they were only flukes because about 2/5 times, the picture was blurry, and the rest of the time, the file written was an empty JPEG (Zero bytes). We looked into the Serial Monitor, and it was displaying unreadable gibberish text. We continued to ask Matt for help, but eventually we deduced that the code from RadioShack might not be configured properly.

It was at this point that we had to leave Metrix because it was time for them to close. However, Matt said that Richard would be on duty the following morning, and that Richard was a smart guy who would be able to help us with our Arduino problem.

We spent most of the next day at Metrix. Richard worked with us on troubleshooting the code. As hours trickled by, we slowly isolated the problem, and with additional help from other random strangers from Metrix (oh, my gosh, Metrix is amazing!!), Maddie and I (and Richard, and Dan, and Aaron) concluded that there was simply something wrong with the code.

The system first kept getting stuck at the capture_photo function, and seemed like it was randomizing writing the file when the picture was supposedly taken. As we narrowed down where the problem code was, it soon became clear that the code provided by RadioShack for both the camera board and SD card shield, which we customized, was broken. It wouldn't even take a write the picture file anymore. As neither Maddie nor I knew enough about going into the code libraries for camera shield and SD card shield to fix the code, and upon confirming that it wouldn't be an easy task for our generous helpers either, we finally accepted that Maddie and I could not fit this square peg of our vision into the round hole of the equipment and code we got from RadioShack.

Fearing the very real possibility that our code ultimately would not work the day before, and that the solution to our design situation might not become a reality, Maddie and I had brainstormed other alternatives. One of the ideas that stuck because we thought it was silly, and would be fun to do, was this thought of a motion-triggered water gun/cannon to ward off intruders/lurkers/pee-happy dogs. However, upon further thought, we found that we didn't like the negative connotations of guns or cannons, and that we wanted to do something more approachable. We still wanted to have motion be the thing that was being sensed, and re-devised a situation.

Perhaps in a "life imitates art" sort of way, one of the situations we discussed kept getting revisited: stress relief.

We asked ourselves, how could Arduino solve the problem of stress? Perhaps it was inspired from our water gun/cannon idea, but we came up with something pretty smile-inducing: bubbles.

There's no way you could say "bubbles" angry.

So, with this Plan B at the back of our mind, we simultaneously tried to build a working motion-triggered bubble machine while trying to fix the code for the camera. And we succeeded!




Below are some codes (in final stages) we used to try to isolate and fix the problem.



CUSTOMIZED CODE FROM http://stratigrafia.org/blog/entries/2012-09-01.html

(There are redundancies on this code, but it shouldn't affect the outcome. Our new friend Dan, who seemed pretty knowledgeable on Arduino, looked over this code and found nothing that stood out to him as wrong.)


// Based on http://luckylarry.co.uk/arduino-projects/arduino-motion-triggered-camera/
// The sequence of pulses needed appears to have been reverse engineered at http://www.bigmike.it/ircontrol/
// This is another useful site on the subject: http://www.bemasher.net/archives/114




//BEGIN CAMERA STUFF


/******************** (C) COPYRIGHT 2012 RadioSHack ********************
 * File Name          : camsd.pde
 * Author             : TRS
 * Version            : V1.0
 * Date               : 28/05/2012
 * Description        : Main program body
 ********************************************************************************
 * THE PRESENT SOFTWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
 * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME.
 * AS A RESULT, RS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
 * INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE
 * CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING
 * INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
 *******************************************************************************/

#include <avr/pgmspace.h>
#include "Arduino.h"


/*
 * The following code includes all necessary routines to control Camera Shield
 *
 * In addition, we have prepared a example for making surveillance camera by putting Camera shield (RS SKU 2760248) and SD Card shield (RS SKU 2760243) together.
 * 1) Install SD Card shield properly and download all necessary FAT drivers from shield providers
 * 2) Install Camera shield properly
 * 3) Enable "#define sdCamera 1" to enable the demo code
 * 4) With the built-in motion detection function, camera shield will capture image and store to SD card automatically .
 *
 */

#define sdCamera 1 // ***** Enable it for Surveillance Camera demonstration *****

#ifdef sdCamera
#include <Sd2Card.h> // ***** SD card driver from http://www.seeedstudio.com/wiki/SD_Card_Shield or SD card shield supplier *****
#include <SdFat.h> // ***** FAT file system from http://www.seeedstudio.com/wiki/SD_Card_Shield or SD card shield supplier *****
#endif



/*
 * SD chip select pin.  Common values are:
 *
 * Arduino Ethernet shield, pin 4.
 * SparkFun SD shield, pin 8.
 * Adafruit SD shields and modules, pin 10.
 * Default SD chip select is the SPI SS pin.
 */

#ifdef sdCamera
const uint8_t SdChipSelect = SS;
SdFat sd;
Sd2Card card;
SdFile myFile;
#endif

#define NORMAL_USE 1

#define VC0706_PROTOCOL_SIGN  0x56
#define VC0706_SERIAL_NUMBER  0x00

#define VC0706_COMMAND_RESET 0x26
#define VC0706_COMMAND_GEN_VERSION 0x11
#define VC0706_COMMAND_TV_OUT_CTRL 0x44
#define VC0706_COMMAND_OSD_ADD_CHAR 0x45
#define VC0706_COMMAND_DOWNSIZE_SIZE 0x53
#define VC0706_COMMAND_READ_FBUF 0x32
#define FBUF_CURRENT_FRAME 0
#define FBUF_NEXT_FRAME 0

#define VC0706_COMMAND_FBUF_CTRL 0x36
#define VC0706_COMMAND_COMM_MOTION_CTRL 0x37
#define VC0706_COMMAND_COMM_MOTION_DETECTED 0x39
#define VC0706_COMMAND_POWER_SAVE_CTRL 0x3E
#define VC0706_COMMAND_COLOR_CTRL 0x3C
#define VC0706_COMMAND_MOTION_CTRL 0x42


#define VC0706_COMMAND_WRITE_DATA 0x31
#define VC0706_COMMAND_GET_FBUF_LEN 0x34

#define READ_DATA_BLOCK_NO 56




unsigned char  tx_counter;
unsigned char  tx_vcbuffer[20];
bool tx_ready;

bool rx_ready;
unsigned char  rx_counter;
unsigned char  VC0706_rx_buffer[80];

uint32_t  frame_length=0;

uint32_t  vc_frame_address =0;

uint32_t  last_data_length=0;


// END CAMERA STUFF




int pirPin = 4; // digital pin 4 for PIR; put a 10k Ohm resistor between pin 4 and OUT on PIR
int ledPin = 7; // digital pin 13 for LED; put a 220 Ohm resistor between pin 13 and the LED
int IRPin = 2; // assign the Infrared emitter/ diode to pin 2; connect other lead of IR diode into ground
int noMotion = 1;
int TIP120pin = 9; //for this project, I pick Arduino's PMW pin 11

// pulse the infrared emitter for a specified duration (in microseconds)
void pulseON(int pulseDuration) {
  unsigned long endPulse = micros() + pulseDuration; // calculate time when pulse should stop
  int halfCycle = 13; // half a clock cycle for a 38 Khz (26.32 microseconds period) wave
  while(micros() < endPulse) {
    digitalWrite(IRPin, HIGH); // emit IR for half a cycle
    delayMicroseconds(halfCycle);
    digitalWrite(IRPin, LOW); // stop emitting for half a cycle
    delayMicroseconds(halfCycle);
  }
}

// stop pulsing the infrared emitter for a specified duration (in microseconds)
void pulseOFF(unsigned long delayDuration) {
  unsigned long endDelay = micros() + delayDuration; // calculate time when delay is over
  while(micros() < endDelay);
}

// sequence of pulses for taking a picture on a Nikon D80 camera
void takePicture() {
  for (int i=0; i<2; i++) {
    pulseON(2000); // pulse for 2000 microseconds,
    pulseOFF(27850); // then off for 27850 microseconds,
    pulseON(390); // on for 390 microseconds, and so on
    pulseOFF(1580);
    pulseON(410);
    pulseOFF(3580);
    pulseON(400);
    pulseOFF(63200);
  } // loop the signal twice.
}

void setup() {

  Serial.begin(115200);
  Serial.println("Hello, world");

  pinMode(pirPin, INPUT); // set PIR pin as input
  pinMode(ledPin, OUTPUT); // set LED pin as output
  pinMode(IRPin, OUTPUT); // set pin as output
  pinMode(TIP120pin, OUTPUT); // Set pin for output to control TIP120 Base pin
  //attachInterrupt(0, capture_photo, CHANGE); // When pin 0 changes, camera takes a picture.
}



void loop() {
  int movementSensor=digitalRead(pirPin);

  if(movementSensor == HIGH) {
  // motion detected
    if (noMotion == 0) {
  // take picture only if coming from a state of no motion
      digitalWrite(TIP120pin, HIGH);
      digitalWrite(ledPin, HIGH);
      //takePicture();
      capture_photo();
      noMotion=1;
  //    delay(5000); // wait 5 seconds between pictures
    }
  } else {
    // No motion
    digitalWrite(TIP120pin, LOW);
    digitalWrite(ledPin, LOW);
    noMotion=0;
  }
}


// BEGIN BUFFER SEND

/*******************************************************************************
 * Function Name  : buffer_send
 * Description    : Transmit buffer to VC0706
 *              
 * Input          : tx_vcbuffer
 *              
 * Output         : None
 * Return         : None
 *******************************************************************************/
void buffer_send()
{
int i=0;

for (i=0;i<tx_counter;i++)
Serial.write(tx_vcbuffer[i]);

tx_ready=true;
}

// END BUFFER SEND


// BEGIN FRAME_CONTROL

/*******************************************************************************
 * Function Name  : VC0706_frame_control
 * Description    : control frame buffer register
 *              
 * Input          : frame_control=control flag(1byte)
 * 0 = stop current frame ; 1= stop next frame;2=step frame;3 =resume frame;
 *              
 * Output         : None
 * Return         : None
 *******************************************************************************/
void VC0706_frame_control(byte frame_control)
{
if(frame_control>3)frame_control=3;
tx_vcbuffer[0]=VC0706_PROTOCOL_SIGN;
tx_vcbuffer[1]=VC0706_SERIAL_NUMBER;
tx_vcbuffer[2]=VC0706_COMMAND_FBUF_CTRL;
tx_vcbuffer[3]=0x01;
tx_vcbuffer[4]=frame_control;
tx_counter=5;

buffer_send();
}


// END FRAME_CONTROL



// BEGIN PASTE STUFF 1


/*******************************************************************************
 * Function Name  : VC0706_compression_ratio
 * Description   : stop current frame for reading
 *
 * Input   : ration >13(minimum)
 * <63(max)
 *
 * Output   : None
 * Return   : None
 *******************************************************************************/
void VC0706_compression_ratio(int ratio)
{
if(ratio>63)ratio=63;
if(ratio<13)ratio=13;
int vc_comp_ratio=(ratio-13)*4+53;
tx_vcbuffer[0]=VC0706_PROTOCOL_SIGN;
tx_vcbuffer[1]=VC0706_SERIAL_NUMBER;
tx_vcbuffer[2]=VC0706_COMMAND_WRITE_DATA;
tx_vcbuffer[3]=0x05;
tx_vcbuffer[4]=01; //chip register
tx_vcbuffer[5]=0x01; //data num ready to write
tx_vcbuffer[6]=0x12; //register address
tx_vcbuffer[7]=0x04;
tx_vcbuffer[8]=vc_comp_ratio; //data

tx_counter=9;

buffer_send();
}

// END PASTE STUFF 1


// BEGIN GET FRAMEBUFFER LENGTH


/*******************************************************************************
 * Function Name  : VC0706_get_framebuffer_length
 * Description    : get byte-lengths in FBUF
 *              
 * Input          : fbuf_type =current or next frame
 *             0   =  current frame
 *      1   =  next frame
 *              
 * Output         : None
 * Return         : None
 *******************************************************************************/
void VC0706_get_framebuffer_length(byte fbuf_type)
{
if(fbuf_type>1)fbuf_type=1;
tx_vcbuffer[0]=VC0706_PROTOCOL_SIGN;
tx_vcbuffer[1]=VC0706_SERIAL_NUMBER;
tx_vcbuffer[2]=VC0706_COMMAND_GET_FBUF_LEN;
tx_vcbuffer[3]=0x01;
tx_vcbuffer[4]=fbuf_type;
tx_counter=5;

buffer_send();
}


// END GET FRAMEBUFFER LENGTH

// BEGIN BUFFER READ

/*******************************************************************************
 * Function Name  : buffer_read
 * Description    : Receive buffer from VC0706
 *              
 * Input          : None
 *              
 * Output         : rx_buffer, rx_ready
 * Return         : None
 *******************************************************************************/
void buffer_read()
{
bool validity=true;

if (rx_ready) // if something unread in buffer, just quit
return;

rx_counter=0;
VC0706_rx_buffer[0]=0;
while (Serial.available() > 0)
{
VC0706_rx_buffer[rx_counter++]= Serial.read();
//delay(1);
}

if (VC0706_rx_buffer[0]!=0x76)
validity=false;
if (VC0706_rx_buffer[1]!=VC0706_SERIAL_NUMBER)
validity=false;

if (validity) rx_ready=true;


}

// END BUFFER READ


// BEGIN READ FRAME BUFFER

/*******************************************************************************
 * Function Name  : VC0706_read_frame_buffer
 * Description    : read image data from FBUF
 *              
 * Input          : buffer_address(4 bytes); buffer_length(4 bytes)
 *              
 * Output         : None
 * Return         : None
 *******************************************************************************/
void VC0706_read_frame_buffer(unsigned long buffer_address, unsigned long buffer_length)
{

tx_vcbuffer[0]=VC0706_PROTOCOL_SIGN;
tx_vcbuffer[1]=VC0706_SERIAL_NUMBER;
tx_vcbuffer[2]=VC0706_COMMAND_READ_FBUF;
tx_vcbuffer[3]=0x0c;
tx_vcbuffer[4]=FBUF_CURRENT_FRAME;
tx_vcbuffer[5]=0x0a; // 0x0a=data transfer by MCU mode; 0x0f=data transfer by SPI interface
tx_vcbuffer[6]=buffer_address>>24; //starting address
tx_vcbuffer[7]=buffer_address>>16;
tx_vcbuffer[8]=buffer_address>>8;
tx_vcbuffer[9]=buffer_address&0x0ff;

tx_vcbuffer[10]=buffer_length>>24; // data length
tx_vcbuffer[11]=buffer_length>>16;
tx_vcbuffer[12]=buffer_length>>8;
tx_vcbuffer[13]=buffer_length&0x0ff;
tx_vcbuffer[14]=0x00; // delay time
tx_vcbuffer[15]=0x0a;


tx_counter=16;

buffer_send();
}


// END READ FRAME BUFFER


#ifdef sdCamera

/*******************************************************************************
 * Function Name  : capture_photo
 * Description   : capture a photo and store the file named temp.jpg into SD
 *
 * Input   : None
 *
 * Output   : None
 * Return   : None
 *******************************************************************************/
void capture_photo(){

// Check to see if the file exists:
// if exists,delete the file:
if(sd.exists("temp.jpg")) sd.remove("temp.jpg");

  Serial.println("A");
// open a new empty file for write at end like the Native SD library
 if (!myFile.open("temp.jpg", O_RDWR | O_CREAT | O_AT_END)) {
   sd.errorHalt("opening temp.jpg for write failed");
 }

  Serial.println("b");
// close the file:
 myFile.close();

VC0706_compression_ratio(63);
delay(100);
  Serial.println("c");

VC0706_frame_control(3);
delay(10);
  Serial.println("d");

VC0706_frame_control(0);
delay(10);
rx_ready=false;
rx_counter=0;
  Serial.println("e");

//Serial.end(); // clear all rx buffer
//delay(5);

//Serial.begin(115200);

//get frame buffer length
VC0706_get_framebuffer_length(0);
delay(10);
buffer_read();

//while(1){};

// store frame buffer length for coming reading
frame_length=(VC0706_rx_buffer[5]<<8)+VC0706_rx_buffer[6];
frame_length=frame_length<<16;
frame_length=frame_length+(0x0ff00&(VC0706_rx_buffer[7]<<8))+VC0706_rx_buffer[8];

vc_frame_address =READ_DATA_BLOCK_NO;

myFile.open("temp.jpg", O_RDWR);
while(vc_frame_address<frame_length){
VC0706_read_frame_buffer(vc_frame_address-READ_DATA_BLOCK_NO, READ_DATA_BLOCK_NO);
delay(9);

//get the data with length=READ_DATA_BLOCK_NObytes
rx_ready=false;
rx_counter=0;
buffer_read();

// write data to temp.jpg
myFile.write(VC0706_rx_buffer+5,READ_DATA_BLOCK_NO);

//read next READ_DATA_BLOCK_NO bytes from frame buffer
vc_frame_address=vc_frame_address+READ_DATA_BLOCK_NO;

}

// get the last data
vc_frame_address=vc_frame_address-READ_DATA_BLOCK_NO;

last_data_length=frame_length-vc_frame_address;


VC0706_read_frame_buffer(vc_frame_address,last_data_length);
delay(9);
//get the data
rx_ready=false;
rx_counter=0;
buffer_read();

myFile.write(VC0706_rx_buffer+5,last_data_length);

myFile.close();

}

#endif








BASIC SD CARD WRITE

void setup()
{
  pinMode(13,OUTPUT);
  digitalWrite(13,HIGH);
  //Serial.begin(115200);
  if (!myFile.open("temp.jpg", O_RDWR | O_CREAT | O_AT_END)) {
     sd.errorHalt("opening temp.jpg for write failed");
   }
  //Serial.println("success");
  digitalWrite(13,LOW);
}

void loop()
{


}

Actuator Experimentation [Maddie and Candice]

Because Maddie and I didn't want to use a heavy DSLR as our camera for our security system, we searched for other options. Our research yielded this Arduino-compatible JPEG color camera board straight from RadioShack! We thanked our lucky stars because we wouldn't have to wait for our camera board to ship - it was right on the Ave!

Shortly after purchasing the camera board, we found out that the camera board could be combined with an SD Card Shield to store the images or video that the camera captured.

After purchasing the SD Card Shield (yet again from RadioShack) and putting in a regular SD Card, we played around with the code from the Support PDE/INO Files and Schematics provided by RadioShack. We followed the instructions on how to set up our camera board with the SD Card Shield (using the SPI Interface Method).

Our hearts sank. None of the code that came along with the product worked. Below are a picture of the camera board with SD Shield, and  two of the several codes we tried.



The RadioShack camera board:
http://www.radioshack.com/product/index.jsp?productId=16513056

The SD Card Shielf:
http://www.radioshack.com/product/index.jsp?productId=13297701&locale=en_US


/******************** (C) COPYRIGHT 2012 RadioSHack ********************
 * File Name          : camsd.pde
 * Author             : TRS
 * Version            : V1.0
 * Date               : 28/05/2012
 * Description        : Main program body
 ********************************************************************************
 * THE PRESENT SOFTWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
 * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME.
 * AS A RESULT, RS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
 * INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE
 * CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING
 * INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
 *******************************************************************************/

#include <avr/pgmspace.h>
#include "Arduino.h"


/*
 * The following code includes all necessary routines to control Camera Shield
 *
 * In addition, we have prepared a example for making surveillance camera by putting Camera shield (RS SKU 2760248) and SD Card shield (RS SKU 2760243) together.
 * 1) Install SD Card shield properly and download all necessary FAT drivers from shield providers
 * 2) Install Camera shield properly
 * 3) Enable "#define sdCamera 1" to enable the demo code
 * 4) With the built-in motion detection function, camera shield will capture image and store to SD card automatically .
 *
 */

#define sdCamera 1 // ***** Enable it for Surveillance Camera demonstration *****

#ifdef sdCamera
#include <Sd2Card.h> // ***** SD card driver from http://www.seeedstudio.com/wiki/SD_Card_Shield or SD card shield supplier *****
#include <SdFat.h> // ***** FAT file system from http://www.seeedstudio.com/wiki/SD_Card_Shield or SD card shield supplier *****
#endif



/*
 * SD chip select pin.  Common values are:
 *
 * Arduino Ethernet shield, pin 4.
 * SparkFun SD shield, pin 8.
 * Adafruit SD shields and modules, pin 10.
 * Default SD chip select is the SPI SS pin.
 */

#ifdef sdCamera
const uint8_t SdChipSelect = SS;
SdFat sd;
Sd2Card card;
SdFile myFile;
#endif

#define NORMAL_USE 1

#define VC0706_PROTOCOL_SIGN  0x56
#define VC0706_SERIAL_NUMBER  0x00

#define VC0706_COMMAND_RESET 0x26
#define VC0706_COMMAND_GEN_VERSION 0x11
#define VC0706_COMMAND_TV_OUT_CTRL 0x44
#define VC0706_COMMAND_OSD_ADD_CHAR 0x45
#define VC0706_COMMAND_DOWNSIZE_SIZE 0x53
#define VC0706_COMMAND_READ_FBUF 0x32
#define FBUF_CURRENT_FRAME 0
#define FBUF_NEXT_FRAME 0

#define VC0706_COMMAND_FBUF_CTRL 0x36
#define VC0706_COMMAND_COMM_MOTION_CTRL 0x37
#define VC0706_COMMAND_COMM_MOTION_DETECTED 0x39
#define VC0706_COMMAND_POWER_SAVE_CTRL 0x3E
#define VC0706_COMMAND_COLOR_CTRL 0x3C
#define VC0706_COMMAND_MOTION_CTRL 0x42


#define VC0706_COMMAND_WRITE_DATA 0x31
#define VC0706_COMMAND_GET_FBUF_LEN 0x34

#define READ_DATA_BLOCK_NO 56




unsigned char  tx_counter;
unsigned char  tx_vcbuffer[20];
bool tx_ready;

bool rx_ready;
unsigned char  rx_counter;
unsigned char  VC0706_rx_buffer[80];

uint32_t  frame_length=0;

uint32_t  vc_frame_address =0;

uint32_t  last_data_length=0;


//------------------------------------------------------------------------------
void buffer_send();



// ***********************************************************************************************************
// *
// *                            Power Up Init.
// *
// *
// ***********************************************************************************************************
void setup()
{

#ifdef NORMAL_USE

#ifdef sdCamera
  // Initialize SdFat or print a detailed error message and halt
  // Use half speed like the native library.
   if (!sd.begin(SdChipSelect, SPI_HALF_SPEED)) sd.initErrorHalt();


Serial.begin(115200);

capture_photo();

delay(100);

VC0706_frame_control(3);
delay(10);

//motion windows setting
VC0706_motion_windows_setting(0x1a5a,0x5000);
delay(10);
VC0706_motion_windows_setting(0x1a5e,0x0a000f000);
delay(10);
VC0706_motion_windows_setting(0x1a62,0x3f010000);
delay(10);
VC0706_motion_windows_setting(0x1a66,0x3c007800);
delay(10);
VC0706_motion_windows_setting(0x1a6a,0x0b400ef00);
delay(10);

//start motion monitoring
VC0706_motion_control(1);
delay(10);
VC0706_motion_detection(1);
delay(10);
Serial.end(); // clear all rx buffer
delay(5);
Serial.begin(115200);
rx_ready=false;
#endif


#else
#endif
}





// ***********************************************************************************************************
// *
// *                            Main Loop
// *
// *
// ***********************************************************************************************************
void loop()
{
#ifdef sdCamera
buffer_read();

if(rx_ready){
rx_ready=false;
if (VC0706_rx_buffer[2]!=VC0706_COMMAND_COMM_MOTION_DETECTED) return;
if (VC0706_rx_buffer[3]!=0x00) return;

//stop motion detection for capture photo
VC0706_motion_control(0);
delay(10);
VC0706_motion_detection(0);
delay(1000);

// capture current photo 1s later
capture_photo();
delay(100);

VC0706_frame_control(3); // resume AV out
delay(10);

//prepare next motion monitoring
VC0706_motion_control(1);
delay(10);
VC0706_motion_detection(1);
delay(10);
Serial.end(); // clear all rx buffer
delay(5);
Serial.begin(115200);
rx_ready=false;
return;

};
#endif

delay(300);

}







/*******************************************************************************
 * Function Name  : VC0706_reset
 * Description    : Reset VC0706
 *              
 * Input          : None
 *              
 * Output         : None
 * Return         : None
 *******************************************************************************/
void VC0706_reset()
{
tx_vcbuffer[0]=VC0706_PROTOCOL_SIGN;
tx_vcbuffer[1]=VC0706_SERIAL_NUMBER;
tx_vcbuffer[2]=VC0706_COMMAND_RESET;
tx_vcbuffer[3]=0x00;

tx_counter=4;

buffer_send();
}



/*******************************************************************************
 * Function Name  : VC0706_get_version
 * Description    : Request version string from VC0706
 *              
 * Input          : None
 *              
 * Output         : None
 * Return         : None
 *******************************************************************************/
void VC0706_get_version()
{
tx_vcbuffer[0]=VC0706_PROTOCOL_SIGN;
tx_vcbuffer[1]=VC0706_SERIAL_NUMBER;
tx_vcbuffer[2]=VC0706_COMMAND_GEN_VERSION;
tx_vcbuffer[3]=0x00;

tx_counter=4;

buffer_send();
}


/*******************************************************************************
 * Function Name  : VC0706_tv_out_control
 * Description    : stop or start TV output from VC0706
 *              
 * Input          : on=0 stop tv output
 ; :  on=1 start tv output
 *              
 * Output         : None
 * Return         : None
 *******************************************************************************/
void VC0706_tv_out_control(int on)
{
tx_vcbuffer[0]=VC0706_PROTOCOL_SIGN;
tx_vcbuffer[1]=VC0706_SERIAL_NUMBER;
tx_vcbuffer[2]=VC0706_COMMAND_TV_OUT_CTRL;
tx_vcbuffer[3]=0x01;
tx_vcbuffer[4]=on;
tx_counter=5;

buffer_send();
}

/*******************************************************************************
 * Function Name  : VC0706_osd_add_char
 * Description    : ADD OSD CHARACTERS TO CHANNELS(CHANNEL 1)
 *              
 * Input          : col : Display column
 * `   row: Display Row
 *   osd_string : display string (max 14 characters)
 *              
 * Output         : None
 * Return         : None
 *******************************************************************************/
void VC0706_osd_add_char(int col, int row, String osd_string)
{
unsigned char col_row;
int string_length;
int i;

col&=0x0f;
row&=0x0f;
col_row=(unsigned char)(col<<4 | row);

string_length=osd_string.length();
if (string_length>14)
string_length=14; // max 14 osd characters

tx_vcbuffer[0]=VC0706_PROTOCOL_SIGN;
tx_vcbuffer[1]=VC0706_SERIAL_NUMBER;
tx_vcbuffer[2]=VC0706_COMMAND_OSD_ADD_CHAR;
tx_vcbuffer[3]=string_length+2;
tx_vcbuffer[4]=string_length; // character number
tx_vcbuffer[5]=col_row;

for (i=0;i<string_length;i++)
{
tx_vcbuffer[i+6]=osd_string.charAt(i);
}

tx_counter=string_length+6;

buffer_send();
}


/*******************************************************************************
 * Function Name  : VC0706_w_h_downsize
 * Description    : control width and height downsize attribute
 *              
 * Input          : scale_width = 0 1:1
 *                         = 1 1:2
 *                         = 2 1:4
 *    scale_height= 0 1:1
 *                         = 1 1:2
 *                         = 2 1:4
 *                  
 * Output         : None
 * Return         : None
 *******************************************************************************/
void VC0706_w_h_downsize(int scale_width, int scale_height)
{
int scale;

if (scale_width>=2) scale_width=2;
if (scale_height>scale_width) scale_height=scale_width;
scale=(unsigned char)(scale_height<<2 | scale_width);


tx_vcbuffer[0]=VC0706_PROTOCOL_SIGN;
tx_vcbuffer[1]=VC0706_SERIAL_NUMBER;
tx_vcbuffer[2]=VC0706_COMMAND_DOWNSIZE_SIZE;
tx_vcbuffer[3]=0x01;

tx_vcbuffer[4]=scale; //bit[1:0] width zooming proportion
//bit[3:2] height zooming proportion

tx_counter=5;

buffer_send();
}

/*******************************************************************************
 * Function Name  : VC0706_read_frame_buffer
 * Description    : read image data from FBUF
 *              
 * Input          : buffer_address(4 bytes); buffer_length(4 bytes)
 *              
 * Output         : None
 * Return         : None
 *******************************************************************************/
void VC0706_read_frame_buffer(unsigned long buffer_address, unsigned long buffer_length)
{

tx_vcbuffer[0]=VC0706_PROTOCOL_SIGN;
tx_vcbuffer[1]=VC0706_SERIAL_NUMBER;
tx_vcbuffer[2]=VC0706_COMMAND_READ_FBUF;
tx_vcbuffer[3]=0x0c;
tx_vcbuffer[4]=FBUF_CURRENT_FRAME;
tx_vcbuffer[5]=0x0a; // 0x0a=data transfer by MCU mode; 0x0f=data transfer by SPI interface
tx_vcbuffer[6]=buffer_address>>24; //starting address
tx_vcbuffer[7]=buffer_address>>16;
tx_vcbuffer[8]=buffer_address>>8;
tx_vcbuffer[9]=buffer_address&0x0ff;

tx_vcbuffer[10]=buffer_length>>24; // data length
tx_vcbuffer[11]=buffer_length>>16;
tx_vcbuffer[12]=buffer_length>>8;
tx_vcbuffer[13]=buffer_length&0x0ff;
tx_vcbuffer[14]=0x00; // delay time
tx_vcbuffer[15]=0x0a;


tx_counter=16;

buffer_send();
}



/*******************************************************************************
 * Function Name  : VC0706_frame_control
 * Description    : control frame buffer register
 *              
 * Input          : frame_control=control flag(1byte)
 * 0 = stop current frame ; 1= stop next frame;2=step frame;3 =resume frame;
 *              
 * Output         : None
 * Return         : None
 *******************************************************************************/
void VC0706_frame_control(byte frame_control)
{
if(frame_control>3)frame_control=3;
tx_vcbuffer[0]=VC0706_PROTOCOL_SIGN;
tx_vcbuffer[1]=VC0706_SERIAL_NUMBER;
tx_vcbuffer[2]=VC0706_COMMAND_FBUF_CTRL;
tx_vcbuffer[3]=0x01;
tx_vcbuffer[4]=frame_control;
tx_counter=5;

buffer_send();
}


/*******************************************************************************
 * Function Name  : VC0706_motion_detection
 * Description    : get motion monitoring status in communication interface.
 *              
 * Input          : control_flag = 0 stop motion monitoring
 *       = 1 start motion monitoring              
 *
 * Output         : None
 * Return         : None
 *******************************************************************************/
void VC0706_motion_detection(int control_flag)
{
if(control_flag>1)control_flag=1;
tx_vcbuffer[0]=VC0706_PROTOCOL_SIGN;
tx_vcbuffer[1]=VC0706_SERIAL_NUMBER;
tx_vcbuffer[2]=VC0706_COMMAND_COMM_MOTION_CTRL;
tx_vcbuffer[3]=0x01;
tx_vcbuffer[4]=control_flag;
tx_counter=5;

buffer_send();
}

/*******************************************************************************
 * Function Name  : VC0706_motion_control
 * Description    : motion control
 *              
 * Input          : control_flag = 0 forbid motion monitoring
 *       = 1 enable motion monitoring              
 *
 * Output         : None
 * Return         : None
 *******************************************************************************/
void VC0706_motion_control(int control_flag)
{
if(control_flag>1)control_flag=1;
tx_vcbuffer[0]=VC0706_PROTOCOL_SIGN;
tx_vcbuffer[1]=VC0706_SERIAL_NUMBER;
tx_vcbuffer[2]=VC0706_COMMAND_MOTION_CTRL;
tx_vcbuffer[3]=0x03;
tx_vcbuffer[4]=0x00; //motion control attribute
tx_vcbuffer[5]=0x01; //mcu uart control
tx_vcbuffer[6]=control_flag;
tx_counter=7;

buffer_send();
}






/*******************************************************************************
 * Function Name  : VC0706_get_framebuffer_length
 * Description    : get byte-lengths in FBUF
 *              
 * Input          : fbuf_type =current or next frame
 *             0   =  current frame
 *      1   =  next frame
 *              
 * Output         : None
 * Return         : None
 *******************************************************************************/
void VC0706_get_framebuffer_length(byte fbuf_type)
{
if(fbuf_type>1)fbuf_type=1;
tx_vcbuffer[0]=VC0706_PROTOCOL_SIGN;
tx_vcbuffer[1]=VC0706_SERIAL_NUMBER;
tx_vcbuffer[2]=VC0706_COMMAND_GET_FBUF_LEN;
tx_vcbuffer[3]=0x01;
tx_vcbuffer[4]=fbuf_type;
tx_counter=5;

buffer_send();
}



/*******************************************************************************
 * Function Name  : VC0706_uart_power_save
 * Description    : stop current frame for reading
 *              
 * Input          : power_on =1  start power-save
 *    = 0  stop power-save
 *              
 * Output         : None
 * Return         : None
 *******************************************************************************/
void VC0706_uart_power_save(byte power_save_on)
{
tx_vcbuffer[0]=VC0706_PROTOCOL_SIGN;
tx_vcbuffer[1]=VC0706_SERIAL_NUMBER;
tx_vcbuffer[2]=VC0706_COMMAND_POWER_SAVE_CTRL;
tx_vcbuffer[3]=0x03;
tx_vcbuffer[4]=00; //power save control mode
tx_vcbuffer[5]=01; // control by UART
tx_vcbuffer[6]=power_save_on; //start power save
tx_counter=7;

buffer_send();
}


/*******************************************************************************
 * Function Name  : VC0706_uart_color_control
 * Description    : stop current frame for reading
 *              
 * Input          : show_mode = 0  automatically step black-white and colour
 *    1  manually step color, select colour
 *    2 manually step color, select black-white
 *              
 * Output         : None
 * Return         : None
 *******************************************************************************/
void VC0706_uart_color_control(byte show_mode)
{
if(show_mode>2) show_mode=2;
tx_vcbuffer[0]=VC0706_PROTOCOL_SIGN;
tx_vcbuffer[1]=VC0706_SERIAL_NUMBER;
tx_vcbuffer[2]=VC0706_COMMAND_COLOR_CTRL;
tx_vcbuffer[3]=0x02;
tx_vcbuffer[4]=01; //control by UART
tx_vcbuffer[5]=show_mode; // automatically step black-white and colour
tx_counter=6;

buffer_send();
}



/*******************************************************************************
 * Function Name  : VC0706_compression_ratio
 * Description   : stop current frame for reading
 *
 * Input   : ration >13(minimum)
 * <63(max)
 *
 * Output   : None
 * Return   : None
 *******************************************************************************/
void VC0706_compression_ratio(int ratio)
{
if(ratio>63)ratio=63;
if(ratio<13)ratio=13;
int vc_comp_ratio=(ratio-13)*4+53;
tx_vcbuffer[0]=VC0706_PROTOCOL_SIGN;
tx_vcbuffer[1]=VC0706_SERIAL_NUMBER;
tx_vcbuffer[2]=VC0706_COMMAND_WRITE_DATA;
tx_vcbuffer[3]=0x05;
tx_vcbuffer[4]=01; //chip register
tx_vcbuffer[5]=0x01; //data num ready to write
tx_vcbuffer[6]=0x12; //register address
tx_vcbuffer[7]=0x04;
tx_vcbuffer[8]=vc_comp_ratio; //data

tx_counter=9;

buffer_send();
}


/*******************************************************************************
 * Function Name  : VC0706_motion_windows_setting
 * Description   : motion windows setting
 *
 * Input   : register_address(2 bytes);
 * data(4 bytes)= data ready to write
 *
 * Output   : None
 * Return   : None
 *******************************************************************************/
void VC0706_motion_windows_setting(unsigned int register_address, unsigned long data)
{
tx_vcbuffer[0]=VC0706_PROTOCOL_SIGN;
tx_vcbuffer[1]=VC0706_SERIAL_NUMBER;
tx_vcbuffer[2]=VC0706_COMMAND_WRITE_DATA;
tx_vcbuffer[3]=0x08;
tx_vcbuffer[4]=01; //chip register
tx_vcbuffer[5]=0x04; //data num ready to write
tx_vcbuffer[6]=register_address>>8; //register address
tx_vcbuffer[7]=register_address&0x0ff;;

tx_vcbuffer[8]=data>>24; // data ready to write
tx_vcbuffer[9]=data>>16;
tx_vcbuffer[10]=data>>8;
tx_vcbuffer[11]=data&0x0ff;

tx_counter=12;

buffer_send();
}




/*******************************************************************************
 * Function Name  : debug_send
 * Description   : Transmit buffer to Arduino Serial Monitor
 *
 * Input   : tx_vcbuffer
 *
 * Output   : None
 * Return   : None
 *******************************************************************************/
void debug_send()
{
int i=0;

for (i=0;i<tx_counter;i++)
{
Serial.print(tx_vcbuffer[i], HEX);
Serial.print(", ");
}

Serial.println("");
}



/*******************************************************************************
 * Function Name  : buffer_send
 * Description    : Transmit buffer to VC0706
 *              
 * Input          : tx_vcbuffer
 *              
 * Output         : None
 * Return         : None
 *******************************************************************************/
void buffer_send()
{
int i=0;

for (i=0;i<tx_counter;i++)
Serial.write(tx_vcbuffer[i]);

tx_ready=true;
}



/*******************************************************************************
 * Function Name  : buffer_read
 * Description    : Receive buffer from VC0706
 *              
 * Input          : None
 *              
 * Output         : rx_buffer, rx_ready
 * Return         : None
 *******************************************************************************/
void buffer_read()
{
bool validity=true;

if (rx_ready) // if something unread in buffer, just quit
return;

rx_counter=0;
VC0706_rx_buffer[0]=0;
while (Serial.available() > 0)
{
VC0706_rx_buffer[rx_counter++]= Serial.read();
//delay(1);
}

if (VC0706_rx_buffer[0]!=0x76)
validity=false;
if (VC0706_rx_buffer[1]!=VC0706_SERIAL_NUMBER)
validity=false;

if (validity) rx_ready=true;


}

#ifdef sdCamera

/*******************************************************************************
 * Function Name  : capture_photo
 * Description   : capture a photo and store the file named temp.jpg into SD
 *
 * Input   : None
 *
 * Output   : None
 * Return   : None
 *******************************************************************************/
void capture_photo(){

// Check to see if the file exists:
// if exists,delete the file:
if(sd.exists("temp.jpg")) sd.remove("temp.jpg");

// open a new empty file for write at end like the Native SD library
 if (!myFile.open("temp.jpg", O_RDWR | O_CREAT | O_AT_END)) {
   sd.errorHalt("opening temp.jpg for write failed");
 }

// close the file:
 myFile.close();

VC0706_compression_ratio(63);
delay(100);

VC0706_frame_control(3);
delay(10);

VC0706_frame_control(0);
delay(10);
rx_ready=false;
rx_counter=0;

Serial.end(); // clear all rx buffer
delay(5);

Serial.begin(115200);

//get frame buffer length
VC0706_get_framebuffer_length(0);
delay(10);
buffer_read();

//while(1){};

// store frame buffer length for coming reading
frame_length=(VC0706_rx_buffer[5]<<8)+VC0706_rx_buffer[6];
frame_length=frame_length<<16;
frame_length=frame_length+(0x0ff00&(VC0706_rx_buffer[7]<<8))+VC0706_rx_buffer[8];

vc_frame_address =READ_DATA_BLOCK_NO;

myFile.open("temp.jpg", O_RDWR);
while(vc_frame_address<frame_length){
VC0706_read_frame_buffer(vc_frame_address-READ_DATA_BLOCK_NO, READ_DATA_BLOCK_NO);
delay(9);

//get the data with length=READ_DATA_BLOCK_NObytes
rx_ready=false;
rx_counter=0;
buffer_read();

// write data to temp.jpg
myFile.write(VC0706_rx_buffer+5,READ_DATA_BLOCK_NO);

//read next READ_DATA_BLOCK_NO bytes from frame buffer
vc_frame_address=vc_frame_address+READ_DATA_BLOCK_NO;

}

// get the last data
vc_frame_address=vc_frame_address-READ_DATA_BLOCK_NO;

last_data_length=frame_length-vc_frame_address;


VC0706_read_frame_buffer(vc_frame_address,last_data_length);
delay(9);
//get the data
rx_ready=false;
rx_counter=0;
buffer_read();

myFile.write(VC0706_rx_buffer+5,last_data_length);

myFile.close();

}

#endif





AND





// Quick hardware test
#include <SdFat.h>
// Test with reduced SPI speed for breadboards.
// Change spiSpeed to SPI_FULL_SPEED for better performance
// Use SPI_QUARTER_SPEED for even slower SPI bus speed
const uint8_t spiSpeed = SPI_HALF_SPEED;
//------------------------------------------------------------------------------
// Normally SdFat is used in applications in place
// of Sd2Card, SdVolume, and SdFile for root.
Sd2Card card;
SdVolume volume;
SdFile root;

// Serial streams
ArduinoOutStream cout(Serial);

// input buffer for line
char cinBuf[40];
ArduinoInStream cin(Serial, cinBuf, sizeof(cinBuf));

// SD card chip select
int chipSelect;

void cardOrSpeed() {
  cout << pstr(
    "Try another SD card or reduce the SPI bus speed.\n"
    "The current SPI speed is: ");
  uint8_t divisor = 1;
  for (uint8_t i = 0; i < spiSpeed; i++) divisor *= 2;
  cout << F_CPU * 0.5e-6 / divisor << pstr(" MHz\n");
  cout << pstr("Edit spiSpeed in this sketch to change it.\n");
}

void reformatMsg() {
  cout << pstr("Try reformatting the card.  For best results use\n");
  cout << pstr("the SdFormatter sketch in SdFat/examples or download\n");
  cout << pstr("and use SDFormatter from www.sdcard.org/consumer.\n");
}

void setup() {
  Serial.begin(9600);
  cout << pstr(
    "\nSD chip select is the key hardware option.\n"
    "Common values are:\n"
    "Arduino Ethernet shield, pin 4\n"
    "Sparkfun SD shield, pin 8\n"
    "Adafruit SD shields and modules, pin 10\n");
}

bool firstTry = true;
void loop() {
  // read any existing Serial data
  while (Serial.read() >= 0) {}

  if (!firstTry) cout << pstr("\nRestarting\n");
  firstTry = false;

  cout << pstr("\nEnter the chip select pin number: ");
  cin.readline();
  if (cin >> chipSelect) {
    cout << chipSelect << endl;
  } else {
    cout << pstr("\nInvalid pin number\n");
    return;
  }
  if (!card.init(spiSpeed, chipSelect)) {
    cout << pstr(
      "\nSD initialization failed.\n"
      "Do not reformat the card!\n"
      "Is the card correctly inserted?\n"
      "Is chipSelect set to the correct value?\n"
      "Is there a wiring/soldering problem?\n");
    cout << pstr("errorCode: ") << hex << showbase << int(card.errorCode());
    cout << pstr(", errorData: ") << int(card.errorData());
    cout << dec << noshowbase << endl;
    return;
  }
  cout << pstr("\nCard successfully initialized.\n");
  cout << endl;

  uint32_t size = card.cardSize();
  if (size == 0) {
    cout << pstr("Can't determine the card size.\n");
    cardOrSpeed();
    return;
  }
  uint32_t sizeMB = 0.000512 * size + 0.5;
  cout << pstr("Card size: ") << sizeMB;
  cout << pstr(" MB (MB = 1,000,000 bytes)\n");
  cout << endl;

  if (!volume.init(&card)) {
    if (card.errorCode()) {
      cout << pstr("Can't read the card.\n");
      cardOrSpeed();
    } else {
      cout << pstr("Can't find a valid FAT16/FAT32 partition.\n");
      reformatMsg();
    }
    return;
  }
  cout << pstr("Volume is FAT") << int(volume.fatType());
  cout << pstr(", Cluster size (bytes): ") << 512L * volume.blocksPerCluster();
  cout << endl << endl;

  root.close();
  if (!root.openRoot(&volume)) {
    cout << pstr("Can't open root directory.\n");
    reformatMsg();
    return;
  }
  cout << pstr("Files found (name date time size):\n");
  root.ls(LS_R | LS_DATE | LS_SIZE);

  if ((sizeMB > 1100 && volume.blocksPerCluster() < 64)
    || (sizeMB < 2200 && volume.fatType() == 32)) {
    cout << pstr("\nThis card should be reformatted for best performance.\n");
    cout << pstr("Use a cluster size of 32 KB for cards larger than 1 GB.\n");
    cout << pstr("Only cards larger than 2 GB should be formatted FAT32.\n");
    reformatMsg();
    return;
  }
  // read any existing Serial data
  while (Serial.read() >= 0) {}
  cout << pstr("\nSuccess!  Type any character to restart.\n");
  while (Serial.read() < 0) {}
}