I am making a sort of electronic music box for a friend for Christmas, using a Sparkfun MP3 Shield and an uno.
Simple design, button attached to the side of the box, take the lid off and it plays a track. Except that it does not work. My circuit is fine, I have quadrupel checked that, just the button example except its attached to pin 12. Switch is high when the lid is on, low when its off. This is what I tried first:
Just a about as simple as it gets, right? No good, I realized later that since the playTrack() function actually doesn't pause your loop and that it was trying to always start the track. So I poked around the examples and found the state change detection, modified it a bit:
#include <SPI.h>
#include <SdFat.h>
#include <SdFatUtil.h>
#include <SFEMP3Shield.h>
SFEMP3Shield MP3player;
const int buttonPin = 12;
int buttonState = 0; // current state of the button
int lastButtonState = 1; // previous state of the button
void setup() {
pinMode(buttonPin, INPUT);
Serial.begin(9600);
MP3player.begin();
MP3player.SetVolume(50, 50);
}
void loop() {
// read the pushbutton input pin:
buttonState = digitalRead(buttonPin);
// compare the buttonState to its previous state
if (buttonState != lastButtonState) {
if (buttonState == LOW) {
MP3player.playTrack(1);
}
else {
}
}
// save the current state as the last state,
//for next time through the loop
lastButtonState = buttonState;
}
Seems like it should work too, huh? There are a couple others I've tried and none work. I am an expert at making stupid mistakes and overlooking small errors. Any suggestions? What am I doing wrong? Thanks a ton, happy holidays!!!
yes indeed, I have gotten the track to play multiple times, just not in the way I want. Like in the original sketch it only works with a press and release, not a plain release. Thanks for the quick reply!
I can see only two things left: 1. The initial values of buttonState and lastButtonState; 2. Debouncing the push-button.
First, change the initialization to match the usage (won't help with the current problem but it makes it clear to the future-you how the variables are used)...
int buttonState = LOW; // current state of the button
int lastButtonState = HIGH; // previous state of the button
How you initialize the variables will affect how the box behaves on startup. Do you want the music to play on startup if the lid is already open? Or would you prefer the lid to have to be closed then opened for the music to play?
no good. I'd want it to do both. The debouncing also seems like it should work...
/*
Debounce
Each time the input pin goes from LOW to HIGH (e.g. because of a push-button
press), the output pin is toggled from LOW to HIGH or HIGH to LOW. There's
a minimum delay between toggles to debounce the circuit (i.e. to ignore
noise).
The circuit:
* LED attached from pin 13 to ground
* pushbutton attached from pin 2 to +5V
* 10K resistor attached from pin 2 to ground
* Note: On most Arduino boards, there is already an LED on the board
connected to pin 13, so you don't need any extra components for this example.
created 21 November 2006
by David A. Mellis
modified 30 Aug 2011
by Limor Fried
This example code is in the public domain.
http://www.arduino.cc/en/Tutorial/Debounce
*/
#include <SPI.h>
#include <SdFat.h>
#include <SdFatUtil.h>
#include <SFEMP3Shield.h>
SFEMP3Shield MP3player;
// constants won't change. They're used here to
// set pin numbers:
const int buttonPin = 12; // the number of the pushbutton pin
//const int ledPin = 13; // the number of the LED pin
// Variables will change:
//int ledState = HIGH; // the current state of the output pin
int buttonState; // the current reading from the input pin
int lastButtonState = HIGH; // the previous reading from the input pin
// the following variables are long's because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long lastDebounceTime = 0; // the last time the output pin was toggled
long debounceDelay = 100; // the debounce time; increase if the output flickers
void setup() {
pinMode(buttonPin, INPUT);
//pinMode(ledPin, OUTPUT);
MP3player.begin();
MP3player.SetVolume(50, 50);
}
void loop() {
// read the state of the switch into a local variable:
int reading = digitalRead(buttonPin);
// check to see if you just pressed the button
// (i.e. the input went from LOW to HIGH), and you've waited
// long enough since the last press to ignore any noise:
// If the switch changed, due to noise or pressing:
if (reading != lastButtonState) {
// reset the debouncing timer
lastDebounceTime = millis();
}
if ((millis() - lastDebounceTime) > debounceDelay) {
// whatever the reading is at, it's been there for longer
// than the debounce delay, so take it as the actual current state:
buttonState = reading;
MP3player.playTrack(1);
}
// set the LED using the state of the button:
//digitalWrite(ledPin, buttonState);
// save the reading. Next time through the loop,
// it'll be the lastButtonState:
lastButtonState = reading;
}
I dont know, maybe i put the playTrack in the wrong spot? im running out of ideas... Thanks!
Might I suggest that you put each { on a new line, and use Tools + Auto Format to properly indent your code. I think that seeing the structure of the program properly will reveal that you did indeed put the code to play the music in the wrong place.
Ask yourself, for each block, what has to happen to get here.
I like names like currState and prevState to keep track of the current and previous state of the switch. To me, they make a lot more sense than reading and lastButtonState. I look at those names and I can't see a relationship. I look at currState and prevState, and the relationship is obvious.
It's also obvious that you don't need three variables to determine whether the lid was removed. It either was last time and is now, wasn't last time and isn't now, was last time and isn't now, or wasn't last time and is now.
All 4 of those possibilities can be determined from just the current state and the previous state.
Alright, here is Debounce and StateChangeDetection modified to your standards:
#include <SPI.h>
#include <SdFat.h>
#include <SdFatUtil.h>
#include <SFEMP3Shield.h>
SFEMP3Shield MP3player;
const int buttonPin = 12;
int currState = 0; // current state of the button
int prevState = 0; // previous state of the button
void setup() {
pinMode(buttonPin, INPUT);
Serial.begin(9600);
MP3player.begin();
MP3player.SetVolume(50, 50);
}
void loop() {
// read the pushbutton input pin:
currState = digitalRead(buttonPin);
// compare the buttonState to its previous state
if (currState != prevState)
{
if (currState == LOW)
{
MP3player.playTrack(1);
}
else
{
}
}
// save the current state as the last state,
//for next time through the loop
prevState = currState;
}
#include <SPI.h>
#include <SdFat.h>
#include <SdFatUtil.h>
#include <SFEMP3Shield.h>
SFEMP3Shield MP3player;
const int buttonPin = 12; // the number of the pushbutton pin
int currState; // the current reading from the input pin
int prevState = HIGH; // the previous reading from the input pin
long lastDebounceTime = 0; // the last time the output pin was toggled
long debounceDelay = 100; // the debounce time; increase if the output flickers
void setup() {
pinMode(buttonPin, INPUT);
MP3player.begin();
MP3player.SetVolume(50, 50);
}
void loop() {
int reading = digitalRead(buttonPin);
if (reading != prevState)
{
lastDebounceTime = millis();
}
if ((millis() - lastDebounceTime) > debounceDelay)
{
currState = reading;
MP3player.playTrack(1);
}
prevState = reading;
}
Still not working... Notice the stupid mistake yet?
We'll start with the first one, with some additions.
#include <SPI.h>
#include <SdFat.h>
#include <SdFatUtil.h>
#include <SFEMP3Shield.h>
SFEMP3Shield MP3player;
const int buttonPin = 12;
int currState = 0; // current state of the button
int prevState = 0; // previous state of the button
void setup()
{
pinMode(buttonPin, INPUT);
Serial.begin(9600);
MP3player.begin();
MP3player.SetVolume(50, 50);
}
void loop()
{
// read the pushbutton input pin:
currState = digitalRead(buttonPin);
// compare the buttonState to its previous state
if (currState != prevState)
{
Serial.println("A transition occurred...");
if (currState == LOW)
{
Serial.println("...to pressed. Play the 1st track");
MP3player.playTrack(1);
}
}
// save the current state as the last state,
//for next time through the loop
prevState = currState;
}
Ok gave it a try, Held the button and started serial monitor, waited 10 seconds then released the button. Here is what I got serial-wise:
A transition occurred...
A transition occurred...
...to pressed. Play the 1st track
A transition occurred...
A transition occurred...
...to pressed. Play the 1st track
A transition occurred...
A transition occurred...
...to pressed. Play the 1st track
A transition occurred...
A transition occurred...
...to pressed. Play the 1st track
A transition occurred...
A transition occurred...
...to pressed. Play the 1st track
A transition occurred...
A transition occurred...
...to pressed. Play the 1st track
That just kept going infinitely, looks like it is constantly trying to play the track so it never actually starts. That was the problem I was getting earlier! Sound-wise I am getting nothing. Thanks for sticking with it! Belated Christmas presents are always more fun anyway.
Then I release the button and get this continuously:
A transition occurred...
A transition occurred...
...to pressed. Play the 1st track
A transition occurred...
A transition occurred...
...to pressed. Play the 1st track
A transition occurred...
A transition occurred...
...to pressed. Play the 1st track
A transition occurred...
A transition occurred...
...to pressed. Play the 1st track
A transition occurred...
A transition occurred...
...to pressed. Play the 1st track
A transition occurred...
A transition occurred...
...to pressed. Play the 1st track
If I press the button while it is doing that it pause the deluge, release it and it resumes.