Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
What's new
4
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Switch to GitLab Next
Sign in / Register
Toggle navigation
Menu
Open sidebar
papp
Mp3Box
Commits
9112451e
Commit
9112451e
authored
Aug 30, 2021
by
papp
Browse files
arduino
parent
044fbf34
Changes
270
Expand all
Hide whitespace changes
Inline
Side-by-side
LilyPad MP3 Player/Examples/Prank/Prank.ino
0 → 100644
View file @
9112451e
// "Prank" example sketch for Lilypad MP3 Player
// Mike Grusin, SparkFun Electronics
// http://www.sparkfun.com
// This was a prank we pulled on "According To" Pete Dokter.
// While Pete was spending the week at Disneyland with his kids,
// we attached the LilyPad MP3 Player to the big speakers in his
// office. The below sketch waits a given number of hours,
// then plays the audio files on the card while _very slowly_
// ramping up the volume to just barely noticeable. The audio
// file we used was "It's a Small World After All". You can
// of course use whatever you like (hopefully something more
// humane).
// Uses the SdFat library by William Greiman, which is supplied
// with this archive, or download from http://code.google.com/p/sdfatlib/
// Uses the SFEMP3Shield library by Bill Porter, which is supplied
// with this archive, or download from http://www.billporter.info/
// License:
// We use the "beerware" license for our firmware. You can do
// ANYTHING you want with this code. If you like it, and we meet
// someday, you can, but are under no obligation to, buy me a
// (root) beer in return.
// Have fun!
// -your friends at SparkFun
// Revision history:
// 1.0 initial release MDG 2013/4/1
// We'll need a few libraries to access all this hardware!
#include
<SPI.h>
// To talk to the SD card and MP3 chip
#include
<SdFat.h>
// SD card file system
#include
<SFEMP3Shield.h>
// MP3 decoder chip
// LilyPad MP3 Player pin definitions:
#define TRIG1 A0
#define ROT_LEDG A1
#define SHDN_GPIO1 A2
#define ROT_B A3
#define TRIG2_SDA A4
#define TRIG3_SCL A5
#define RIGHT A6
#define LEFT A7
#define TRIG5_RXI 0
#define TRIG4_TXO 1
#define MP3_DREQ 2
#define ROT_A 3
#define ROT_SW 4
#define ROT_LEDB 5
#define MP3_CS 6
#define MP3_DCS 7
#define MP3_RST 8
#define SD_CS 9
#define ROT_LEDR 10
#define MOSI 11
#define MISO 12
#define SCK 13
// Create library objects:
SFEMP3Shield
MP3player
;
SdFat
sd
;
SdFile
file
;
char
track
[
13
];
// If you would like debugging information sent to the
// serial port, set debugging = true. This will require
// the use of triggers 4 and 5 (but this sketch doesn't
// need them).
boolean
debugging
=
true
;
void
setup
()
{
unsigned
char
result
;
// If serial port debugging is inconvenient, you can connect
// a LED to the red channel of the rotary encoder to see any
// startup error codes:
pinMode
(
ROT_LEDR
,
OUTPUT
);
digitalWrite
(
ROT_LEDR
,
HIGH
);
// HIGH = off
// Turn the amplifier chip off and start the MP3 chip
// in MP3 mode:
pinMode
(
SHDN_GPIO1
,
OUTPUT
);
digitalWrite
(
SHDN_GPIO1
,
LOW
);
// MP3 mode / amp off
// Keep the VS1053 MP3 chip powered down while we're waiting
// to save power:
pinMode
(
MP3_RST
,
OUTPUT
);
digitalWrite
(
MP3_RST
,
LOW
);
// keep VS1053 in reset
if
(
debugging
)
{
Serial
.
begin
(
9600
);
Serial
.
println
(
F
(
"Lilypad MP3 Player prank sketch"
));
}
// Wait until we're ready to play the prank:
if
(
debugging
)
Serial
.
print
(
"waiting... "
);
delay
(
60000L
*
60L
*
16L
);
// wait 16 hours
if
(
debugging
)
Serial
.
println
(
"done"
);
// Turn on the MP3 chip:
digitalWrite
(
MP3_RST
,
HIGH
);
// VS1053 active
// Initialize the SD card:
if
(
debugging
)
Serial
.
print
(
F
(
"initialize SD card... "
));
result
=
sd
.
begin
(
SD_CS
,
SPI_HALF_SPEED
);
// 1 for success
if
(
result
!=
1
)
// Problem initializing the SD card
{
if
(
debugging
)
Serial
.
print
(
F
(
"error, halting"
));
errorBlink
(
1
);
// Halt forever, blink LED if present.
}
else
if
(
debugging
)
Serial
.
println
(
F
(
"success!"
));
// Start up the MP3 library:
if
(
debugging
)
Serial
.
print
(
F
(
"initialize MP3 chip... "
));
result
=
MP3player
.
begin
();
// 0 or 6 for success
// Check the result, see the library readme for error codes.
if
((
result
!=
0
)
&&
(
result
!=
6
))
// Problem starting up
{
if
(
debugging
)
Serial
.
print
(
F
(
"error code "
));
if
(
debugging
)
Serial
.
print
(
result
);
if
(
debugging
)
Serial
.
print
(
F
(
", halting."
));
errorBlink
(
result
);
// Halt forever, blink red LED if present.
}
else
if
(
debugging
)
Serial
.
println
(
F
(
"success!"
));
// Change to the root directory of the SD card:
sd
.
chdir
(
"/"
,
true
);
// Set the VS1053 volume. 0 is loudest, 255 is lowest:
MP3player
.
setVolume
(
255
,
255
);
// all the way off
// Turn on the amplifier chip:
digitalWrite
(
SHDN_GPIO1
,
HIGH
);
delay
(
2
);
}
void
loop
()
{
static
unsigned
long
next
=
0L
;
static
unsigned
int
volume
=
255
;
// Play the files on the SD card. Over and over and over...
if
(
!
MP3player
.
isPlaying
())
// if not playing...
{
getNextTrack
();
startPlaying
();
}
// Very slowly increase the volume. Because the volume register
// is logarithmic, we do this -slower- as it gets louder so that
// it doesn't quickly increase at the end. The below values will
// take about 1.5 hours to increase from off to barely noticeable.
// The following if() statement is like an alarm clock;
// we set "next" to be a future millis clock time, and when the
// millis clock reaches that value, the if() statement will run.
if
(
millis
()
>
next
)
{
// Increase the volume, but don't let it rise above 110dB.
// (You can make this 0 if you eventually want it to reach
// full volume.)
if
(
volume
>
110
)
volume
--
;
MP3player
.
setVolume
(
volume
,
volume
);
// The below line resets the alarm clock value to a new
// time in the future. The values in the pow() equation
// will take about 1.5 hours to increase from nothing to
// barely noticeable.
next
=
millis
()
+
(
pow
(((
255
-
volume
)
/
14
),
2
)
*
1000L
);
// For testing, you might want to comment out the above
// line, and uncomment the below line (this will raise
// the volume in less than a minute rather than taking hours.)
// next = millis() + 100L;
if
(
debugging
)
Serial
.
print
(
"volume: "
);
if
(
debugging
)
Serial
.
print
(
volume
);
if
(
debugging
)
Serial
.
print
(
"delay: "
);
if
(
debugging
)
Serial
.
println
(
pow
(((
255
-
volume
)
/
14
),
2
)
*
1000L
);
}
}
void
errorBlink
(
int
blinks
)
{
// The following function will blink the red LED in the rotary
// encoder (optional) a given number of times and repeat forever.
// This is so you can see any startup error codes without having
// to use the serial monitor window.
int
x
;
while
(
true
)
// Loop forever
{
for
(
x
=
0
;
x
<
blinks
;
x
++
)
// Blink the given number of times
{
digitalWrite
(
ROT_LEDR
,
LOW
);
// Turn LED ON
delay
(
250
);
digitalWrite
(
ROT_LEDR
,
HIGH
);
// Turn LED OFF
delay
(
250
);
}
delay
(
1500
);
// Longer pause between blink-groups
}
}
void
getNextTrack
()
{
// Get the next playable track (check extension to be
// sure it's an audio file)
do
getNextFile
();
while
(
isPlayable
()
!=
true
);
}
void
getNextFile
()
{
// Get the next file (which may be playable or not)
int
result
=
(
file
.
openNext
(
sd
.
vwd
(),
O_READ
));
// If we're at the end of the directory,
// loop around to the beginning:
if
(
!
result
)
{
sd
.
chdir
(
"/"
,
true
);
getNextTrack
();
return
;
}
file
.
getFilename
(
track
);
file
.
close
();
}
boolean
isPlayable
()
{
// Check to see if a filename has a "playable" extension.
// This is to keep the VS1053 from locking up if it is sent
// unplayable data.
char
*
extension
;
extension
=
strrchr
(
track
,
'.'
);
extension
++
;
if
(
(
strcasecmp
(
extension
,
"MP3"
)
==
0
)
||
(
strcasecmp
(
extension
,
"WAV"
)
==
0
)
||
(
strcasecmp
(
extension
,
"MID"
)
==
0
)
||
(
strcasecmp
(
extension
,
"MP4"
)
==
0
)
||
(
strcasecmp
(
extension
,
"WMA"
)
==
0
)
||
(
strcasecmp
(
extension
,
"FLA"
)
==
0
)
||
(
strcasecmp
(
extension
,
"OGG"
)
==
0
)
||
(
strcasecmp
(
extension
,
"AAC"
)
==
0
)
)
return
true
;
else
return
false
;
}
void
startPlaying
()
{
int
result
;
if
(
debugging
)
{
Serial
.
print
(
F
(
"playing "
));
Serial
.
print
(
track
);
Serial
.
print
(
F
(
"..."
));
}
result
=
MP3player
.
playMP3
(
track
);
if
(
debugging
)
{
Serial
.
print
(
F
(
" result "
));
Serial
.
println
(
result
);
}
}
void
stopPlaying
()
{
if
(
debugging
)
Serial
.
println
(
F
(
"stopping playback"
));
MP3player
.
stopTrack
();
}
LilyPad MP3 Player/Examples/Rotary_Encoder_Demo/Rotary_Encoder_Demo.ino
0 → 100644
View file @
9112451e
// "Rotary_Encoder_Demo"
// Example sketch for the Lilypad MP3 Player
// Mike Grusin, SparkFun Electronics
// http://www.sparkfun.com
// This sketch demonstrates (only) the use of the rotary encoder
// hardware on the Lilypad MP3 Player board from Sparkfun. If you
// want to use the rotary encoder in your own sketches, this code
// will give you a starting point.
// HARDWARE CONNECTIONS
// This sketch will run on a LilyPad MP3 Player board (with
// a rotary encoder installed) without modifications.
// If you're not using the LilyPad MP3 Player board, connect
// a rotary encoder to your Arduino using these pins:
// Rotary encoder pin A to digital pin 3*
// Rotary encoder pin B to analog pin 3
// Rotary encoder pin C to ground
// This sketch implements software debounce, but you can further
// improve performance wby placing 0.1uF capacitors between
// A and ground, and B and ground.
// If you wish to use the RGB LED and button functions of
// SparkFun part number COM-10982, use the following connections:
// Rotary encoder pin 1 (red cathode) to digital pin 10
// Rotary encoder pin 2 (green cathode) to analog pin 1
// Rotary encoder pin 3 (button) to digital pin 4
// Rotary encoder pin 4 (blue cathode) to digital pin 5
// Rotary encoder pin 5 (common anode) to VCC (3.3V or 5V)
// Note that because this is a common anode device,
// the pushbutton requires an external 1K-10K pullDOWN resistor
// to operate.
// * Pins marked with an asterisk should not change because
// they use interrupts on that pin. All other pins can change,
// see the constants below.
// SERIAL MONITOR
// Run this sketch with the serial monitor window set to 9600 baud.
// HOW IT WORKS
// The I/O pins used by the rotary encoder hardware are set up to
// automatically call interrupt functions (rotaryIRQ and buttonIRQ)
// each time the rotary encoder changes states.
// The rotaryIRQ function transparently maintains a counter that
// increments or decrements by one for each detent ("click") of
// the rotary encoder knob. This function also sets a flag
// (rotary_change) to true whenever the counter changes. You can
// check this flag in your main loop() code and perform an action
// when the knob is turned.
// The buttonIRQ function does the same thing for the pushbutton
// built into the rotary encoder knob. It will set flags for
// button_pressed and button_released that you can monitor in your
// main loop() code. There is also a variable for button_downtime
// which records how long the button was held down.
// There is also code in the main loop() that keeps track
// of whether the button is currently being held down and for
// how long. This is useful for "hold button down for five seconds
// to power off"-type situations, which cannot be handled by
// interrupts alone because no interrupts will be called until
// the button is actually released.
// Uses the PinChangeInt library by Lex Talionis,
// download from http://code.google.com/p/arduino-pinchangeint/
// License:
// We use the "beerware" license for our firmware. You can do
// ANYTHING you want with this code. If you like it, and we meet
// someday, you can, but are under no obligation to, buy me a
// (root) beer in return.
// Have fun!
// -your friends at SparkFun
// Revision history:
// 1.0 initial release MDG 2013/01/24
// Load the PinChangeInt (pin change interrupt) library
#include
<PinChangeInt.h>
// LilyPad MP3 pin defines. Not all of these are used in this
// sketch; the unused pins are commented out:
//#define TRIG1 A0
#define ROT_LEDG A1 // green LED
//#define SHDN_GPIO1 A2
#define ROT_B A3 // rotary B
//#define TRIG2_SDA A4
//#define TRIG3_SCL A5
//#define RIGHT A6
//#define LEFT A7
//#define TRIG5_RXI 0
//#define TRIG4_TXO 1
//#define MP3_DREQ 2
#define ROT_A 3 // rotary A
#define ROT_SW 4 // rotary puhbutton
#define ROT_LEDB 5 // blue LED
//#define MP3_CS 6
//#define MP3_DCS 7
//#define MP3_RST 8
//#define SD_CS 9
#define ROT_LEDR 10 // red LED
//#define MOSI 11
//#define MISO 12
//#define SCK 13
// RGB LED colors (for common anode LED, 0 is on, 1 is off)
#define OFF B111
#define RED B110
#define GREEN B101
#define YELLOW B100
#define BLUE B011
#define PURPLE B010
#define CYAN B001
#define WHITE B000
// Global variables that can be changed in interrupt routines
volatile
int
rotary_counter
=
0
;
// current "position" of rotary encoder (increments CW)
volatile
boolean
rotary_change
=
false
;
// will turn true if rotary_counter has changed
volatile
boolean
button_pressed
=
false
;
// will turn true if the button has been pushed
volatile
boolean
button_released
=
false
;
// will turn true if the button has been released (sets button_downtime)
volatile
unsigned
long
button_downtime
=
0L
;
// ms the button was pushed before release
void
setup
()
{
// Set up all the I/O pins. Unused pins are commented out.
// pinMode(TRIG1, INPUT);
// digitalWrite(TRIG1, HIGH); // turn on weak pullup
// pinMode(MP3_CS, OUTPUT);
// pinMode(SHDN_GPIO1, OUTPUT);
pinMode
(
ROT_B
,
INPUT
);
digitalWrite
(
ROT_B
,
HIGH
);
// turn on weak pullup
// pinMode(TRIG2_SDA, INPUT);
// digitalWrite(TRIG1, HIGH); // turn on weak pullup
// pinMode(TRIG3_SCL, INPUT);
// digitalWrite(TRIG1, HIGH); // turn on weak pullup
// pinMode(TRIG5_RXI, INPUT);
// digitalWrite(TRIG5_RXI, HIGH); // turn on weak pullup
// pinMode(TRIG4_TXO, INPUT);
// digitalWrite(TRIG4_TXO, HIGH); // turn on weak pullup
pinMode
(
ROT_A
,
INPUT
);
digitalWrite
(
ROT_A
,
HIGH
);
// turn on weak pullup
pinMode
(
ROT_SW
,
INPUT
);
// The rotary switch is common anode with external pulldown, do not turn on pullup
// pinMode(MP3_DREQ, INPUT);
pinMode
(
ROT_LEDB
,
OUTPUT
);
pinMode
(
ROT_LEDG
,
OUTPUT
);
// pinMode(MP3_DCS, OUTPUT);
// pinMode(MP3_RST, OUTPUT);
pinMode
(
ROT_LEDR
,
OUTPUT
);
// pinMode(SD_CS, OUTPUT);
// pinMode(MOSI, OUTPUT);
// pinMode(MISO, INPUT);
// pinMode(SCK, OUTPUT);
//digitalWrite(SHDN_GPIO1, LOW); // Shut down Amplifier chip
//digitalWrite(MP3_RST, LOW); // Shut down MP3 chip
setLED
(
OFF
);
Serial
.
begin
(
9600
);
// Use serial for debugging
Serial
.
println
(
"rotary encoder testing"
);
// We use the standard external interrupt pin for the rotary,
// but we'll use the pin change interrupt library for the button.
attachInterrupt
(
1
,
rotaryIRQ
,
CHANGE
);
PCintPort
::
attachInterrupt
(
ROT_SW
,
&
buttonIRQ
,
CHANGE
);
}
void
buttonIRQ
()
{
// Process rotary encoder button presses and releases, including
// debouncing (extra "presses" from noisy switch contacts).
// If button is pressed, the button_pressed flag is set to true.
// (Manually set this to false after handling the change.)
// If button is released, the button_released flag is set to true,
// and button_downtime will contain the duration of the button
// press in ms. (Set this to false after handling the change.)
// Raw information from PinChangeInt library:
// Serial.print("pin: ");
// Serial.print(PCintPort::arduinoPin);
// Serial.print(" state: ");
// Serial.println(PCintPort::pinState);
static
boolean
button_state
=
false
;
static
unsigned
long
start
,
end
;
if
((
PCintPort
::
pinState
==
HIGH
)
&&
(
button_state
==
false
))
// Button was up, but is currently being pressed down
{
// Discard button presses too close together (debounce)
start
=
millis
();
if
(
start
>
(
end
+
10
))
// 10ms debounce timer
{
button_state
=
true
;
button_pressed
=
true
;
}
}
else
if
((
PCintPort
::
pinState
==
LOW
)
&&
(
button_state
==
true
))
// Button was down, but has just been released
{
// Discard button releases too close together (debounce)
end
=
millis
();
if
(
end
>
(
start
+
10
))
// 10ms debounce timer
{
button_state
=
false
;
button_released
=
true
;
button_downtime
=
end
-
start
;
}
}
}
void
rotaryIRQ
()
{
// Process input from the rotary encoder.
// The rotary "position" is held in rotary_counter, increasing for CW rotation (changes by one per detent).
// If the position changes, rotary_change will be set true. (You may manually set this to false after handling the change).
// This function will automatically run when rotary encoder input A transitions in either direction (low to high or high to low)
// By saving the state of the A and B pins through two interrupts, we'll determine the direction of rotation
// int rotary_counter will be updated with the new value, and boolean rotary_change will be true if there was a value change
// Based on concepts from Oleg at circuits@home (http://www.circuitsathome.com/mcu/rotary-encoder-interrupt-service-routine-for-avr-micros)
// Unlike Oleg's original code, this code uses only one interrupt and has only two transition states;
// it has less resolution but needs only one interrupt, is very smooth, and handles switchbounce well.
static
unsigned
char
rotary_state
=
0
;
// current and previous encoder states
rotary_state
<<=
2
;
// remember previous state
rotary_state
|=
(
digitalRead
(
ROT_A
)
|
(
digitalRead
(
ROT_B
)
<<
1
));
// mask in current state
rotary_state
&=
0x0F
;
// zero upper nybble
//Serial.println(rotary_state,HEX);
if
(
rotary_state
==
0x09
)
// from 10 to 01, increment counter. Also try 0x06 if unreliable
{
rotary_counter
++
;
rotary_change
=
true
;
}
else
if
(
rotary_state
==
0x03
)
// from 00 to 11, decrement counter. Also try 0x0C if unreliable
{
rotary_counter
--
;
rotary_change
=
true
;
}
}
void
loop
()
{
// "Static" variables are initalized once the first time
// that loop runs, but they keep their values through
// successive loops.
static
unsigned
char
x
=
0
;
static
boolean
button_down
=
false
;
static
unsigned
long
int
button_down_start
,
button_down_time
;