This is my enhanced code for a daylight alarm on Arduino UNO with an added MP3-Player. The device is supposed to sleep all the time except when I hit the play button (then it is supposed to play music) or when the RTC wakes it up, both via interrupt. When the RTC wakes it up it will start its actual daylight alarm routine.
I just implemented the sleep/power-down code and got it working so that I could wake it up and put it to sleep with pins 9 (sleep) and 2 (wake up via interrupt). There was a problem though and I had to change the code.
Apparently while trying to fix it I broke something. The current behiour upon startup is: 1. Go to sleep (correct) 2. When I bridge pin 2 and ground, it wakes up. (correct) 3. When I then bridge pin 9 and ground it goes to sleep. (correct). 4. When I bridge pin 2 and ground again it does not wake up again.
I have changed the code so that in addition to playing music the builtin LED will light up.
#include <avr/sleep.h>
/************ init mp3-player ***************/
#include <SoftwareSerial.h>
#define ARDUINO_RX 4 //should connect to TX of the Serial MP3 Player module
#define ARDUINO_TX 5 //connect to RX of the module
SoftwareSerial mp3(ARDUINO_RX, ARDUINO_TX);
static int8_t Send_buf[8] = {0}; // Buffer for Send commands. // BETTER LOCALLY
String sbyte2hex(uint8_t b);
#define CMD_SLEEP_MODE 0X0A
#define CMD_WAKE_UP 0X0B
#define CMD_SEL_DEV 0X09
#define CMD_PLAY 0X0D
#define CMD_STOP_PLAY 0X16 // Stop playing continuously.
#define CMD_FOLDER_CYCLE 0X17
#define CMD_SET_DAC 0X1A
#define DAC_ON 0X00
#define DAC_OFF 0X01
#define DEV_TF 0X02
/**************** init the real time clock ***************/
#include <Rtc_Pcf8563.h>
Rtc_Pcf8563 rtc;
/**************** setup pins & buttons ***************/
const byte led = 11; // Pin LED is connected to
const byte sixAmPin = 6; // Pin for set-alarm-to-6am-button
const byte sevenAmPin = 7; // Pin for set-alarm-to-7am-button
const byte eightAmPin = 8; // Pin for set-alarm-to-8am-button
const byte stopPin = 9; // Pin for stop button
const byte timeResetPin = 10; // Pin for reset-clock-to-9am-button (useful e.g. after battery failure)
const byte playPin = 2; // Pin for play-music-button (and interrupt!)
const byte rtcIntPin = 3; // Pin for RTC interrupt
byte sixAmButton = 1; // State of 6am-set-button
byte sevenAmButton = 1; // State of 7am-set-button
byte eightAmButton = 1; // State of 8am-set-button
byte stopButton = 1; // State of stopButton
byte timeResetButton = 1; // State of time-set-button
byte playButton = 1; // State of play-music-button
byte brightness = 0; // LED brightness
bool wakeupMode = false;
unsigned long prevStepTime = millis();
unsigned long time;
/*************** Changeable variables here **************/
byte setHour = 6;
byte setMin = 30;
byte fadeDuration = 30; // Duration of fade in minutes (default: 30)
byte afterBurn = 30; // Keep light on after alarm for this many minutes (default: 30)
/********************************************************/
unsigned long keepLight = afterBurn * 60000UL; // Calculate time to keep LED on after fade (in ms)
int fadeStepLength = fadeDuration * 60000 / 255; // Calculate step duration for increasing LED brightness (in ms) (default: fadeDuration * 60000 / 255)
void setup() {
/*DEBUG*/
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, HIGH);
/*DEBUG END*/
// Serial.begin(9600); //uncomment after testing
mp3.begin(9600);
delay(500);
sendCommand(CMD_SEL_DEV, 0, DEV_TF);
delay(500);
// declare LED pin to be an output:
pinMode(led, OUTPUT);
// declare button pins as inputs:
pinMode(stopPin, INPUT_PULLUP);
pinMode(sixAmPin, INPUT_PULLUP);
pinMode(sevenAmPin, INPUT_PULLUP);
pinMode(eightAmPin, INPUT_PULLUP);
pinMode(timeResetPin, INPUT_PULLUP);
pinMode(playPin, INPUT_PULLUP);
pinMode(rtcIntPin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(playPin), wakeUpPlay, FALLING);
attachInterrupt(digitalPinToInterrupt(rtcIntPin), wakeAlarm, FALLING);
}
void loop() {
goToSleep();
}
void wakeup() {
// If wake-up-mode is true and brightness < 255, add +1 to brightness every 7 seconds (256 steps)
wakeupMode = true;
while (wakeupMode == true) {
//update clock
time = millis();
// If current time is wakeup-time, increase LED brightness slowly over the course of 30 minutes
if (brightness < 255 ) {
// Delay brightening in steps. Do only if interval has passed.
if (time > prevStepTime + fadeStepLength) {
brightness ++;
prevStepTime = millis(); // Resets counter to restart interval
}
}
// Turn off light and exit wakupMode x minutes after max brightness
else if (brightness == 255 && time > prevStepTime + keepLight) {
brightness = 0;
wakeupMode = false; // Exit wakeupMode loop
}
readButtons(); // Check for button input
analogWrite(led, brightness); // Set LED brightness accordingly
}
goToSleep;
}
void readButtons() {
// Always run this:
// Check if alarm gets set for 6, 7 or 8am
sixAmButton = digitalRead(sixAmPin);
if (sixAmButton == LOW) {
rtc.setAlarm(5, 30, 99, 99);
}
sevenAmButton = digitalRead(sevenAmPin);
if (sevenAmButton == LOW) {
rtc.setAlarm(6, 30, 99, 99);
}
eightAmButton = digitalRead(eightAmPin);
if (eightAmButton == LOW) {
rtc.setAlarm(7, 30, 99, 99);
}
// If stopButton is pressed: stop playing music, turn off LED, sleep mp3-player, sleep arduino
stopButton = digitalRead(stopPin);
if (stopButton == LOW) {
wakeupMode = false;
brightness = 0; // uncomment after testing
analogWrite(led, brightness); // Set LED brightness accordingly
sendCommand(CMD_STOP_PLAY);
sendCommand(CMD_SLEEP_MODE);
delay(200);
goToSleep();
}
// If timeResetButton is pressed, reset RTC to 9am
if (timeResetButton == LOW) {
rtc.setTime(9, 0, 0);
}
// If Play music button is pressed, start playing music
playButton = digitalRead(playPin);
if (playButton == LOW) {
playMusic();
}
}
void playMusic(){
digitalWrite(LED_BUILTIN, HIGH);
sendCommand(CMD_WAKE_UP);
delay(200);
sendCommand(CMD_FOLDER_CYCLE, 1, 0);
while (1){
readButtons();
}
}
void wakeUpPlay(){
sleep_disable();
detachInterrupt(digitalPinToInterrupt(playPin));
detachInterrupt(digitalPinToInterrupt(rtcIntPin));
playMusic();
}
void wakeAlarm(){
sleep_disable();
detachInterrupt(digitalPinToInterrupt(playPin));
detachInterrupt(digitalPinToInterrupt(rtcIntPin));
wakeup();
}
void goToSleep() {
sleep_enable();
attachInterrupt(digitalPinToInterrupt(playPin), wakeUpPlay, FALLING);
attachInterrupt(digitalPinToInterrupt(rtcIntPin), wakeAlarm, FALLING);
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
digitalWrite(LED_BUILTIN, LOW);
delay(500);
sleep_cpu();
}
/**************************/
/** Stuff for MP3 player **/
/**************************/
/********************************************************************************/
/*Function: Send command to the MP3 */
/*Parameter: byte command */
/*Parameter: byte dat1 parameter for the command */
/*Parameter: byte dat2 parameter for the command */
void sendCommand(byte command){
sendCommand(command, 0, 0);
}
void sendCommand(byte command, byte dat1, byte dat2){
delay(20);
Send_buf[0] = 0x7E; //
Send_buf[1] = 0xFF; //
Send_buf[2] = 0x06; // Len
Send_buf[3] = command; //
Send_buf[4] = 0x01; // 0x00 NO, 0x01 feedback
Send_buf[5] = dat1; // datah
Send_buf[6] = dat2; // datal
Send_buf[7] = 0xEF; //
Serial.print("Sending: ");
for (uint8_t i = 0; i < 8; i++)
{
mp3.write(Send_buf[i]) ;
Serial.print(sbyte2hex(Send_buf[i]));
}
Serial.println();
}
/********************************************************************************/
/*Function: sbyte2hex. Returns a byte data in HEX format. */
/*Parameter:- uint8_t b. Byte to convert to HEX. */
/*Return: String */
String sbyte2hex(uint8_t b)
{
String shex;
shex = "0X";
if (b < 16) shex += "0";
shex += String(b, HEX);
shex += " ";
return shex;
}
/********************************************************************************/
/*Function: shex2int. Returns a int from an HEX string. */
/*Parameter: s. char *s to convert to HEX. */
/*Parameter: n. char *s' length. */
/*Return: int */
int shex2int(char *s, int n){
int r = 0;
for (int i=0; i<n; i++){
if(s[i]>='0' && s[i]<='9'){
r *= 16;
r +=s[i]-'0';
}else if(s[i]>='A' && s[i]<='F'){
r *= 16;
r += (s[i] - 'A') + 10;
}
}
return r;
}
I can only imagine that the problem lies in the way I send Arduino to sleep when playing music (i.e. the way I call goToSleep(); from the wakeUpPlay()-class). Waking up from sleep does work when sleep was induced from the main loop (apparently). Do you have any idea what is wrong? (I thought about reducing my code to the bare minimum so it is less confusing for you - but then I'd probably change too much to find the bug).