Cylon Pumpkin

Hey, would you be willing to share your code & a pic of your circuit? It might be a little much for me on the hardware side, but I'd like to take a look anyway

Where do you buy parts in Ottawa?

Best local sources of parts that I know of are:Gervais Electronics on Industrial near St Laurent, and Active Components on Merivale. Both have walk-in retail with stands of resistors, connectors, and the like and a catalog of components backing them up. For ordering-in I find digikey.ca to be best, $8 flat fee shipping, no customs hassles, and very quick.

Here's a few pics of the Cylon Pumpkin's hardware and the code. Happy to help with any questions.


//version 2 of the cylon pumpkin.
//incorporates wav player with soft playback option
//plays cylon noise at low volume til motion is detected.
//starts cylon noise as soon as motion is detected rather than at beginning of scan
//waveform modified to reduce pop at beginning of playback
#include <stdint.h>
#include <avr/interrupt.h>
#include <avr/io.h>
#include <avr/pgmspace.h>

#define SAMPLE_RATE 8000

//Charlieplexing a cylon pumpkin display
const int cpin1=4;   //Charlieplexing pin 1 
const int cpin2=5;  //Charlieplexing pin 2 
const int cpin3=6; //Charlieplexing pin 3  
const int cpin4=7;  //Charlieplexing pin 4 
const int cpin5=8; //Charlieplexing pin 5
const int cpin6=9; //Charlieplexing pin 5

int clow=1; 
int chigh=25; //low and high scan limits
int s1=clow; 
int delta=1; //scan start, direction
int csfast=50; 
int csslow=200;   //fast and slow scans
int pirpin=3; 
int ledpin=13; //pins for motion detector and standalone led

#include "sounddata.h"


int speakerPin = 11;
volatile uint16_t sample;
byte lastSample;
boolean softly=true; 

void setup() {
  Serial.begin(9600);
  pinMode(ledpin,OUTPUT);
  //give the sensor some time to calibrate
  Serial.print("calibrating sensor ");
  for(int i = 1; i <= 25; i++){
    cplex(i);
    Serial.print(".");
    delay(1000);
  }
  Serial.println(" done");
  Serial.println("SENSOR ACTIVE");
  delay(50);
  startPlayback();

}

void loop(){
  static boolean excited=false; //excited is true when motion is detected
  int csspd=csslow; //by default eye scan is slow
  if(digitalRead(pirpin)==HIGH){
    csspd=csfast;
    digitalWrite(ledpin,HIGH); 
    if (!excited){
      softly=false; 
      startPlayback();
      excited=true;
    } 
  }
  else {
    csspd=csslow; 
    excited=false; 
    softly=true; 
    digitalWrite(ledpin,LOW); 
  }
  int s2=s1+delta; //inner scan
  cplex2(s2,s1,csspd); //cplex 2 positions
  s1=s1+delta;
  if (s1>=chigh){
    s1=chigh-1;
    delta=-1;
  }
  if (s1<=clow){
    s1=clow+1;
    delta=1;
    startPlayback();
  }
}

void cplex2(int which,int which2, int t){ //cplex 2 positions for t ms
  unsigned long when=millis()+t; //when to stop
  while(millis()<when){
    Serial.print(" t=");
    Serial.println(t);
    cplex(which); 
    delay(2);
    cplex(which2); 
    delay(2);
  }
}

void cplex(byte digit){ 
  pinMode(cpin1,INPUT);   
  pinMode(cpin2,INPUT); 
  pinMode(cpin3,INPUT);
  pinMode(cpin4,INPUT);
  pinMode(cpin5,INPUT);
  pinMode(cpin6,INPUT);//safe mode
  digitalWrite(cpin1,LOW);  
  digitalWrite(cpin2,LOW);  
  digitalWrite(cpin3,LOW);  
  digitalWrite(cpin4,LOW);  
  digitalWrite(cpin5,LOW);  
  digitalWrite(cpin6,LOW);
  int cpinh[]={
    cpin1, //0 isn't used
    cpin1,cpin2,cpin1,cpin3,cpin1, //1-5
    cpin4,cpin1,cpin5,cpin1,cpin6, //6-10
    cpin5,cpin6,cpin4,cpin6,cpin3, //11-15
    cpin6,cpin2,cpin6,cpin2,cpin5, //16-20
    cpin2,cpin4,cpin2,cpin3,cpin4  }; //21-25
  int cpinl[]={
    cpin1, //0 isn't used
    cpin2,cpin1,cpin3,cpin1,cpin4,
    cpin1,cpin5,cpin1,cpin6,cpin1,
    cpin6,cpin5,cpin6,cpin4,cpin6,
    cpin3,cpin6,cpin2,cpin5,cpin2,
    cpin4,cpin2,cpin3,cpin2,cpin3  };
  pinMode(cpinh[digit],OUTPUT); 
  digitalWrite(cpinh[digit],HIGH);
  pinMode(cpinl[digit],OUTPUT); 
  digitalWrite(cpinl[digit],LOW);
}
// This is called at 8000 Hz to load the next sample.
ISR(TIMER1_COMPA_vect) {
  if (sample >= sounddata_length) {
    if (sample == sounddata_length + lastSample) {
      stopPlayback();
    }
    else {
      // Ramp down to zero to reduce the click at the end of playback.
      OCR2A = sounddata_length + lastSample - sample;
    }
  }
  else {
    if(softly){
      OCR2A = pgm_read_byte(&sounddata_data[sample])>>2;
    } //reduce volume of playback
    else{
      OCR2A = pgm_read_byte(&sounddata_data[sample]); //full volume playback
    }
  }

  ++sample;
}

void startPlayback()
{
  pinMode(speakerPin, OUTPUT);

  // Set up Timer 2 to do pulse width modulation on the speaker
  // pin.

  // Use internal clock (datasheet p.160)
  ASSR &= ~(_BV(EXCLK) | _BV(AS2));

  // Set fast PWM mode  (p.157)
  TCCR2A |= _BV(WGM21) | _BV(WGM20);
  TCCR2B &= ~_BV(WGM22);

  // Do non-inverting PWM on pin OC2A (p.155)
  // On the Arduino this is pin 11.
  TCCR2A = (TCCR2A | _BV(COM2A1)) & ~_BV(COM2A0);
  TCCR2A &= ~(_BV(COM2B1) | _BV(COM2B0));

  // No prescaler (p.158)
  TCCR2B = (TCCR2B & ~(_BV(CS12) | _BV(CS11))) | _BV(CS10);

  // Set initial pulse width to the first sample.
  if (softly) 
    OCR2A = pgm_read_byte(&sounddata_data[0])>>2;
  else
    OCR2A = pgm_read_byte(&sounddata_data[0]);



  // Set up Timer 1 to send a sample every interrupt.

  cli();

  // Set CTC mode (Clear Timer on Compare Match) (p.133)
  // Have to set OCR1A *after*, otherwise it gets reset to 0!
  TCCR1B = (TCCR1B & ~_BV(WGM13)) | _BV(WGM12);
  TCCR1A = TCCR1A & ~(_BV(WGM11) | _BV(WGM10));

  // No prescaler (p.134)
  TCCR1B = (TCCR1B & ~(_BV(CS12) | _BV(CS11))) | _BV(CS10);

  // Set the compare register (OCR1A).
  // OCR1A is a 16-bit register, so we have to do this with
  // interrupts disabled to be safe.
  OCR1A = F_CPU / SAMPLE_RATE;    // 16e6 / 8000 = 2000

  // Enable interrupt when TCNT1 == OCR1A (p.136)
  TIMSK1 |= _BV(OCIE1A);

  lastSample = pgm_read_byte(&sounddata_data[sounddata_length-1]);
  if (softly) lastSample=lastSample>>2;
  sample = 0;
  sei();
}

void stopPlayback()
{
  // Disable playback per-sample interrupt.
  TIMSK1 &= ~_BV(OCIE1A);

  // Disable the per-sample timer completely.
  TCCR1B &= ~_BV(CS10);

  // Disable the PWM timer.
  TCCR2B &= ~_BV(CS10);

  digitalWrite(speakerPin, LOW);
}