Or "Yet Another Arduino Blinken Light Thing" :)
So we were chatting on the TASLUG (Tasmanian Linux Users Group) mailing list talking about a new hackerspace development and whatnot when one of the fellows said he hoped that it didn't become a club of Arduino fanboys. I said what's up with Arduino, it's awesome, and he said there's far too much boring blinkenlights and not enough actual cool stuff. It was a bit tongue in cheek, but regardless, my nerd pride was offended and I managed to interpret it as a challenge :) A month or so later and I had created TINY:
I'm pretty sure nerd etiquette precludes me from proclaiming success, but it did have an awesome time doing it. I am curious though, what do you think? ;)
/*
Space Invaders
Turns on an LED on for one second, then off for one second, repeatedly.
This example code is in the public domain.
*/
// pin assignments
int annodes0 = 2;int annodes1 = 3;int annodes2 = 4;int annodes3 = 5;int annodes4 = 6;
//pin 7 is spare
int cathodes0 = 8;int cathodes1 = 9;int cathodes2 = 10;int cathodes3 = 11;int cathodes4 = 12;
int IndicatorLED = 13;
int InputPot = A0;
int C_ButtonPin = 18; //ie analog4, in use as a digital pin
int C_SpeakerPin = 19; //ie analog5, in use as a digital pin
int mycursor=2; // set initial position of the cursor
//int difficulty = 1; // where 1 is easy and 3 is hard.
// the setup routine runs once when you press reset:
void setup() {
// initialize the pins
pinMode(annodes0, OUTPUT); pinMode(annodes1, OUTPUT); pinMode(annodes2, OUTPUT); pinMode(annodes3, OUTPUT); pinMode(annodes4, OUTPUT);
pinMode(cathodes0, OUTPUT); pinMode(cathodes1, OUTPUT); pinMode(cathodes2, OUTPUT); pinMode(cathodes3, OUTPUT); pinMode(cathodes4, OUTPUT);
pinMode(IndicatorLED, OUTPUT);
pinMode(C_ButtonPin, INPUT); pinMode(InputPot, INPUT);
Serial.begin(9600);
}
void loop() {
//basicMultiplexing();
//SoundEffectGenViaPot();
//MakeASmiley();
//lightled(6,2000); delay(2000);
//int buttonState = digitalRead(C_ButtonPin); if (buttonState == HIGH) { sound(7); }
int difficulty = introSequence(); delay(200);
SnotVaders(difficulty); delay(200);
MakeASmiley(); delay(1000);
}
int introSequence(){
int difficultyX = SimpleVelocityLoop();
//int difficulty = map(difficultyX, 0, 1023, 3, 1);
int difficulty = 0;
if (difficultyX < 315) { difficulty = 3; }
else if (difficultyX > 648 ) { difficulty = 1; }
else { difficulty = 2; }
Serial.print("difficultyX = "); Serial.println(difficultyX);
Serial.print("difficulty = "); Serial.println(difficulty);
delay(200);
int mydelay=10;
for (int i = 1; i <= 25; i++) {
sound(1);
lightled(i,mydelay); delay(mydelay);
lightled(25-i,mydelay); delay(mydelay);
}
sound(7);
delay(400);
return difficulty;
}
void SnotVaders(int difficulty){
// (number of displaycycles per tick will be determined by gameroundtickspeed[v_round].
// the number of rounds is determined by the length of gameroundtickspeed[].
// we determine the ticks per round based on the difficulty :)
int gameroundtickspeed[]= {0,0,0,0,0,0,0,0,0};
switch (difficulty){
case 1: // easy
{ int gameroundtickspeedX[]= {28,22,23,20,21,17,17,17,17}; for (int z = 0; z < 9; z++) { gameroundtickspeed[z]=gameroundtickspeedX[z];} break; }
case 2: // medium
{ int gameroundtickspeedX[]= {20,20,20,19,18,14,14,14,11}; for (int z = 0; z < 9; z++) { gameroundtickspeed[z]=gameroundtickspeedX[z];} break; }
case 3: // hard
{ int gameroundtickspeedX[]= {7,7,7,7,7,7,7,7,7}; for (int z = 0; z < 9; z++) { gameroundtickspeed[z]=gameroundtickspeedX[z];} break; }
}
int rounds = sizeof(gameroundtickspeed)/sizeof(int);
int shipLocation=1; int notdead=1; int idealFlikerRate=24;
int buttonStateToggle = 1; int baddieDetails[] = {0,0,0,0,0};
// play successive rounds, each terminating when either all baddies or the player dies
for (int round = 1; round <= rounds; round++){
// output the round to the serial console for debug
//Serial.print(" round = "); Serial.println(round);
// baddies move closer to the player each round.
// and they will do that faster depending on the round number.
// if they hit the player, then the player dies, game over etc.
// we define baddie starting location based on the round.
// note that locations < 1 is "no location" and wont be displayed at all.
// i was unable to have the switch populate baddieDetails[] directly, so that's why
// we have this odd baddieDetails[z]=locations[z] arrangement.
switch (round) {
case 1: {
int locations[]= {15, -1, -1, -1, -1}; for (int z = 0; z <= 5; z++) { baddieDetails[z]=locations[z];} } break;
case 2: {
int locations[]= {5, 25, -1, -1, -1}; for (int z = 0; z <= 5; z++) { baddieDetails[z]=locations[z];} } break;
case 3: {
int locations[]= {5, 14, 25, -1, -1}; for (int z = 0; z <= 5; z++) { baddieDetails[z]=locations[z];} } break;
case 4: {
int locations[]= {4, 15, 24, -1, -1}; for (int z = 0; z <= 5; z++) { baddieDetails[z]=locations[z];} } break;
case 5: {
int locations[]= {4, 10, 15, 20, 24}; for (int z = 0; z <= 5; z++) { baddieDetails[z]=locations[z];} } break;
case 6: {
int locations[]= {3, 9, 15, 19, 23}; for (int z = 0; z <= 5; z++) { baddieDetails[z]=locations[z];} } break;
case 7: {
int locations[]= {4, 8, 15, 18, 24}; for (int z = 0; z <= 5; z++) { baddieDetails[z]=locations[z];} } break;
case 8: {
int locations[]= {3, 8, 15, 18, 23}; for (int z = 0; z <= 5; z++) { baddieDetails[z]=locations[z];} } break;
} int baddieDetailsarraylen = sizeof(baddieDetails)/sizeof(int);
while(notdead) {
// grunt noise
sound(1);
// update the display X times to do the flicker thing
for (int displaycycle = 1; displaycycle <= gameroundtickspeed[round-1]; displaycycle++) {
// we plot LEDs once per displaycycle. we do that repeatedly to give us a picture.
// (number of displaycycles per tick will be determined by gameroundtickspeed[v_round]
// each plotXX() function will illuminate and also extinguish it's own LEDs
// we want this to minimise the number of simultaneously lit leds; ie flicker.)
// first plot the baddies based on baddieDetails[] and check to see if they're all dead
notdead = PlotBaddiesAndDetectAllDead(baddieDetails, baddieDetailsarraylen, idealFlikerRate);
if (notdead == 0) { break; } //terminate processing the while loop
// check to see if any of the baddies have hit the ground, if so terminate the game.
int Zinstruction[] = {1, 6, 11, 16, 21};
for(int z = 0; z < baddieDetailsarraylen; z++) {
for(int q = 0; q < 5; q++){
if (baddieDetails[z] == Zinstruction[q]){
// then a baddie has hit the ground, play wah wah wahhh and end
sound(5); delay (500); software_Reset();
} } }
// check to see if the player is shooting and if so, plot the laser and return the path it took.
// the toggle stuff is to make sure they're not just holding the fire button
int buttonState = digitalRead(C_ButtonPin);
if (buttonState == HIGH) {
if (buttonStateToggle) {
PlotShootAndDetectHit(baddieDetails, baddieDetailsarraylen, shipLocation);
buttonStateToggle = 0;
}
} else { buttonStateToggle = 1; }
// move ship and return our current location
shipLocation=PlotAndControlShipV2(idealFlikerRate); //ie; PlotAndControlShip(delay)
// output debug stuff
//Serial.print(" dc = "); Serial.print(displaycycle);
//Serial.print(" rounds = "); Serial.print(rounds);
//Serial.print(" round = "); Serial.println(round);
//Serial.print(" shipLocation = "); Serial.println(shipLocation);
} // end of displaycycle
// make the baddies move closer to the player
for(int z = 0; z < baddieDetailsarraylen; z++) {
baddieDetails[z]--;
Serial.print(" baddieDetails["); Serial.print(z); Serial.print("] "); Serial.println( baddieDetails[z]);
}
//}
} // end of roundlengthcounter, ie end of round
delay(500); sound(4); delay(1000); //delay between rounds
notdead = 1;
} // end of round, ie end of the game.
sound(6); // play endgame music
}
void software_Reset() {
// Restarts program from beginning but does not reset the peripherals and registers
// taken from http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1246541553
asm volatile (" jmp 0");
}
void MakeASmiley(){
int instructions[]= {9, 19, 2, 6, 11, 16, 22};
//int instructions[]= {10, 20, 14, 22, 21, 16, 11, 6, 1, 2}; //froggy
int instructionsArraylen = sizeof(instructions)/sizeof(int);
for (int i = 0; i < instructionsArraylen; i++){
lightled(instructions[i],350);
}
delay(200);
for (int flickercounter = 0; flickercounter < 1008 ; flickercounter ++) {
// iterate through the array, starting at element 0
for (int i = 0; i < instructionsArraylen; i++){
lightled(instructions[i],1);
//delay(100);
}
}
delay(1000);
}
int PlotBaddiesAndDetectAllDead(int baddieDetails[], int baddieDetailsarraylen, int mydelay){
int deadBaddieCounter=0;
// note the last element in the array is arraylen -1.
int lastarrayelement = baddieDetailsarraylen - 1;
// iterate through the array, starting at element 1, not 0. and while we're at it
// we'll calculate the score too
int score = 0;
for (int i = 0; i < baddieDetailsarraylen; i++){
// blink the leds according to the baddieDetails
if (baddieDetails[i] < 0){ // this is a dead baddie, so don't plot it. instead count it.
deadBaddieCounter++;
if (deadBaddieCounter == baddieDetailsarraylen) { // all baddies are dead
score = score + baddieDetails[i]; score = score * -1; score = 5 - score;
Serial.print(" score = "); Serial.println( score);
return 0;
}
} else {
lightled(baddieDetails[i],mydelay);
}
}
}
void PlotShootAndDetectHit(int baddieDetails[], int baddieDetailsarraylen, int shipLocation){
//note this assumes that the ship won't leave the planet surface and that the
//planet surface is defined explicityly as 1, 6, 11, 16, 21. if that changes
//then this will look odd.
int shootdelay = 12;
// to start with, simply play the shoot noise
sound(2); //shoot
// then take the ship location, and for each one, calculate the laser trajectory
// each led upon that trajectory is called laserLocation. when we have that laserLocation
// also iterate through the baddieDetails array to see if that laserLocation coincides with
// where a baddie is, if so, play the explode noise.
switch(shipLocation){ // this will send the laser towards the baddies :)
case 1:
for(int laserLocation=2; laserLocation <=5; laserLocation++){ // plot the laser trajectory
lightled(laserLocation,shootdelay); // plot the led(note singular) corresponding to the laserLocation
for (int blc = 0; blc < baddieDetailsarraylen; blc ++){
if (laserLocation == baddieDetails[blc]) { // if the laser is where a baddie is
sound(3); // they hit the target!! so play the explode noise
baddieDetails[blc]=-1; // set that baddie to dead; ie don't display it
} } }
break;
case 6:
for(int laserLocation=7; laserLocation <=10; laserLocation++){
lightled(laserLocation,shootdelay); // plot the led(note singular) corresponding to the laserLocation
for (int blc = 0; blc < baddieDetailsarraylen; blc ++){
if (laserLocation == baddieDetails[blc]) { // if the laser is where a baddie is
sound(3); // they hit the target!! so play the explode noise
baddieDetails[blc]=-1; // set that baddie to dead; ie don't display it
} } }
break;
case 11:
for(int laserLocation=12; laserLocation <=15; laserLocation++){
lightled(laserLocation,shootdelay); // plot the led(note singular) corresponding to the laserLocation
for (int blc = 0; blc < baddieDetailsarraylen; blc ++){
if (laserLocation == baddieDetails[blc]) { // if the laser is where a baddie is
sound(3); // they hit the target!! so play the explode noise
baddieDetails[blc]=-1; // set that baddie to dead; ie don't display it
} } }
break;
case 16:
for(int laserLocation=17; laserLocation <=20; laserLocation++){
lightled(laserLocation,shootdelay); // plot the led(note singular) corresponding to the laserLocation
for (int blc = 0; blc < baddieDetailsarraylen; blc ++){
if (laserLocation == baddieDetails[blc]) { // if the laser is where a baddie is
sound(3); // they hit the target!! so play the explode noise
baddieDetails[blc]=-1; // set that baddie to dead; ie don't display it
} } }
break;
case 21:
for(int laserLocation=22; laserLocation <=25; laserLocation++){
lightled(laserLocation,shootdelay); // plot the led(note singular) corresponding to the laserLocation
for (int blc = 0; blc < baddieDetailsarraylen; blc ++){
if (laserLocation == baddieDetails[blc]) { // if the laser is where a baddie is
sound(3); // they hit the target!! so play the explode noise
baddieDetails[blc]=-1; // set that baddie to dead; ie don't display it
} } }
break;
}
}
int PlotAndControlShipV2(int mydelay){
// planet surface
int instruction[] = {1, 6, 11, 16, 21};
// mycursor is a globally declared variable which stores where in the *instruction array* the ship
// is currently residing. it should not be confused with shipLocation which stores the LEDid of the
// ship location. ie shipLocation = instruction[mycursor]
int rawLocation = analogRead(InputPot); int location = map(rawLocation, 0, 1025, 0, 5);
//Serial.print("rawLocation = "); Serial.print(rawLocation); Serial.print(" location = "); Serial.println(location);
lightled(instruction[location],mydelay);
return instruction[location];
}
void sound(int soundeffect) {
switch( soundeffect ) {
case 1: {//grunt
tone(C_SpeakerPin, 17, 250);
} break;
case 2: {//shoot
for (int z = 0; z < 1; z++){
tone(C_SpeakerPin, 600, 80); delay(40);
tone(C_SpeakerPin, 100, 40); delay(10);
}
} break;
case 3: {//explode
//basically random-ish noise descending in frequency
int freqbase=480; // where to start
for(int i=0; i < 15; i++){ // how many individual noises in the effect
freqbase = freqbase - 20; // how much lower should each noise go?
int frequency = random(freqbase-30,freqbase); //what exact freqency to plot
int mydelay = random(30,150); // how long should each noise go for
tone(C_SpeakerPin, frequency, mydelay);
Serial.print("frequency = "); Serial.print(frequency); Serial.print(" mydelay = "); Serial.println(mydelay);
}
} break;
case 4: {// end round
tone(C_SpeakerPin, 300, 300);delay(150);
tone(C_SpeakerPin, 600, 100);delay(300);
tone(C_SpeakerPin, 300, 300);delay(150);
tone(C_SpeakerPin, 600, 800);delay(300);
} break;
case 5: {//you loose
for (int z = 0; z < 1; z++){
tone(C_SpeakerPin, 300, 80); delay(800);
tone(C_SpeakerPin, 275, 80); delay(800);
tone(C_SpeakerPin, 260, 80); delay(800);
for (int i = 0; i < 30; i++) {
tone(C_SpeakerPin, 245, 15); delay(15);
tone(C_SpeakerPin, 255, 15); delay(15);
}
tone(C_SpeakerPin, 100, 40); delay(10);
}
} break;
case 6: {//you win!
// the song to play at the truimphant conclusion :)
char *song = "20thCenFoxShort:d=16,o=5,b=140:b,8p,b,b,2b,p,c6,32p,b,32p,c6,32p,b,32p,c6,32p,b,8p,b,b,b,32p,b,32p,b,32p,b,32p,b,32p,b,32p,b,32p,g#,32p,a,32p,b,8p,b,b,2b,4p";
play_rtttl(song);
} break;
case 7: {// game start
//basically random-ish noise ascending in frequency
int freqbase=180; // where to start
for(int i=0; i < 30; i++){ // how many individual noises in the effect
freqbase = freqbase + 15; // how much lower should each noise go?
int frequency = random(freqbase-30,freqbase); //what exact freqency to plot
int mydelay = random(30,150); // how long should each noise go for
tone(C_SpeakerPin, frequency, mydelay);
Serial.print("frequency = "); Serial.print(frequency); Serial.print(" mydelay = "); Serial.println(mydelay);
}
tone(C_SpeakerPin, 100, 15); delay(250);
for (int i = 0; i < 2; i++) {
for (int i = 0; i < 4; i++) {
tone(C_SpeakerPin, 690, 100); delay(20);
tone(C_SpeakerPin, 640, 100); delay(20);
}
tone(C_SpeakerPin, 100, 15); delay(100);
}
} break;
}
}
void lightled(int LEDid, int ondelay) {
//Serial.print(" led = "); Serial.print(LEDid); Serial.print(" ondelay = "); Serial.println(ondelay);
switch (LEDid) {
case 0:
//all off
digitalWrite(cathodes0, LOW); digitalWrite(annodes0, LOW); digitalWrite(cathodes1, LOW); digitalWrite(annodes1, LOW);
digitalWrite(cathodes2, LOW); digitalWrite(annodes2, LOW); digitalWrite(cathodes3, LOW); digitalWrite(annodes3, LOW);
digitalWrite(cathodes4, LOW); digitalWrite(annodes4, LOW); break;
case 1: //c0a0
digitalWrite(cathodes0, HIGH); digitalWrite(annodes0, HIGH); break;
case 2: //c0a1
digitalWrite(cathodes0, HIGH); digitalWrite(annodes1, HIGH); break;
case 3: //c0a2
digitalWrite(cathodes0, HIGH); digitalWrite(annodes2, HIGH); break;
case 4: //c0a3
digitalWrite(cathodes0, HIGH); digitalWrite(annodes3, HIGH); break;
case 5: //c0a4
digitalWrite(cathodes0, HIGH); digitalWrite(annodes4, HIGH); break;
case 6: //c1a0
digitalWrite(cathodes1, HIGH); digitalWrite(annodes0, HIGH); break;
case 7: //c1a1
digitalWrite(cathodes1, HIGH); digitalWrite(annodes1, HIGH); break;
case 8: //c1a2
digitalWrite(cathodes1, HIGH); digitalWrite(annodes2, HIGH); break;
case 9: //c1a3
digitalWrite(cathodes1, HIGH); digitalWrite(annodes3, HIGH); break;
case 10: //c1a4
digitalWrite(cathodes1, HIGH); digitalWrite(annodes4, HIGH); break;
case 11: //c2a0
digitalWrite(cathodes2, HIGH); digitalWrite(annodes0, HIGH); break;
case 12: //c2a1
digitalWrite(cathodes2, HIGH); digitalWrite(annodes1, HIGH); break;
case 13: //c2a2
digitalWrite(cathodes2, HIGH); digitalWrite(annodes2, HIGH); break;
case 14: //c2a3
digitalWrite(cathodes2, HIGH); digitalWrite(annodes3, HIGH); break;
case 15: //c2a4
digitalWrite(cathodes2, HIGH); digitalWrite(annodes4, HIGH); break;
case 16: //c3a0
digitalWrite(cathodes3, HIGH); digitalWrite(annodes0, HIGH); break;
case 17: //c3a1
digitalWrite(cathodes3, HIGH); digitalWrite(annodes1, HIGH); break;
case 18: //c3a2
digitalWrite(cathodes3, HIGH); digitalWrite(annodes2, HIGH); break;
case 19: //c3a3
digitalWrite(cathodes3, HIGH); digitalWrite(annodes3, HIGH); break;
case 20: //c3a4
digitalWrite(cathodes3, HIGH); digitalWrite(annodes4, HIGH); break;
case 21: //c4a0
digitalWrite(cathodes4, HIGH); digitalWrite(annodes0, HIGH); break;
case 22: //c4a1
digitalWrite(cathodes4, HIGH); digitalWrite(annodes1, HIGH); break;
case 23: //c4a2
digitalWrite(cathodes4, HIGH); digitalWrite(annodes2, HIGH); break;
case 24: //c4a3
digitalWrite(cathodes4, HIGH); digitalWrite(annodes3, HIGH); break;
case 25: //c4a3
digitalWrite(cathodes4, HIGH); digitalWrite(annodes4, HIGH); break;
case 88: //do nothing.
break;
case 100:
//all on
digitalWrite(cathodes0, HIGH); digitalWrite(annodes0, HIGH); digitalWrite(cathodes1, HIGH); digitalWrite(annodes1, HIGH);
digitalWrite(cathodes2, HIGH); digitalWrite(annodes2, HIGH); digitalWrite(cathodes3, HIGH); digitalWrite(annodes3, HIGH);
digitalWrite(cathodes4, HIGH); digitalWrite(annodes4, HIGH);
break;
default: // if nothing else matches, do the default
//Serial.print("ERROR LEDid = "); Serial.println(LEDid); alloff(); allon(); delay(1500);
break;
}
//delay a sec before resuming
delay(ondelay); alloff();
}
void alloff(){
// turn everything off for contrast
digitalWrite(cathodes0, LOW); digitalWrite(cathodes1, LOW); digitalWrite(cathodes2, LOW); digitalWrite(cathodes3, LOW); digitalWrite(cathodes4, LOW);
digitalWrite(annodes0, LOW); digitalWrite(annodes1, LOW); digitalWrite(annodes2, LOW); digitalWrite(annodes3, LOW); digitalWrite(annodes4, LOW);
digitalWrite(IndicatorLED, LOW);
}
void allon(){
// turn everything off for contrast
digitalWrite(cathodes0, HIGH); digitalWrite(cathodes1, HIGH); digitalWrite(cathodes2, HIGH); digitalWrite(cathodes3, HIGH); digitalWrite(cathodes4, HIGH);
digitalWrite(annodes0, HIGH); digitalWrite(annodes1, HIGH); digitalWrite(annodes2, HIGH); digitalWrite(annodes3, HIGH); digitalWrite(annodes4, HIGH);
digitalWrite(IndicatorLED, HIGH);
}
void SoundEffectGenViaPot(){
//generate sounds using input pot
int buttonState = digitalRead(C_ButtonPin);
int frequencyX = analogRead(InputPot); int frequency = map(frequencyX, 0, 1023, 1, 6000);
if (buttonState == HIGH) {
//tone(C_SpeakerPin, frequency, 200);
tone(C_SpeakerPin, frequency, 40); //delay(10);
tone(C_SpeakerPin, frequency-200, 40); //delay(10);
tone(C_SpeakerPin, frequency, 40); //delay(10);
//tone(C_SpeakerPin, 100, 40); delay(5);
}
Serial.print("frequency = "); Serial.println(frequency);
}
void basicMultiplexing(){
// for our matrix 24 is a good delay, but more leds means more flicker. simple.
int ondelayX = analogRead(InputPot); int ondelay = map(ondelayX, 0, 1023, 0, 100);
for (int i = 1; i <= 25; i++){lightled(i,ondelay);}
Serial.print("ondelay = "); Serial.println(ondelay);
}
int PlotAndControlShipVelocity(int mydelay){
// planet surface
int instruction[] = {1, 6, 11, 16, 21};
// mycursor is a globally declared variable which stores where in the *instruction array* the ship
// is currently residing. it should not be confused with shipLocation which stores the LEDid of the
// ship location. ie shipLocation = instruction[mycursor]
// note the last element in the array is arraylen -1 !!!!
int arraylen = sizeof(instruction)/sizeof(int); int lastarrayelement = arraylen - 1;
// determine the position of the pot and assign a velocity to it
int velocityX= analogRead(InputPot); int velocity = map(velocityX, 0, 1023, -150, 150);
// set the cursor to increment or decrement depending on the velocity, note the deadzone
if (velocity > 15) { mycursor++;}
if (velocity < -15) {mycursor--;}
// what do we do when they reach the edge of the play area? to wrap or not to wrap?
// wrap:
// if (mycursor < 0) { mycursor = lastarrayelement; } if (mycursor > lastarrayelement) { mycursor = 0; }
// not wrap:
if (mycursor < 0) { mycursor = 0; } if (mycursor > lastarrayelement) { mycursor = lastarrayelement; }
//Serial.print("mycursor = "); Serial.print(mycursor); Serial.print(" mydelay = "); Serial.print(mydelay); Serial.print(" velocity = "); Serial.print(velocity);
// blink the leds according to the instructions
lightled(instruction[mycursor],mydelay);
//ie shipLocation = instruction[mycursor]
return instruction[mycursor];
}
int SimpleVelocityLoop(){
// define the instructions for the array and the delay for led illumination
//int instruction[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,0,100,0,100}; //test
//int instruction[] = {1, 6, 11, 16, 21, 22, 23, 24, 25, 20, 15, 10, 5, 4, 3, 2, 7, 12, 17, 18, 19, 14, 9, 8, 13, 7}; // spiral and exit
int instruction[] = {1, 6, 11, 16, 21, 22, 23, 24, 25, 20, 15, 10, 5, 4, 3, 2}; // outside loop
//int instruction[] = {1, 6, 7, 11, 16, 12, 21, 22, 17, 23, 24, 18, 25, 20, 19, 15, 10, 14, 5, 4, 9, 3, 2, 8}; // 2 square loop
// and then simply iterate through the instruction array
int i; int arraylen = sizeof(instruction)/sizeof(int);
int mydelayX = 0;
int buttonState = 0;
while(buttonState != HIGH){
for (i = 0; i < arraylen; i = i + 1) {
buttonState = digitalRead(C_ButtonPin); if (buttonState) { break; }
// delay is used for setting both the ON and OFF durations
mydelayX= analogRead(InputPot); int mydelay = map(mydelayX, 0, 1023, 4, 200);
// blink the leds according to the instructions
// sound(1);
lightled(instruction[i],mydelay);
// turn everything off and wait a sec (before re-reading the instructinos and starting again etc)
alloff(); delay(mydelay/2);
//Serial.print("mydelayX = "); Serial.print(mydelayX);
}
}
return mydelayX;
}
void play_rtttl(char *p) {
// this function based on the LCA 2012 leo stick tunes collaborative effort at https://gist.github.com/1800871
//char *song = "Muppets:d=4,o=5,b=250:c6,c6,a,b,8a,b,g,p,c6,c6,a,8b,8a,8p,g.,p,e,e,g,f,8e,f,8c6,8c,8d,e,8e,8e,8p,8e,g,2p,c6,c6,a,b,8a,b,g,p,c6,c6,a,8b,a,g.,p,e,e,g,f,8e,f,8c6,8c,8d,e,8e,d,8d,c";
//char *song = "Looney:d=4,o=5,b=140:32p,c6,8f6,8e6,8d6,8c6,a.,8c6,8f6,8e6,8d6,8d#6,e.6,8e6,8e6,8c6,8d6,8c6,8e6,8c6,8d6,8a,8c6,8g,8a#,8a,8f";
//char *song = "20thCenFox:d=16,o=5,b=140:b,8p,b,b,2b,p,c6,32p,b,32p,c6,32p,b,32p,c6,32p,b,8p,b,b,b,32p,b,32p,b,32p,b,32p,b,32p,b,32p,b,32p,g#,32p,a,32p,b,8p,b,b,2b,4p,8e,8g#,8b,1c#6,8f#,8a,8c#6,1e6,8a,8c#6,8e6,1e6,8b,8g#,8a,2b";
//char *song = "Canon:d=4,o=5,b=80:8d,8f#,8a,8d6,8c#,8e,8a,8c#6,8d,8f#,8b,8d6,8a,8c#,8f#,8a,8b,8d,8g,8b,8a,8d,8f#,8a,8b,8f#,8g,8b,8c#,8e,8a,8c#6,f#6,8f#,8a,e6,8e,8a,d6,8f#,8a,c#6,8c#,8e,b,8d,8g,a,8f#,8d,b,8d,8g,c#.6";
//char *song = "StarWars:d=4,o=5,b=45:32p,32f#,32f#,32f#,8b.,8f#.6,32e6,32d#6,32c#6,8b.6,16f#.6,32e6,32d#6,32c#6,8b.6,16f#.6,32e6,32d#6,32e6,8c#.6,32f#,32f#,32f#,8b.,8f#.6,32e6,32d#6,32c#6,8b.6,16f#.6,32e6,32d#6,32c#6,8b.6,16f#.6,32e6,32d#6,32e6,8c#6";
//char *song = "Gadget:d=16,o=5,b=50:32d#,32f,32f#,32g#,a#,f#,a,f,g#,f#,32d#,32f,32f#,32g#,a#,d#6,4d6,32d#,32f,32f#,32g#,a#,f#,a,f,g#,f#,8d#";
//char *song = "Smurfs:d=32,o=5,b=200:4c#6,16p,4f#6,p,16c#6,p,8d#6,p,8b,p,4g#,16p,4c#6,p,16a#,p,8f#,p,8a#,p,4g#,4p,g#,p,a#,p,b,p,c6,p,4c#6,16p,4f#6,p,16c#6,p,8d#6,p,8b,p,4g#,16p,4c#6,p,16a#,p,8b,p,8f,p,4f#";
//char *song = "LeisureSuit:d=16,o=6,b=56:f.5,f#.5,g.5,g#5,32a#5,f5,g#.5,a#.5,32f5,g#5,32a#5,g#5,8c#.,a#5,32c#,a5,a#.5,c#.,32a5,a#5,32c#,d#,8e,c#.,f.,f.,f.,f.,f,32e,d#,8d,a#.5,e,32f,e,32f,c#,d#.,c#";
#define isdigit(n) (n >= '0' && n <= '9')
#define NOTE_B0 31
#define NOTE_C1 33
#define NOTE_CS1 35
#define NOTE_D1 37
#define NOTE_DS1 39
#define NOTE_E1 41
#define NOTE_F1 44
#define NOTE_FS1 46
#define NOTE_G1 49
#define NOTE_GS1 52
#define NOTE_A1 55
#define NOTE_AS1 58
#define NOTE_B1 62
#define NOTE_C2 65
#define NOTE_CS2 69
#define NOTE_D2 73
#define NOTE_DS2 78
#define NOTE_E2 82
#define NOTE_F2 87
#define NOTE_FS2 93
#define NOTE_G2 98
#define NOTE_GS2 104
#define NOTE_A2 110
#define NOTE_AS2 117
#define NOTE_B2 123
#define NOTE_C3 131
#define NOTE_CS3 139
#define NOTE_D3 147
#define NOTE_DS3 156
#define NOTE_E3 165
#define NOTE_F3 175
#define NOTE_FS3 185
#define NOTE_G3 196
#define NOTE_GS3 208
#define NOTE_A3 220
#define NOTE_AS3 233
#define NOTE_B3 247
#define NOTE_C4 262
#define NOTE_CS4 277
#define NOTE_D4 294
#define NOTE_DS4 311
#define NOTE_E4 330
#define NOTE_F4 349
#define NOTE_FS4 370
#define NOTE_G4 392
#define NOTE_GS4 415
#define NOTE_A4 440
#define NOTE_AS4 466
#define NOTE_B4 494
#define NOTE_C5 523
#define NOTE_CS5 554
#define NOTE_D5 587
#define NOTE_DS5 622
#define NOTE_E5 659
#define NOTE_F5 698
#define NOTE_FS5 740
#define NOTE_G5 784
#define NOTE_GS5 831
#define NOTE_A5 880
#define NOTE_AS5 932
#define NOTE_B5 988
#define NOTE_C6 1047
#define NOTE_CS6 1109
#define NOTE_D6 1175
#define NOTE_DS6 1245
#define NOTE_E6 1319
#define NOTE_F6 1397
#define NOTE_FS6 1480
#define NOTE_G6 1568
#define NOTE_GS6 1661
#define NOTE_A6 1760
#define NOTE_AS6 1865
#define NOTE_B6 1976
#define NOTE_C7 2093
#define NOTE_CS7 2217
#define NOTE_D7 2349
#define NOTE_DS7 2489
#define NOTE_E7 2637
#define NOTE_F7 2794
#define NOTE_FS7 2960
#define NOTE_G7 3136
#define NOTE_GS7 3322
#define NOTE_A7 3520
#define NOTE_AS7 3729
#define NOTE_B7 3951
#define NOTE_C8 4186
#define NOTE_CS8 4435
#define NOTE_D8 4699
#define NOTE_DS8 4978
#define OCTAVE_OFFSET 0
int notes[] = { 0,
NOTE_C4, NOTE_CS4, NOTE_D4, NOTE_DS4, NOTE_E4, NOTE_F4, NOTE_FS4, NOTE_G4, NOTE_GS4, NOTE_A4, NOTE_AS4, NOTE_B4,
NOTE_C5, NOTE_CS5, NOTE_D5, NOTE_DS5, NOTE_E5, NOTE_F5, NOTE_FS5, NOTE_G5, NOTE_GS5, NOTE_A5, NOTE_AS5, NOTE_B5,
NOTE_C6, NOTE_CS6, NOTE_D6, NOTE_DS6, NOTE_E6, NOTE_F6, NOTE_FS6, NOTE_G6, NOTE_GS6, NOTE_A6, NOTE_AS6, NOTE_B6,
NOTE_C7, NOTE_CS7, NOTE_D7, NOTE_DS7, NOTE_E7, NOTE_F7, NOTE_FS7, NOTE_G7, NOTE_GS7, NOTE_A7, NOTE_AS7, NOTE_B7
};
// Absolutely no error checking in here
byte default_dur = 4;
byte default_oct = 6;
int bpm = 63;
int num;
long wholenote;
long duration;
byte note;
byte scale;
// format: d=N,o=N,b=NNN:
// find the start (skip name, etc)
while(*p != ':') p++; // ignore name
p++; // skip ':'
// get default duration
if(*p == 'd'){
p++; p++; // skip "d="
num = 0;
while(isdigit(*p)){
num = (num * 10) + (*p++ - '0');
}
if(num > 0) default_dur = num;
p++; // skip comma
}
// get default octave
if(*p == 'o'){
p++; p++; // skip "o="
num = *p++ - '0';
if(num >= 3 && num <=7) default_oct = num;
p++; // skip comma
}
// get BPM
if(*p == 'b'){
p++; p++; // skip "b="
num = 0;
while(isdigit(*p)){
num = (num * 10) + (*p++ - '0');
}
bpm = num;
p++; // skip colon
}
// BPM usually expresses the number of quarter notes per minute
wholenote = (60 * 1000L / bpm) * 4; // this is the time for whole note (in milliseconds)
// now begin note loop
while(*p){
// first, get note duration, if available
num = 0;
while(isdigit(*p)){
num = (num * 10) + (*p++ - '0');
}
if(num) duration = wholenote / num;
else duration = wholenote / default_dur; // we will need to check if we are a dotted note after
// now get the note
note = 0;
switch(*p) {
case 'c':
note = 1;
break;
case 'd':
note = 3;
break;
case 'e':
note = 5;
break;
case 'f':
note = 6;
break;
case 'g':
note = 8;
break;
case 'a':
note = 10;
break;
case 'b':
note = 12;
break;
case 'p':
default:
note = 0;
}
p++;
// now, get optional '#' sharp
if(*p == '#'){
note++;
p++;
}
// now, get optional '.' dotted note
if(*p == '.'){
duration += duration/2;
p++;
}
// now, get scale
if(isdigit(*p)){
scale = *p - '0';
p++;
}
else{
scale = default_oct;
}
scale += OCTAVE_OFFSET;
if(*p == ',')
p++; // skip comma for next note (or we may be at the end)
// now play the note
if(note){
digitalWrite(C_SpeakerPin, HIGH);
int danFreq;
float danDur;
danFreq = notes[(scale - 4) * 12 + note];
danDur = 1000000 / danFreq;
unsigned long start = millis();
while (millis() - start <= duration) {
digitalWrite(C_SpeakerPin, HIGH);
delayMicroseconds(danDur);
digitalWrite(C_SpeakerPin, LOW);
delayMicroseconds(danDur);
}
digitalWrite(C_SpeakerPin, LOW);
}
else{
delay(duration);
}
}
}