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; // ============================// inputsconst int PB01 = 9; // flashers// const int PC00 = 14; // removedconst int PC01 = 15; const int PC02 = 16; const int PC03 = 17; const int PC04 = 18; const int PC05 = 19; // servosconst int PD05 = 4; // lite1const int PD06 = 6; // servo 1// audioconst int PD03 = 3; const int PB03 = 11; // arduinoconst 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 vacantvoid flashled( unsigned char period ) { if ( seconds & period ) { digitalWrite( ledPin, HIGH ); } else { digitalWrite( ledPin, LOW ); } // if seconds } // flashled// startMoving -- yep, let's govoid 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 targetvoid 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 secondvoid 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; } // setupvoid 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