Hackster is hosting Hackster Holidays, Finale: Livestream & Giveaway Drawing. Watch previous episodes or stream live on Tuesday!Stream Hackster Holidays, Finale on Tuesday!
Jiří Praus
Published © CC BY-NC-SA

Kids' Wooden Radio

Small and handy radio for your little ones. Let them play their favorite songs or fairytales. And that all in the wooden box!

IntermediateFull instructions provided6 hours12,607
Kids' Wooden Radio

Things used in this project

Hardware components

Arduino Nano R3
Arduino Nano R3
×1
DFRobot DFPlayer Mini
×1

Story

Read more

Custom parts and enclosures

Radio Wooden Parts

Schematics

radio_bb_RTQua8fhRw.png

Code

radio.ino

Arduino
Radio Source Code for Arduino
#include "Arduino.h"
#include "SoftwareSerial.h"
#include "DFRobotDFPlayerMini.h"
#include <Adafruit_NeoPixel.h>

#define BUTTON_1 A2 // yellow left
#define BUTTON_2 A1 // yellow right
#define BUTTON_3 A3 // red left
#define BUTTON_4 A0 // red right
#define BUTTON_5 A4 // blue left
#define BUTTON_6 2 // blue right
#define BUTTON_7 3 // black

#define BUTTONS_COUNT 7

#define BUTTON_RELEASED 0
#define BUTTON_PRESSED 1
#define BUTTON_HANDLED 2

byte buttonPins[] = {BUTTON_1, BUTTON_2, BUTTON_3, BUTTON_4, BUTTON_5, BUTTON_6, BUTTON_7};
byte buttonState[] = {0, 0, 0, 0, 0, 0, 0};

#define NEOPIXEL_PIN 9
#define RED 0
#define GREEN 1
#define BLUE 2

float currentRGB[] = {0, 0, 0};
float changeRGB[] = {0, 0, 0};
byte newRGB[] = {0, 0, 0};

Adafruit_NeoPixel pixels = Adafruit_NeoPixel(4, NEOPIXEL_PIN, NEO_GRB + NEO_KHZ400);
SoftwareSerial playerSerial(7, 6); // RX, TX
DFRobotDFPlayerMini player;

#define FOLDER_RED 0
#define FOLDER_BLUE 1
#define FOLDER_YELLOW 2

byte currentSong[] = {0, 0, 0}; // 1 to size of folder
byte folderSizes[] = {0, 0, 0};
byte volume = 5;
byte lightIntensity = 0;

void setup() {
  randomSeed(analogRead(A7));
  playerSerial.begin(9600);
  Serial.begin(115200);
  pixels.begin();
  pixelsUnifiedColor(0);

  for (int i = 0; i < BUTTONS_COUNT; i++) {
    pinMode(buttonPins[i], INPUT_PULLUP);
    buttonState[i] = BUTTON_RELEASED;
  }
  
  Serial.println();
  Serial.println(F("DFRobot DFPlayer Mini Demo"));
  Serial.println(F("Initializing DFPlayer ... (May take 3~5 seconds)"));
  
  if (!player.begin(playerSerial)) {  //Use softwareSerial to communicate with mp3.
    Serial.println(F("Unable to begin:"));
    Serial.println(F("1.Please recheck the connection!"));
    Serial.println(F("2.Please insert the SD card!"));
    while(true);
  }
  Serial.println(F("DFPlayer Mini online."));

  //player.EQ(DFPLAYER_EQ_ROCK);
  player.outputDevice(DFPLAYER_DEVICE_SD);
  player.volume(volume);
  //player.play(1);

  folderSizes[FOLDER_RED] = player.readFileCountsInFolder(FOLDER_RED + 1);
  folderSizes[FOLDER_BLUE] = player.readFileCountsInFolder(FOLDER_BLUE + 1);
  folderSizes[FOLDER_YELLOW] = player.readFileCountsInFolder(FOLDER_YELLOW + 1);
  Serial.println(F("Radio ready."));
}

void loop() {  
  if (player.available()) {
    printDetail(player.readType(), player.read()); //Print the detail message from DFPlayer to handle different errors and states.
  }

  readButtons();
  crossFade();
  delay(15);
}

void readButtons() {
  for (int i = 0; i < BUTTONS_COUNT; i++) {
    if (digitalRead(buttonPins[i]) == HIGH) {
      buttonState[i] = BUTTON_RELEASED;
    }
    else if (buttonState[i] == BUTTON_RELEASED) {
      buttonState[i] = BUTTON_PRESSED;
    }
  }

  if (buttonState[0] == BUTTON_PRESSED) { // yellow left
    buttonState[0] = BUTTON_HANDLED;
    playNextInFolder(FOLDER_YELLOW);
  }
  else if (buttonState[1] == BUTTON_PRESSED) { // yellow right
    buttonState[1] = BUTTON_HANDLED;
    playPreviousInFolder(FOLDER_YELLOW);
  }
  else if (buttonState[2] == BUTTON_PRESSED) { // red left
    buttonState[2] = BUTTON_HANDLED;
    playNextInFolder(FOLDER_RED);
  }
  else if (buttonState[3] == BUTTON_PRESSED) { // red right
    buttonState[3] = BUTTON_HANDLED;
    playPreviousInFolder(FOLDER_RED);
  }
  else if (buttonState[4] == BUTTON_PRESSED) { // blue left
    buttonState[4] = BUTTON_HANDLED;
    playNextInFolder(FOLDER_BLUE);
  }
  else if (buttonState[5] == BUTTON_PRESSED) { // blue right
    buttonState[5] = BUTTON_HANDLED;
    playPreviousInFolder(FOLDER_BLUE);
  }
  else if (buttonState[6] == BUTTON_PRESSED) { // black
    volume = volume >= 15 ? 5 : volume + 5;
    player.volume(volume);
    buttonState[6] = BUTTON_HANDLED;
  }
}

void playNextInFolder(byte folder) {
  currentSong[folder]++;
  if (currentSong[folder] > folderSizes[folder]) {
    currentSong[folder] = 1;
  }
  player.playFolder(folder + 1, currentSong[folder]);
}

void playPreviousInFolder(byte folder) {
  currentSong[folder]--;
  if (currentSong[folder] <= 0) {
    currentSong[folder] = folderSizes[folder];
  }
  player.playFolder(folder + 1, currentSong[folder]);
}

void printDetail(uint8_t type, int value){
  switch (type) {
    case TimeOut:
      Serial.println(F("Time Out!"));
      break;
    case WrongStack:
      Serial.println(F("Stack Wrong!"));
      break;
    case DFPlayerCardInserted:
      Serial.println(F("Card Inserted!"));
      break;
    case DFPlayerCardRemoved:
      Serial.println(F("Card Removed!"));
      break;
    case DFPlayerCardOnline:
      Serial.println(F("Card Online!"));
      break;
    case DFPlayerPlayFinished:
      Serial.print(F("Number:"));
      Serial.print(value);
      Serial.println(F(" Play Finished!"));
      break;
    case DFPlayerError:
      Serial.print(F("DFPlayerError:"));
      switch (value) {
        case Busy:
          Serial.println(F("Card not found"));
          break;
        case Sleeping:
          Serial.println(F("Sleeping"));
          break;
        case SerialWrongStack:
          Serial.println(F("Get Wrong Stack"));
          break;
        case CheckSumNotMatch:
          Serial.println(F("Check Sum Not Match"));
          break;
        case FileIndexOut:
          Serial.println(F("File Index Out of Bound"));
          break;
        case FileMismatch:
          Serial.println(F("Cannot Find File"));
          break;
        case Advertise:
          Serial.println(F("In Advertise"));
          break;
        default:
          break;
      }
      break;
    default:
      break;
  }
}

void prepareCrossFade(byte red, byte green, byte blue, unsigned int duration) {
  float rchange = red - currentRGB[RED];
  float gchange = green - currentRGB[GREEN];
  float bchange = blue - currentRGB[BLUE];

  changeRGB[RED] = rchange / (float) duration;
  changeRGB[GREEN] = gchange / (float) duration;
  changeRGB[BLUE] = bchange / (float) duration;

  newRGB[RED] = red;
  newRGB[GREEN] = green;
  newRGB[BLUE] = blue;

  Serial.print(newRGB[RED]);
  Serial.print(" ");
  Serial.print(newRGB[GREEN]);
  Serial.print(" ");
  Serial.print(newRGB[BLUE]);
  Serial.print(" (");
  Serial.print(changeRGB[RED]);
  Serial.print(" ");
  Serial.print(changeRGB[GREEN]);
  Serial.print(" ");
  Serial.print(changeRGB[BLUE]);
  Serial.println(")");
}

boolean crossFade() {
  if (currentRGB[RED] == newRGB[RED] && currentRGB[GREEN] == newRGB[GREEN] && currentRGB[BLUE] == newRGB[BLUE]) {
    return true;
  }
  for (byte i = 0; i < 3; i++) {
    if (changeRGB[i] > 0 && currentRGB[i] < newRGB[i]) {
      currentRGB[i] = currentRGB[i] + changeRGB[i];
    }
    else if (changeRGB[i] < 0 && currentRGB[i] > newRGB[i]) {
      currentRGB[i] = currentRGB[i] + changeRGB[i];
    }
    else {
      currentRGB[i] = newRGB[i];
    }
  }
  pixelsUnifiedColor(pixels.Color(currentRGB[RED], currentRGB[GREEN], currentRGB[BLUE]));
  return false;
}

void pixelsUnifiedColor(uint32_t color) {
  for (unsigned int i = 0; i < pixels.numPixels(); i++) {
    pixels.setPixelColor(i, color);
  }
  pixels.show();
}

void rainbow(int j) {
  uint16_t i;
  byte num = pixels.numPixels() - 1;
  pixels.setPixelColor(pixels.numPixels() - 1, 100, 100, 100);

  for (i = 0; i < num; i++) {
    pixels.setPixelColor(i, colorWheel(((i * 256 / num) + j) & 255));
  }
  pixels.show();
}

uint32_t colorWheel(byte wheelPos) {
  // Input a value 0 to 255 to get a color value.
  // The colours are a transition r - g - b - back to r.
  wheelPos = 255 - wheelPos;
  if (wheelPos < 85) {
    return pixels.Color(255 - wheelPos * 3, 0, wheelPos * 3);
  }
  if (wheelPos < 170) {
    wheelPos -= 85;
    return pixels.Color(0, wheelPos * 3, 255 - wheelPos * 3);
  }
  wheelPos -= 170;
  return pixels.Color(wheelPos * 3, 255 - wheelPos * 3, 0);
}

Credits

Jiří Praus
10 projects • 204 followers
Developer for Samepage.io and hardware maker. I started with a simple Arduino kit two years ago and I fell in love with the platform.

Comments