My Projects‎ > ‎

Leonard Birchall Exhibit


INTRODUCTION:

    On 4 April 1942, only two days after arrival, Squadron Leader Birchall was the ocean to the south of Ceylon. Eight hours into the mission, ships were spotted on the horizon.  Investigation revealed a large Japanese fleet, including five aircraft carriers, headed for Ceylon.  Birchall's crew managed to send out a radio message, but was soon shot down. The Japanese still attacked but, but because of 
Birchall’s signal the British cleared the port and, inflicted significant losses on the Japanese.

    After he is shot down he is taken to a Japanese POW camp where he is the senior Allied officer.  He repeatedly stands up and demands better treatment 
for his men
.  For this he is severely beaten.  His actions and leadership drops the death rate from over 30% down to almost nothing.  One day he encounters a group of sick POWs working at the docks, and orders them to stop, for this he is beaten to near death and sent to a disciplinary camp where he continues to fight for better treatment.

    Throughout the ordeal he maintains a diary, knowing that he would be executed if it is ever discovered.  This diary is used as evidence in war trials following the war.

    He continues to serve in the Canadian Forces after the war.
  He is the only military member to receive 5 bars on this Canadian Forces Decoration for 62 years of service.


Air Commodore Leonard Joseph BirchallCMOBEDFCO.OntCD
6 July 1915 - 10 September 2004
RIP *salute*





PROJECT BACKGROUND:

    Something special is hidden in the Greenwood Military Aviation Museum.  A 4' wide and 12' deep diorama containing a Japanese Naval Fleet coming out of the morning fog.  A small blue button holds an amazing surprise.  When pressed the sound of an airplane engine could be heard, the ships come to life and begin to fire.  Anti-aircraft guns and cannon shots could be heard as the morning sky is lit up by the flashes from the guns.  Leonard Birchall's plane can be seen in the sky with 2 Zeros at 3 o'clock high.  And moment in history is recreated.  This is how the Canadian Air Force honored it's heroes.


Picture 1:  The booth itself (built by Ret Gen. Patric and Maj. Johnson)


Picture 2: The models (Maj. Johnson did an amazing job on these models)


Birchall

Video 1:  The display in action (sorry about the quality, I don't have the best camera)





TECHNICAL DETAILS:

    This project is both simple and challenging.   The display needed to support a large number of lights,  the wiring needs to be hidden, sounds must be heard, and finally the thing needs to be as low power as possible.

    My solution was to use an Arduino and use 16 Digital Outputs in order to create an 8 x 8 grid which could support 64 lights when multiplexed properly.  The sound is provided by an MP3 Trigger board from Sparkfun hooked into standard computer speakers.





HARDWARE:

Picture 3: Brains: Arduino, MP3 Trigger and my matrix board


Picture 4: The enclosure, keeps everything dry, and a bit of slack on the wires in-case we want to move some models around.


Picture 5: The belly of the beast, the speakers shown were not loud enough to pump out the sound we wanted, so we now have a set of PC speakers on top of the display that can shake the house.


Figure 1: The Matrix Board


Figure 2: LED cables

    The Cathode of the LEDs are all tied together, and connected to any of the LED COMM ports.  The Anode is connected to the LED SOURCE.


Figure 3: Complete Project Schematic



BOM:
 # ITEM # ofDESCRIPTION PRICE
 1 Arduino 1 The brains $30
 2 MP3 Trigger 1 The voice $50
 3 3mm LED 50 The flash (Off e-bay) $10
 4 ULN2803A 1 Booster for the led common $2
 5 Micro SD 2gb 1 To hold the recording $10
 6 IDE Cable x  Salvaged
 7 7-12V Adapter 1  Salvaged
 8 HEADER 3  $1
 9 PINS 1  $1
 10 Push Button 1 Arcade style $1
 11 PC Speakers 1 Bring on the noise Salvaged
 12 Enclosure 1 Tupperware (Dollar Store) $1
 13 PC Board 1 You need something to solder to $5
 14 330 Ohm Resistor 8 330Ohm Resitors 1/8 watt. $0.50


    A few zip ties, electrical tape, a bit of 2 sided tape and some heat shrink is all you need to complete this.

    Hardware wise this is nothing more then a simple matrix.  The sourcing pins give our LEDs a high signal, and the sinking pins make our darlington give us a ground.  If you are only driving 1 LED at a time the darlington is not really needed since the AVR Digital I/O pins can handle 10mA, however, I wasn't sure how well it would work driving 1 LED at a time.  So i dumped the darlington in just in case we needed to drive 8 LEDs at a time (80mA would be too much for the AVR pins).  Oh and lets not forget the resistors, the source side has the resistors that we need in order to limit the current of the LEDs down to around 5-10mA.






SOFTWARE:



    The software is fairly simple, despite it looking a bit confusing.

    The cannons[][] register holds a time in the 6-0 bit and the 7th bit is a flag.  Every time the counter overflows (every tenth of a second) the register value is decremented. When register hits all 0s, the flag bit (7th bit) is set HIGH(1) and a value of 7 is written to the register (meaning .7 sec).  When the register hits all 0's in the 6-0 bits the Flag bit (7th bit) is set LOW(0) and a random number is loaded into the register starting the cycle all over again.  Yes that's right, I said random, the display is different every time it runs.

    If the flag bit is LOW(0) the LED is off and if the flag bit is HIGH(1) the LED turns on.

    While this is happening the program constantly scans the LED matrix one at a time over and over again.  The sinking and sourcing functions do all the I/O decoding Stuff.

 Function
 Description
 Setup() sets up all the I/O
 main() the main loop
 randomize() loads random values into cannons[][]
 startspeech() starts the recording
 barrage() executes 1 sweep of the matrix
 sinkingOn()
 sets one of the bits on the darlington to give us a ground
 sinkingOff() sets one of the bits on the darlington to not give us a ground
 sourcingOn() sets one of the AVR pins high to drive the LED
 sourcingOff() sets one of the AVR pins low to sink the LED




// Copy of the Arduino Program
/*
Program:  Birchall Exhibit
Author:  Pte. Q
Date: 10 Jun 2010

This program runs the Birchall Exhibit at the Greenwood Aviation 
Museum in Greenwood Nova Scotia.

*/

#include <avr/interrupt.h>



// *** Variables
byte running = 0;
volatile byte cannons[8][8];



// *** setup IO
void setup()
{
  // INPUTS/OUTPUTS
  PORTB = 0;
  DDRB = (1 << DDB0) | (1 << DDB1) | (1 << DDB2) | (1 << DDB3) | (1 << DDB4) | (1 << DDB5);
  
  PORTC = 0;
  DDRC = (1 << DDC0) | (1 << DDC1) | (1 << DDC2) | (1 << DDC3) | (1 << DDC4) | (1 << DDC5);
  
  PORTD = 0;
  PORTD = (1 << 2);  // SET PD2 to be an input with PULLUP enabled
  DDRD = (1 << DDD0) | (1 << DDD1) |(1 << DDD4) | (1 << DDD5) | (1 << DDD6) | (1 << DDD7);


  //Timer2 Settings: Timer Prescaler /1028, 
  TCCR2B |= (1<<CS22) | (1<<CS21) | (1<<CS20);  // turn on CS22 bit
  // Use CTC Mode
  TCCR2A |= (1<<WGM21);
  OCR2A = 0x98;             // 0x98 for .1 sec             
  TIMSK2 |= (1<<OCIE2A);    //Timer2 Overflow Interrupt Enable

  //enable interuputs
  sei();
}



// *** timer2 interupts
// the heart of the program, it decrements the value of cannons[][]. if they hit 0 it generates a new number for them
ISR(TIMER2_COMPA_vect) {
  if (running > 0)
  {
    for (byte x = 0; x < 8; x++)
    {
      for (byte y = 0; y < 8; y++)
      {
        cannons[x][y]--;
      
        if (cannons[x][y] == 0b00000000)
        {
          cannons[x][y] = 0b10000111;
        }
        else if (cannons[x][y] == 0b10000000)
        {
          cannons[x][y] = random(32,54);
        }
      } // end FOR y
    }  // end FOR x
  }  // end IF
}  // end ISR



// *** MAIN LOOP
void loop(){

  // loads up cannons with a random number for the start;

  if (running == 0)
  {
    PORTD |= (1 << 1);  // set high reset sound
    randomize();
  }
  
  // detect keypress with debounce and run english, french or turn off
  if (running == 0 && (PIND & (1 << 2)) == 0)
  {
    delay(50);
    if ((PIND & (1 << 2)) == 0)
    {
      startspeech();
      for (uint8_t delaytimer = 1; delaytimer < 21; delaytimer++)
      {
        delay(100);
      }
      running = 1;
    }  
  }
  
  
  //running = 1;
  if(running > 0)
  {
    for(int i = 0; i < 61; i++)
    {
      delay(5);
      barrage();
    }
    running = 0;
  }

} // END MAIN



// *** randomize all of the bits within cannons[][]
void randomize(void){
    for(byte x = 0; x < 8; x++)
    {
      for(byte y = 0; y < 8; y++)
      {
        cannons[x][y] = random(0x20,0x70);
      }
    }     
}



// *** start the speech
// sends a pulse to the MP3 shield IO PIN
void startspeech (void){

  PORTD &= ~(1 << 1);  // set PD0 low to trigger sound
  delay(500);          // delay 1/2 second
  PORTD |= (1 << 1);   // set high (triggered on low signal)
}



// *** fire the guns
void barrage (void){
  
  for(int x = 0; x < 8; x++)
  {
    sinkingOn (1 << x);
    delay(10);
    for(int y = 0; y < 8; y++)
    {
      
      if (cannons[x][y] >= 0b10000000)
      {
        sourcingOn ((1 << y));
        delay(10);
        sourcingOff ((1 << y));
        delay(10);
      }
    }
    sinkingOff(1 << x);
    delay(1);
  }
}



// ************** byte streem to physical IO translation

// *** Map of bit manipulation to pins
// 8th bit closest to resistors, 1s bit closest to outside of board
// bits ... PB5 PB4 PB3 PB2 PB1 PB0 PD7 PD6
// bits ... [7] [6] [5] [4] [3] [2] [1] [0]
void sinkingOn (byte sinkingoutput){
  
  byte sinkingtmp;

  sinkingtmp = sinkingoutput;

  PORTB |= (sinkingtmp >>2 );                 // PORTB only used for sinking, so we can get away with =
  PORTD |= (sinkingoutput <<6);               // PORTD shared with Sourcing so we need to do some bitmath
}

void sinkingOff (byte sinkingoutput){
  
  byte sinkingtmp;

  sinkingtmp = sinkingoutput;

  PORTB &= ~(sinkingtmp >>2 );               // PORTB only used for sinking, so we can get away with =
  PORTD &= ~(sinkingoutput <<6);             // PORTD shared with Sourcing so we need to do some bitmath
}



// *** Map of bit manipulation to pins
// 8th bit closest to the Darlington, 1s bit closest to outside of board
// bits ... PC5 PC4 PC3 PC2 PC1 PC0 PD5 PD4
// bits ... [7] [6] [5] [4] [3] [2] [1] [0]
void sourcingOn (byte sourcingoutput){

  byte sourcingtmp;

  sourcingtmp = sourcingoutput;
  sourcingoutput = (sourcingoutput << 6);
  
  PORTC |= (sourcingtmp >> 2);               // PORTC = stand alone for sourcing
  PORTD |= (sourcingoutput >> 2);            // PORTD shared with sinking so we need to do some bithmath  
}

void sourcingOff (byte sourcingoutput){

  byte sourcingtmp;

  sourcingtmp = sourcingoutput;
  sourcingoutput = (sourcingoutput << 6);
  
  PORTC &= ~(sourcingtmp >> 2);             // PORTC = stand alone for sourcing
  PORTD &= ~(sourcingoutput >> 2);          // PORTD shared with sinking so we need to do some bithmath  
}



Cheers
Q



Comments