Go Down

Topic: Can't get Coburn's code for Buzz Wire Game to compile (Read 2005 times) previous topic - next topic

groundFungus

#15
Dec 14, 2018, 01:02 am Last Edit: Dec 14, 2018, 01:05 am by groundFungus
Here is the code with the TM1637 stuff removed and the LCD stuff inserted.  Note that I had to change one pin as there was a conflict between one of the buzzers and the LCD.  Changed the buzzer to pin 8.  See comment in code.  Don't forget to copy the pitches.h file into a tab.  The #include is already fixed.  Code tested to the extent that I can without building the entire circuit.  You now have a lot more flexibility in terms of what you can display.

Code: [Select]
#include <hd44780.h>
#include <hd44780ioClass/hd44780_pinIO.h> // Arduino pin i/o class header
#include "pitches.h" // include pitches

const int rs = 11, en = 12, db4 = 4, db5 = 5, db6 = 6, db7 = 7; // for all other devices

hd44780_pinIO lcd(rs, en, db4, db5, db6, db7);

// LCD geometry
const int LCD_COLS = 16;
const int LCD_ROWS = 2;

// music
int songState = 0;

int melody[] =
{
   NOTE_F4, NOTE_E4, NOTE_D4, NOTE_CS4,
   NOTE_C4, NOTE_B3, NOTE_AS3, NOTE_A3,
   NOTE_G3, NOTE_A3, NOTE_AS3, NOTE_A3,
   NOTE_G3, NOTE_C4, 0,

   NOTE_C4, NOTE_A3, NOTE_A3, NOTE_A3,
   NOTE_GS3, NOTE_A3, NOTE_F4, NOTE_C4,
   NOTE_C4, NOTE_A3, NOTE_AS3, NOTE_AS3,
   NOTE_AS3, NOTE_C4, NOTE_D4, 0,

   NOTE_AS3, NOTE_G3, NOTE_G3, NOTE_G3,
   NOTE_FS3, NOTE_G3, NOTE_E4, NOTE_D4,
   NOTE_D4, NOTE_AS3, NOTE_A3, NOTE_A3,
   NOTE_A3, NOTE_AS3, NOTE_C4, 0,

   NOTE_C4, NOTE_A3, NOTE_A3, NOTE_A3,
   NOTE_GS3, NOTE_A3, NOTE_A4, NOTE_F4,
   NOTE_F4, NOTE_C4, NOTE_B3, NOTE_G4,
   NOTE_G4, NOTE_G4, NOTE_G4, 0,

   NOTE_G4, NOTE_E4, NOTE_G4, NOTE_G4,
   NOTE_FS4, NOTE_G4, NOTE_D4, NOTE_G4,
   NOTE_G4, NOTE_FS4, NOTE_G4, NOTE_C4,
   NOTE_B3, NOTE_C4, NOTE_B3, NOTE_C4, 0
};

int tempo[] =
{
   8, 16, 8, 16,
   8, 16, 8, 16,
   16, 16, 16, 8,
   16, 8, 3,

   12, 16, 16, 16,
   8, 16, 8, 16,
   8, 16, 8, 16,
   8, 16, 4, 12,

   12, 16, 16, 16,
   8, 16, 8, 16,
   8, 16, 8, 16,
   8, 16, 4, 12,

   12, 16, 16, 16,
   8, 16, 8, 16,
   8, 16, 8, 16,
   8, 16, 4, 16,

   12, 17, 17, 17,
   8, 12, 17, 17,
   17, 8, 16, 8,
   16, 8, 16, 8, 1
};

// non blocking setup
// free play
unsigned long previousMillis1 = 0; // time words last changed
const long interval1 = 1500; // interval between changing

// music
unsigned long previousMillis2 = 0; // time last changed
const long interval2 = 100; // interval between notes

int displayStatus = 0; // keep track of what's displayed
int mode = 0; // keep track of game mode -- change to 0 or 1 for different modes

bool countdown = false;

unsigned long previousMillis3 = 0; // time last changed
const long interval3 = 1000; // interval between countdown
int count = 20; // challenge mode timer

void setup()
{
   // put your setup code here, to run once:
   pinMode(9, INPUT); // setup circuit
   pinMode(10, OUTPUT); // setup buzzer 1
   pinMode(8, OUTPUT); // setup buzzer 2  // had to change this pin. conflict with LCD
   pinMode(2, INPUT); // setup button

   lcd.begin(LCD_COLS, LCD_ROWS);
   lcd.print("BUZZ REAADY");
   delay(1000);
   lcd.clear();
}

void loop()
{
   // put your main code here, to run repeatedly:
   if (mode == 0)
   {
      // challenge mode
      if (digitalRead(2) == HIGH)
      {
         delay(25);
         if (digitalRead(2) == HIGH)
         {
            countdown = true; // stop the countdown
         }
         else
         {
            countdown = false; // stop the countdown
         }
      }
      if (countdown)
      {
         showCountdown(); // advance countdown
      }
   }
   else
   {
      // free play
      toggleFreePlay();
   }
   if (digitalRead(10) == HIGH)
   {
      delay(25);
      if (digitalRead(10) == HIGH)
      {
         while (digitalRead(10) == HIGH)
         {
            buzz(11, NOTE_B0, 1000 / 24);
         }
      }
   }
   else
   {
      sing();
    }
}

void showCountdown()
{
   // countdown the time remaining
   unsigned long currentMillis = millis(); // current time
   if (currentMillis - previousMillis3 >= interval3)
   {
      previousMillis3 = currentMillis;
      --count;
      showNumber(count);
      if (count == 0)
      {
         // game over
         countdown = false;
         count = 20;
         // reset countdown
         // buzz 3 times
         buzz(11, NOTE_B0, 1000 / 24);
         delay(100);
         buzz(11, NOTE_B0, 1000 / 24);
         delay(100);
         buzz(11, NOTE_B0, 1000 / 24);
      }
   }
}

void showNumber(int number)
{
  lcd.clear();
  lcd.setCursor(4,0);
  lcd.print("-- "); 
  lcd.setCursor(7,0);
  lcd.print(number);
  lcd.print(" --");
}

void toggleFreePlay()
{
   // scroll between words without blocking
   unsigned long currentMillis = millis(); // current time
   if (currentMillis - previousMillis1 >= interval1)
   {
      previousMillis1 = currentMillis;
      if (displayStatus == 1)
         showPlay();
      else
         showFree();
   }
}

void showPlay()
{
   // write "PLAY" to the display
   lcd.clear();
   lcd.setCursor(6,0);
   lcd.print("PLAY");
   displayStatus = 2;
}

void showFree()
{
   // write "Free" to the display
   lcd.clear();
   lcd.setCursor(6,1);
   lcd.print("FREE");
   displayStatus = 1;
}

void buzz(int targetPin, long frequency, long length)
{
   /* Buzzer example function by Rob Faludi
      http://www.faludi.com
      https://gist.github.com/AnthonyDiGirolamo/1405180
   */
   long delayValue = 1000000 / frequency / 2; // calculate the delay value between transitions
   //// 1 second's worth of microseconds, divided by the frequency, then split in half since
   //// there are two phases to each cycle
   long numCycles = frequency * length / 1000; // calculate the number of cycles for proper timing
   //// multiply frequency, which is really cycles per second, by the number of seconds to
   //// get the total number of cycles to produce
   for (long i = 0; i < numCycles; i++) // for the calculated length of time...
   {
      digitalWrite(targetPin, HIGH); // write the buzzer pin high to push out the diaphragm
      delayMicroseconds(delayValue); // wait for the calculated delay value
      digitalWrite(targetPin, LOW); // write the buzzer pin low to pull back the diaphragm
      delayMicroseconds(delayValue); // wait again for the calculated delay value
   }
}

void sing()
{
   // play the song in a non blocking way
   unsigned long currentMillis = millis();

   if (currentMillis - previousMillis2 >= interval2)
   {
      previousMillis2 = currentMillis;
      int noteDuration = 1000 / tempo[songState];
      buzz(10, melody[songState], noteDuration);
      int pauseBetweenNotes = noteDuration;
      delay(pauseBetweenNotes);

      // stop the tone playing:
      buzz(10, 0, noteDuration);

      ++songState;
      // start song again if finished
      if (songState > 79)
      {
         songState = 14; // skip intro
      }
   }
}


Have fun, Charlie.

jjeffh

Outstanding! I'm looking forward to trying this, Charlie. I've done a good deal of coding in VBA for Excel, but never in C++ (or any other language). I'm getting a bit of education about C++ and circuits both.





ardy_guy

#17
Dec 14, 2018, 04:55 am Last Edit: Dec 14, 2018, 04:56 am by ardy_guy
I'm getting a bit of education about C++ and circuits both.
And that's all part of it: you start by just trying to get something done because you have a result in mind, which looks dead simple because it's all written in a book, and learn stuff along the way too. (Although my kids are both engineers in their 20s (fire and electrical, respectively*), no grandkids here yet. I guess my days of Christmas projects have still to come.)

*Just had a thought about that: if one's sparks cause a fire, we should be safe.

Kudos to groundFungus for the way he handled this thread. Certain other members could learn from that....

groundFungus

Thanks, ardy_guy and Jeff. 

Jeff, as you go along with learning you will see that the circuit could use some small improvements.  The push button switch could be wired to ground and use the internal pullup resistor instead of the external pull down and wand could be wired the same without the voltage divider.  That is, the course wired to ground and the wand to a digital input with the internal pullup.  The logic for the push button and the wand would need to be adjusted for active low logic.

jjeffh

... Kudos to groundFungus for the way he handled this thread. ...
Hear! Hear!

Jeff, as you go along with learning you will see that the circuit could use some small improvements.  The push button switch could be wired to ground and use the internal pullup resistor instead of the external pull down and wand could be wired the same without the voltage divider.  That is, the course wired to ground and the wand to a digital input with the internal pullup.  The logic for the push button and the wand would need to be adjusted for active low logic.
I'm afraid all that just zinged right over my head. I'm still working on what ardy-guy called the "dead simple" stuff: copying directly out of the book and hoping something works.

I haven't started yet today, but in my tests yesterday the Monty Python theme Coburn programmed in played fine, but when I touched the wand and course leads, I didn't get a buzz, which is the point of the project.

And regarding the Monty Python theme, much as I like it, the circuit tweak that occurred to me was a way to turn it on and off, or at least subdue it. Coming out of that little piezo it kind of grates after a while. (Not to mention it clearly bothered my cat!)

I'll be starting over today with the new code to see what I get. Wish me luck!

BTW, the lesson in how to use the 2 line LCD display really gives me something I think I can play with with Chance (the grandson) aside from this project.

groundFungus

#20
Dec 14, 2018, 05:56 pm Last Edit: Dec 14, 2018, 05:58 pm by groundFungus
I will look and see if the buzzer problem is in the code or circuit.

You could add a button to turn the MP theme off and on.  If you want, I will look at that.


Wow, here is a coincidence.  My son's name is Chance.

jjeffh

That's pretty cool about the shared name!

Today completely got away from me, so I won't be able to rebuild the circuit until tomorrow (I'm in EST, 5- the forum time).

I don't know if the lack of a buzzer when the wand and course leads touch was a construction or code error, so I'm going to revisit that when I get back to the project.

A music-on-off button would be cool. I'd like to see how that's done. One problem I have with the push-buttons in general is that they don't seat well on the solderless breadboard. I tried straightening the contacts, but that didn't help. Could that just be the ones supplied in the Starter Kit?

The one thing I was able to do today was read through your code. I found 4 instances of "buzz()" which included an argument for "11" (1 under "// free play", and 3 under "void showCountdown()"). I'm assuming I should change those 11's to 8's, right? But I also see "const int rs = 11, ..." at the top, in the 4th line of the code. I'm not sure if that reference to 11 is about the pin and/or whether it should be 8.

groundFungus

#22
Dec 15, 2018, 12:15 am Last Edit: Dec 15, 2018, 12:21 am by groundFungus
You are right about those switches.  They can be a pain.  I take a pair of needle nose and twist the legs 90 degrees so they fit into the breadboard easier.  A marginal improvement.

You are also right about the pin 11.   I missed changing that.   Change those pins to 8.  That is another thing about that code.  Definitely written by an inexperienced coder.  You should not use pin numbers like that in code.  Give the pin a name, in global scope, then use the name in the code.  That way, to change the pin number it needs done in only one place.

Leave the int rs =11;  that is for the LCD.  Just change the ones related to the buzzer.




jjeffh

I'm back...

I've got the board set up for Buzz Wire, with the LCD display including the change of buzzer 2 to pin 8. I've compiled and uploaded your code (with the corrections to buzzer 2). I've been over the connections with a flashlight and magnifying glass and they seem to be correct. But all I'm getting is the Monty Python theme.

When I touch the course and wand leads (wand to power; course grounded through two 220 resistors), there's no buzz. (Monty Python only plays through buzzer 1, incidentally. I'm guessing Coburn wrote it to play the music through buzzer 1 and the touch buzzer through buzzer 2.)

There's no display on the LCD (should be "BUZZ READY", right?). And when I press the button nothing happens except that the music slows down slightly. (BTW, good tip about twisting the button contacts inward.)

I also uploaded your LCD, "Hello World" code, which worked fine when I set up just for that, but I'm getting nothing on the LCD in this configuration.

In case you still think there's any hope, I've uploaded an annotated pdf of the LCD setup. But I'll understand if it looks hopeless ... it kind of feels that way.

Maybe I should just take Chance to Chuck E Cheese!


groundFungus

I don't see anything wrong with the wiring.  Can you post the code that you are running?   Does the display show anything?

jjeffh

I don't see anything wrong with the wiring.  Can you post the code that you are running?   Does the display show anything?
Nothing on the display, not even the back lighting.

I've attached the code as a Word doc. I copied it directly from Arduino, then added line numbers in Word in case that might help.


groundFungus

#26
Dec 15, 2018, 11:50 pm Last Edit: Dec 15, 2018, 11:54 pm by groundFungus
It is OK for now, but in the future, please post in code tags.  That way I can copy to the IDE (the IDE will insert line numbers).  I have to remove the line numbers to be able put the code in the IDE. 

How are the breadboard's bottom power rails getting power and ground.  They are not tied to the top rails unless you make the connection.

And a hint to make things easier.  Use red jumpers for 5V and black for ground.  I use the colors of the jumpers to make things easier to trace.  I go by the resistor color code and the jumpers color reflects the Uno pin number that the jumper comes from. 


jjeffh

Whoops!! Sorry about that. I wasn't thinking. In case you haven't already gone to all that trouble, here it is, below.

Regarding power and ground, in the picture you can sort of see a red and a black lead going to the power and ground rails in the upper right corner of the board (from 5v and GND). It's pretty much in the middle of the picture. Then at the other end of those rails I have two orange leads, one taking the power and the other taking the ground to the opposite rails of the board.

Code: [Select]
#include <hd44780.h>
#include <hd44780ioClass/hd44780_pinIO.h> // Arduino pin i/o class header
#include "pitches.h" // include pitches

const int rs = 11, en = 12, db4 = 4, db5 = 5, db6 = 6, db7 = 7; // for all other devices

hd44780_pinIO lcd(rs, en, db4, db5, db6, db7);

// LCD geometry
const int LCD_COLS = 16;
const int LCD_ROWS = 2;

// music: Monty Python theme
int songState = 0;

int melody[] =
{
   NOTE_F4, NOTE_E4, NOTE_D4, NOTE_CS4,
   NOTE_C4, NOTE_B3, NOTE_AS3, NOTE_A3,
   NOTE_G3, NOTE_A3, NOTE_AS3, NOTE_A3,
   NOTE_G3, NOTE_C4, 0,

   NOTE_C4, NOTE_A3, NOTE_A3, NOTE_A3,
   NOTE_GS3, NOTE_A3, NOTE_F4, NOTE_C4,
   NOTE_C4, NOTE_A3, NOTE_AS3, NOTE_AS3,
   NOTE_AS3, NOTE_C4, NOTE_D4, 0,

   NOTE_AS3, NOTE_G3, NOTE_G3, NOTE_G3,
   NOTE_FS3, NOTE_G3, NOTE_E4, NOTE_D4,
   NOTE_D4, NOTE_AS3, NOTE_A3, NOTE_A3,
   NOTE_A3, NOTE_AS3, NOTE_C4, 0,

   NOTE_C4, NOTE_A3, NOTE_A3, NOTE_A3,
   NOTE_GS3, NOTE_A3, NOTE_A4, NOTE_F4,
   NOTE_F4, NOTE_C4, NOTE_B3, NOTE_G4,
   NOTE_G4, NOTE_G4, NOTE_G4, 0,

   NOTE_G4, NOTE_E4, NOTE_G4, NOTE_G4,
   NOTE_FS4, NOTE_G4, NOTE_D4, NOTE_G4,
   NOTE_G4, NOTE_FS4, NOTE_G4, NOTE_C4,
   NOTE_B3, NOTE_C4, NOTE_B3, NOTE_C4, 0
};

int tempo[] =
{
   8, 16, 8, 16,
   8, 16, 8, 16,
   16, 16, 16, 8,
   16, 8, 3,

   12, 16, 16, 16,
   8, 16, 8, 16,
   8, 16, 8, 16,
   8, 16, 4, 12,

   12, 16, 16, 16,
   8, 16, 8, 16,
   8, 16, 8, 16,
   8, 16, 4, 12,

   12, 16, 16, 16,
   8, 16, 8, 16,
   8, 16, 8, 16,
   8, 16, 4, 16,

   12, 17, 17, 17,
   8, 12, 17, 17,
   17, 8, 16, 8,
   16, 8, 16, 8, 1
};

// non blocking setup
// free play
unsigned long previousMillis1 = 0; // time words last changed
const long interval1 = 1500; // interval between changing

// music
unsigned long previousMillis2 = 0; // time last changed
const long interval2 = 100; // interval between notes

int displayStatus = 0; // keep track of what's displayed
int mode = 0; // keep track of game mode -- change to 0 or 1 for different modes

bool countdown = false;

unsigned long previousMillis3 = 0; // time last changed
const long interval3 = 1000; // interval between countdown
int count = 20; // challenge mode timer

void setup()
{
   // put your setup code here, to run once:
   pinMode(9, INPUT); // setup circuit
   pinMode(10, OUTPUT); // setup buzzer 1
   pinMode(8, OUTPUT); // setup buzzer 2  // had to change this pin. conflict with LCD
   pinMode(2, INPUT); // setup button

   lcd.begin(LCD_COLS, LCD_ROWS);
   lcd.print("BUZZ READY");
   delay(1000);
   lcd.clear();
}

void loop()
{
   // put your main code here, to run repeatedly:
   if (mode == 0)
   {
      // challenge mode
      if (digitalRead(2) == HIGH)
      {
         delay(25);
         if (digitalRead(2) == HIGH)
         {
            countdown = true; // stop the countdown [shouldn’t this be ‘start the countdown’?]
         }
         else
         {
            countdown = false; // stop the countdown
         }
      }
      if (countdown)
      {
         showCountdown(); // advance countdown
      }
   }
   else
   {
      // free play
      toggleFreePlay();
   }
   if (digitalRead(10) == HIGH)
   {
      delay(25);
      if (digitalRead(10) == HIGH)
      {
         while (digitalRead(10) == HIGH)
         {
            buzz(8, NOTE_B0, 1000 / 24); //[This was changed from 11 to 8]
         }
      }
   }
   else
   {
      sing();
    }
}

void showCountdown()
{
   // countdown the time remaining
   unsigned long currentMillis = millis(); // current time
   if (currentMillis - previousMillis3 >= interval3)
   {
      previousMillis3 = currentMillis;
      --count;
      showNumber(count);
      if (count == 0)
      {
         // game over
         countdown = false;
         count = 20;
         // reset countdown
         // buzz 3 times
         buzz(8, NOTE_B0, 1000 / 24); //[changed from 11 to 8]
         delay(100);
         buzz(8, NOTE_B0, 1000 / 24); //[changed from 11 to 8]
         delay(100);
         buzz(8, NOTE_B0, 1000 / 24); //[changed from 11 to 8]
      }
   }
}

void showNumber(int number)
{
  lcd.clear();
  lcd.setCursor(4,0);
  lcd.print("-- "); 
  lcd.setCursor(7,0);
  lcd.print(number);
  lcd.print(" --");
}

void toggleFreePlay()
{
   // scroll between words without blocking
   unsigned long currentMillis = millis(); // current time
   if (currentMillis - previousMillis1 >= interval1)
   {
      previousMillis1 = currentMillis;
      if (displayStatus == 1)
         showPlay();
      else
         showFree();
   }
}

void showPlay()
{
   // write "PLAY" to the display
   lcd.clear();
   lcd.setCursor(6,0);
   lcd.print("PLAY");
   displayStatus = 2;
}

void showFree()
{
   // write "Free" to the display
   lcd.clear();
   lcd.setCursor(6,1);
   lcd.print("FREE");
   displayStatus = 1;
}

void buzz(int targetPin, long frequency, long length)
{
   /* Buzzer example function by Rob Faludi
      http://www.faludi.com
      https://gist.github.com/AnthonyDiGirolamo/1405180
   */
   long delayValue = 1000000 / frequency / 2; // calculate the delay value between transitions
   //// 1 second's worth of microseconds, divided by the frequency, then split in half since
   //// there are two phases to each cycle
   long numCycles = frequency * length / 1000; // calculate the number of cycles for proper timing
   //// multiply frequency, which is really cycles per second, by the number of seconds to
   //// get the total number of cycles to produce
   for (long i = 0; i < numCycles; i++) // for the calculated length of time...
   {
      digitalWrite(targetPin, HIGH); // write the buzzer pin high to push out the diaphragm
      delayMicroseconds(delayValue); // wait for the calculated delay value
      digitalWrite(targetPin, LOW); // write the buzzer pin low to pull back the diaphragm
      delayMicroseconds(delayValue); // wait again for the calculated delay value
   }
}

void sing()
{
   // play the song in a non blocking way
   unsigned long currentMillis = millis();

   if (currentMillis - previousMillis2 >= interval2)
   {
      previousMillis2 = currentMillis;
      int noteDuration = 1000 / tempo[songState];
      buzz(10, melody[songState], noteDuration);
      int pauseBetweenNotes = noteDuration;
      delay(pauseBetweenNotes);

      // stop the tone playing:
      buzz(10, 0, noteDuration);

      ++songState;
      // start song again if finished
      if (songState > 79)
      {
         songState = 14; // skip intro
      }
   }
}

groundFungus

#28
Dec 16, 2018, 12:11 am Last Edit: Dec 16, 2018, 12:14 am by groundFungus
But without changing anything and uploading my test code the LCD works? 
If the bottom rails are getting power the backlight should light.

jjeffh

After I set it up for the full Buzz Wire game and nothing happened (except Monty Python), then I left it all as you see it and uploaded your LCD code. That didn't work either. It would seem that I must be doing something wrong, but I sure can't see it.


Go Up