Roy has a WigWag

The Red Signal Light to fade in not too well, but indeed so, but not fading out at the end yet, your homework!

The servo now moves one ding from the center to max, so it takes a longer time to get there...and on the next ding it has to go all the way to the other other side. So when you decide to change the range of the swing, you need to make sure that you also know exactly when you want the servo to be where.

Oh, the original code came from ArduinoGate, thank you Marty.
/*
 * Arduino_Crossing_Gate_controller_WigWag.ino
 *
 * Created: 3/15/2012 4:25:31 PM
 *  Modified: 2015/08/06
 *  Authors: Gert Muller, Marty
 *  Arduino Uno ATMega328P 16MHz
 *
 * timer 0 = servo PWM OC0A, OC0B 1-2ms pulse every 24 ms
 * timer 1 = audio sample, realtime clock 8000Hz
 * timer 2 = audio PWM clock -- running at 16MHz/255 = 62kHz pwm period
 *
 * 9=pb1 = pulled low to indicate occupancy...
 *
 * 11=pb3 = OC2A audio PWM high bit...
 * 13=pb5 = LED on arduino
 *
 * 15/A1=pc1 = flasher1-1 output...
 * 16/A2=pc2 = flasher1-2 output...
 * 17/A3=pc3 = gate1 led output
 * A4=pc4 = flasher2-1 output
 * A5=pc5 = flasher2-2 output
 *
 * 0=pd0 = serial input
 * 1=pd1 = serial output
 * 3=pd3 = OC2B audio PWM low bit...pin 11 for other side
 * 6=pd6 = OC0A servo1 pulse output .5 to 2.5ms every 24 ms
 * 5=pd5 = OC0B ... not working now
 * ?=ADC6 analog input // not used
 * 
 * when pb0 is pulled low, the servo starts moving the wigwag and the flashers and sound start.  
 * when pb0 goes high, the servo moves to the middle. Once the there, the flashers stop.
 *
 * Do not attempt to drive the servo beyond the physical limit.  
 * If the servo is buzzing, it means the servo is trying to move and will
 * overheat if left in that position for more than a few moments. 
 *
 */


// This header file is inside a folder in the library locaiton, 
//    example: [Drive:][User][Documents]\Arduino\libraries\WigWagSoundlibrary
// First time you put the file there, you need to restart the Arduino IDE.
// The file contains the sound data to output to the speaker:
//#define SOUNDLEN  const int pcm_length=16025; //WigWag8.8.wav
//#define SOUNDDATA const unsigned char pcm_samples[] PROGMEM = { 239,61,0,0,135,76,113,176,124,133,118,173,128,102,190,105,108,...

#include "WigWagSound.h"

// and then we use the #define MARCOs here
SOUNDLEN;
// and here. This is the easiest to include and external file and not deal with the "scope" problem.
SOUNDDATA;

// ============================

// inputs
const int PB01 = 9;

// flashers
// const int PC00 = 14;  // removed
const int PC01 = 15;
const int PC02 = 16;
const int PC03 = 17;
const int PC04 = 18;
const int PC05 = 19;

// servos
const int PD05 = 4; // lite1
const int PD06 = 6; // servo 1

// audio
const int PD03 = 3;
const int PB03 = 11;

// arduino
const int PB05 = 13;
const int ledPin = 13;

#define DEL 1000

#define PULLUPS digitalRead( PB01 ) | digitalRead( PB02 ) // ( 1 << PB1) | ( 1 << PB2 ) // pullups on pb1 and pb2

#define FLASHERH11 digitalWrite( PC01, HIGH );
#define FLASHERH12 digitalWrite( PC02, HIGH );

#define FLASHERH21 digitalWrite( PC04, HIGH );
#define FLASHERH22 digitalWrite( PC05, HIGH );

#define FLASHERL11 digitalWrite( PC01, LOW );
#define FLASHERL12 digitalWrite( PC02, LOW );

#define FLASHERL21 digitalWrite( PC04, LOW );
#define FLASHERL22 digitalWrite( PC05, LOW );

#define GATE1LEDH digitalWrite( PC03, HIGH );
//#define GATE2LEDH digitalWrite(PC00, HIGH);

#define GATE1LEDL digitalWrite( PC03, LOW );
//#define GATE2LEDL digitalWrite(PC00, LOW);

#define FLASHERH1 FLASHERH11; FLASHERH12;
#define FLASHERH2 FLASHERH21; FLASHERH22;

#define FLASHERL1 FLASHERL11; FLASHERL12;
#define FLASHERL2 FLASHERL21; FLASHERL22;

#define DOSERVOHI01 digitalWrite( PD06, HIGH );
#define DOLIGHTHI   digitalWrite( PD05, HIGH );
#define DOSERVOLO01 digitalWrite( PD06, LOW );
#define DOLIGHTLO   digitalWrite( PD05, LOW );

// can not use servo.h here, ISR and timers are set up to do the sound!!!
//
// see  http://arduino.cc/en/Tutorial/Knob
// #include <Servo.h> 
// Servo myservo;  // create servo object to control a servo in setup 
// myservo.attach(9);  // attaches the servo on pin 9 to the servo object

//#define SERVOBITSON PORTD |= SERVO1 | SERVO2
//#define SERVOBITSOFF PORTD &= ~( SERVO1 | SERVO2)
#define GATE1LEDOFF  GATE1LEDL;
#define GATE1LEDON   GATE1LEDH;
//#define GATE2LEDOFF  GATE2LEDL;
//#define GATE2LEDON   GATE2LEDH;

#define GATELEDL GATE1LEDOFF;/*GATE2LEDOFF;*/
#define GATELEDH GATE1LEDON;/*GATE2LEDON;*/

#define DIV1024CLOCK ( 1 << CS00) | ( 1 << CS02 )
#define CLOCKSTOP  0
#define DIV64CLOCK ( 1 << CS00) | ( 1 << CS01 )

/* minimum value for servo */
#define SERVOMIN 10
/* maximum value for servo */    
#define SERVOMAX 150
#define SERVOMID ( SERVOMAX - SERVOMIN ) / 2 + SERVOMIN

// PB01 pulled low by occupancy detector
#define OCCUPIED !digitalRead( PB01 )

volatile unsigned int tickcount;
volatile unsigned char fasttick;    // 8 ticks = 1 millisec
volatile unsigned int millisec;     // increments once per millisec
volatile unsigned int millisec2;    // increments once per millisec, we needed to reset to zero for the servo 
                                    // swinging more often than the rest of the system needed 
                    
volatile unsigned char servoticks;  // 192 ticks for each servo period
volatile unsigned char flashers;    // the gates need ligths, the wigwag not, but we kept the code
volatile unsigned char seconds;
volatile unsigned char servomoving; // 0 servo stopped, 1 servo moving
volatile uint16_t sample;           // pointer to current audio sample byte (max 65535) 
 
unsigned char servo1min;
unsigned char servo1max;
unsigned char firstTime;
unsigned char waitingForFirstTime;

unsigned char target;
unsigned char servodelay;

// realtime clock
// Timer1 compare A interrupt 16e6/2000 = interrupt 8000 times per sec ( .000125sec)
ISR( TIMER1_COMPA_vect) {
  // 8000 times a second update the audio pwm with the next sample
  // if the flashers are going or we are decaying after the last ding
  if ( flashers == 1 || sample != 0 ) {
    if ( firstTime == 0 )
      OCR2A = pgm_read_byte( &pcm_samples[sample++] );
    else
      sample++;     // if firstTime, don't load music, but still increase sample
      
    // following here is not my preferred way of writing code, but, since 
    // we had a bit of a time pressure on us, and we wanted to show that the
    // lamp does not simply turn on, but fade in a little bit, we added this, sorry.
    // we are using the position of the sound file, to turn the led on and off
    // so it is somewhat fading in. You could do the same with fading out,
    // just need to keep track of lastTime somehow.
    if ( firstTime == 1 ) {
      if ( sample == 1 ) 
         DOLIGHTHI 
      if ( sample == 100 ) 
         DOLIGHTLO 
      if ( sample == 150 ) 
        DOLIGHTHI 
      if ( sample == 350 ) 
        DOLIGHTLO   
      if ( sample == 400 ) 
         DOLIGHTHI 
      if ( sample == 700 ) 
         DOLIGHTLO 
      if ( sample == 750 ) 
        DOLIGHTHI 
      if ( sample == 1150 ) 
        DOLIGHTLO
      if ( sample == 1200 ) 
         DOLIGHTHI 
      if ( sample == 1700 ) 
         DOLIGHTLO 
      if ( sample == 1750 ) 
        DOLIGHTHI 
      if ( sample == 2350 ) 
        DOLIGHTLO   
      if ( sample == 2400 ) 
         DOLIGHTHI 
      if ( sample == 3100 ) 
         DOLIGHTLO 
      if ( sample == 3150 ) 
        DOLIGHTHI    
    } else {
      DOLIGHTHI
    } // if firstTime
    if ( sample == 200 ) 
      target = SERVOMAX;
    if ( sample == ( 200+8010 ) ) { 
      target = SERVOMIN;
    }
    if ( sample == 6012 ) {
      firstTime = 0;            // when we reach 6012, it is not firstTime any more
    }
    if ( sample > 16025 ) {     // Normal bell repeats every .36 seconds

      if ( flashers == 1 ) {	// if the bell is ringing, repeat back to the beginning.
        sample = 0;
      }	else if ( sample > pcm_length ) {  // at the last ding, let the bell decay as long as we have samples
        sample = 0;
      } // if sample	
    } // if 16025
  } else {
    if ( OCR2A > 0 ) OCR2A--;	// fade to zero to eliminate the click at the end.
    target = SERVOMID;
  } // if flashers

  if ( servomoving ) {
    // servo control sends pulses once every .024 seconds
    if ( ++servoticks >= 192 ) {
      // every 24 milliseconds start sending the servo pulse.
      // a servo pulse is between 1 and 2 milliseconds long.  We turn it on here
      // in 1 millisecond, we will start counter 0 to turn off the servo bits based on OCR0A and OCR0B
      // this gives us 255 possible servo positions
      DOSERVOHI01;
      //DOLIGHTHI; // this did not worl
      
      servoticks = 0; 	// reset the servo pulse counter
    } // 192
    // after the servo bits have been on for 1 millisecond, start timer 0 counting up.  When it
    // reaches the count specified in OCR0A and OCR0B we get an interrupt where we turn off the servo bit enough)
    if ( servoticks == 8 ) {
      // the servo bits have been on for 1 msec.  start timer0 to turn them off
      // start timer 0 running at 250khz
      // send an interrupt when the counter matches our servo postion
      TCNT0 = 0;
      TIFR0 = ( 1<<OCF0A) | ( 1<<OCF0B );         // clear any pending interrupts ( writing 1 to the bits clears them for whatever reaszon)
      TIMSK0 = ( 1 << OCIE0A ) | ( 1 << OCIE0B ); // enable the output compare interrupts
    } // if
  } // if servomoving

  // 8 fast ticks is 1 millisec
  // The millisec counter gets cleared by the delay subroutine,  all we do here is increment it.
  if ( fasttick++ >= 4 ) {
    millisec2++;
    if ((  millisec2 % 2 ) == 0 ) 
      millisec++;
    fasttick=0;
  } // if
  
  if ( millisec2 > servodelay ) {
    if ( firstTime == 1 ) {    // run the servo slower first time, since it only has to travel halfway from mid to max
      if ( OCR0A > target ) {
        OCR0A--;
      } // if >
      if ( OCR0A < target ) {
        OCR0A++; 
      } // if <
    } else {                  // rest of the time, double the speed, 2 times ++ or --, since we travel twice the distance
      if ( OCR0A > target ) {
        OCR0A--;      OCR0A--;  
      } // if >
      if ( OCR0A < target ) {
        OCR0A++;      OCR0A++;  
      } // if <
    } // if else firstTime
    millisec2 = 0;
  } // if
  
  // 4000 ticks = half a second
  if ( tickcount++ >= 4000 ) {
    //PORTB=( PORTB ^ FLASHER2) | PULLUPS;
    seconds++;              // actually counts half seconds

    tickcount = 0;
    
    // don't need to do this, wigwag is not flashing
    if ( flashers == 1 ) {  // alternating flasher1, flasher2
      GATELEDH;
      if ( seconds & 1 ) {
        FLASHERH1;
        FLASHERL2;
      } else {
        FLASHERL1;
        FLASHERH2;
      }	// if seconds
    } else {
      FLASHERL1;
      FLASHERL2;
      GATELEDL;
    } // if seconds
  } // if 4000// ISR

/*
// timer0 OVERFLOW -- not used 
//ISR( TIMER0_OVF_vect) {
//TCCR0B= CLOCKSTOP;	// stop timer 0. we will restart it in 24msec using timer1
//PORTB &= ~( 1<<PB5 );
//}
*/

// timer 0 compare A -- turn off servo bit 1 at the end of the pulse
ISR( TIMER0_COMPA_vect ) {
  DOSERVOLO01                  // make sure servo bit is off
  TIMSK0 &= ~( 1<<OCIE0A );    // disable compare A interrupt// ISR


// timer 0 compare B -- turn off servo bit 2 at the end of the pulse
// (Servo2 is not used here, and neither did this seem to dim or bright the lamp, so we cheated up above instead)
ISR( TIMER0_COMPB_vect ) {
//  DOLIGHTLO;       // make sure servo bit is off
  TIMSK0 &= ~( 1 << OCIE0B );  // disable compare B interrupt// ISR


// deelay -- stop processing for N milliseconds.
void deelay( unsigned int ticks ) {
  // set the millisecond tick timer to zero.  Interrupts will increment this for us
  // at .001 seconds per tick.
  millisec = 0;
  while( millisec < ticks ) {};
} // deelay


// toggle the arduino LED once per period mask secconds (not sure if this is still ture, i.e. not tested! (GM)
//   1 = once per second gates moving
//   2 = once per 2 seconds occupied
//   4 = once every 4 seconds vacant
void flashled( unsigned char period ) {
  if ( seconds & period ) {
    digitalWrite( ledPin, HIGH );
  } else {
    digitalWrite( ledPin, LOW );
  } // if seconds// flashled


// startMoving -- yep, let's go
void startMoving() {
  flashled( 1 );           // while moving the gates flash the arduino LED once per second
  servomoving = 1;         // turn on the servo// startMoving

// moveto -- move the servos to the given target
void moveto( unsigned char target1 ) { 
  // we are swinging, so no moving here!// moveto


// given a bit on port C, turn on that LED for half a second
void testit( unsigned char thePin ) {
  return;
  digitalWrite( thePin, HIGH );
  deelay( DEL );
  digitalWrite( thePin, LOW );
  deelay( DEL );
  digitalWrite( thePin, HIGH );
} // testit


/* initialise everything */
void init_pins( void ) {
  // set up the data direction registers
  pinMode( PB01, INPUT_PULLUP );

  pinMode( PC01, OUTPUT );
  pinMode( PC02, OUTPUT );
  pinMode( PC03, OUTPUT );
  pinMode( PC04, OUTPUT );
  pinMode( PC05, OUTPUT );
 
  pinMode( PD03, OUTPUT ); // audioL
  pinMode( PB03, OUTPUT ); // audioH

  pinMode( PD05, OUTPUT ); // servo02
  pinMode( PD06, OUTPUT ); // servo01
  
  pinMode( ledPin, OUTPUT );
 
  flashers = 0;

  servo1max = SERVOMAX;
  servo1min = SERVOMIN;
  
  if ( servodelay == 0 ) {
    servodelay = 1;
  } // if servodelay

  // set up timer 0 servo pulse timer
  // a servo pulse is 1 millisecond for 0 degrees and 2 milliseconds for 90 degrees.
  // the pulses are every 24 milliseconds.  The servo pulse  is started every 24 milliseconds
  // by the realtime clock ( timer1).  Timer 0 compare match A and B are used to
  // set the length of the pulses
  TCCR0A = 0;            // normal mode
  TCCR0B = DIV64CLOCK;   // 250kHz
  OCR0A = SERVOMID;     // start with the wigwag in the middle
  OCR0B = 0; //SERVOMID;     // start with the wigwag in the middle

  // set up the timer1 to provide the main realtime clock of 8000 ticks per second
  TCCR1A = 0;		// Normal operation
  TCCR1B = ( 1<<WGM12 ) | ( 1 << CS10 );	// OCR1A CTC mode, divide by 1 clock ( 16mhz)
  OCR1A = 2000;	// upper limit of counter, generate 8000 overflow interrupts per second
  TIMSK1 = ( 1 << OCIE1A );	// interrupt on output compare A

/*
    // set up the analog to digital converter
  ADMUX = ( 1<<ADLAR )       // left adjust to get the high 8 bits ( just read ADCH
    | ( 1 << REFS0 )         // 5 volt reference
      | 6;                   // ADC6 input  ( actually mux1 | mux2)

  ADCSRA = ( 1 << ADEN )     // Enable A/D conversion
    | ( 1 << ADSC)           // start the conversion
      | ( 1 << ADATE)        // enable auto conversion ( free running)
        | ( 1<<ADPS2) | ( 1<<ADPS0 ); // /32 Prescale
*/
  // set up timer 2 for AUDIO pwm generation
  // clear OC0A on compare match 
  // set OC0A at BOTTOM, non-inverting mode
  // Fast PWM, 8bit
  TCCR2A = ( 1<<COM2A1 ) | ( 1<<WGM21 ) | ( 1<<WGM20 );
  // Fast PWM, 8bit
  // Prescaler: clk/1 = 16MHz
  // PWM frequency = 16MHz / ( 255 + 1) = 62.5kHz
  TCCR2B =  ( 1<<CS20 );
  // set initial duty cycle to zero */
  OCR2A = 0;
  
  sei( );                    // Enable interrupts
  //deelay( 1000 );          // pause for a bit at startup to allow the ADC to rise above 0
  //..target = SERVOMID;// init_pins

void setup( ) {   init_pins( );      servodelay = 25;   // on startup flash each led once   servomoving = 1;           // force gates to the top while LEDs are flashing   testit( PC01 );   testit( PC02 );   testit( PC03 );   firstTime = 0;   waitingForFirstTime = 1; } // setup void loop( ) {   flashled( 4 );        // toggle the led while we are waiting   // if we have occupancy, lets roll   if ( OCCUPIED ) {     if ( waitingForFirstTime == 1 ) {       firstTime = 1;       waitingForFirstTime = 0;           } // if waitingForFirstTime     flashers = 1;     delay( 2000 ); // delay for 2 seconds after starting flashers     startMoving( );     while( OCCUPIED ) {       flashled( 2 );     } // while   } else { // unoccupied     delay( 1000 ); // don't want to turn off immediately, debouncing     if ( OCCUPIED ) {       // keep running     } else {       delay( 500 ); // don't want to turn off immediately, debouncing       if ( OCCUPIED ) {         // keep running       } else {         waitingForFirstTime = 1;               DOLIGHTLO;      // turn light off         // turn off flashers         flashers = 0;         deelay( 1000 ); //.       } // if OCCUPIED     } // if OCCUPIED   } // if OCCUPIED// loop
ċ
Arduino_Crossing_Gate_controller_WigWag.ino
(16k)
Gert (TxAdmin) Muller,
Aug 6, 2015, 11:42 AM
Comments