Final Project Documentation Alex_Lewis


Fliqz has shut down their service. To access this video, email support with this video id: b669db8f4fff456690657828f650291b
a at a minimum, to post your design point of view (what are you designing a player for?), your Verplank diagram, photos of your paper prototype, your state diagram, your project code, and a video of the final working player in use.

 

Design Point of View- My design point of view was the make a MP3 player that would sit on a desk and be able to combine a model of the enterprise, a desk lamp, and a speaker. I wanted to make something that both looks cool and is very functional. I wanted it to alos be mobile so it would not rely on a wall outlet to play music or light a place up with it s big LEDs. 

 

 

#include <SD.h>

#include <EEPROM.h>

 

#include <mp3.h>

#include <mp3conf.h>

 

// include the adafruit pcd8544 & gfx libraries for a nokia 5110 graphic lcd.

 

#include <Adafruit_GFX.h>

#include <Adafruit_PCD8544.h>

 

// setup microsd and decoder chip select pins, and the decoder-specific pins.

 

#define sd_cs         17        // 'chip select' line for the microsd card

 

#define mp3_cs        A0        // 'command chip select' connect to cs pin

#define mp3_dcs       A1        // 'data chip select' connect to bsync pin

#define mp3_rst       -1        // 'reset' connects to decoder's reset pin

#define mp3_dreq      A2        // 'data request line' connect to dreq pin

 

// now assign pins for the graphic lcd (carried over from the etch-a-sketch).

 

#define lcd_clk        7        // 'serial clock' connect to lcd's clk pin

#define lcd_din        6        // 'serial data input' connects to din pin

#define lcd_dc         5        // 'data/command input' connect to d/c pin

#define lcd_cs        -1        // 'slave chip select' connects to  cs pin

#define lcd_rst        4        // 'reset' connects to graphic lcd rst pin

 

// 'read_buffer' is the amount of data read from microsd and sent to decoder.

// it's probably best to keep this a factor of 2, up to about 1kb (2kb is the

// max). you might change this if you experienced skips during song playback.

 

#define read_buffer  512        // size (bytes) of the microsd read buffer

#define mp3_vol      175        // default volume. range min=0 and max=254

 

// file names are 13 bytes max (8 + '.' + 3 + '\0'), and the file list should

// fit into the eeprom. for example, 13 * 40 = 520 bytes of eeprom are needed

// to store a list of 40 songs. if you use shorter file names, or if your mcu

// has more eeprom, you can change these.

 

#define max_name_len  13

#define max_num_songs 40

 

// id3v2 tags have variable-length song titles. that length is indicated in 4

// bytes within the tag. id3v1 tags also have variable-length song titles, up

// to 30 bytes maximum, but the length is not indicated within the tag. using

// 60 bytes here is a compromise between holding most titles and saving sram.

 

// if you increase this above 255, look for and change 'for' loop index types

// so as to not to overflow the unsigned char data type.

 

#define max_title_len 60

 

// ---- global variables ----------------------------------------------------

 

// instantiate a graphic lcd object using the pins that we #define'd earlier.

// comment out the graphics lines to save memory if you're not using the lcd.

 

Adafruit_PCD8544 lcd = Adafruit_PCD8544(lcd_clk, lcd_din, lcd_dc, lcd_cs, lcd_rst);

 

// 'File' is a wrapper of the 'SdFile' data type from the sd utility library.

 

File sd_file;                   // object to represent a file on a microsd

 

// store the number of songs in this directory, and the current song to play.

 

unsigned char num_songs = 0, current_song = 0;

 

// an array to hold the current_song's file name in ram. every file's name is

// stored longer-term in the eeprom. this array is used in 'sd_file.open()'.

 

char fn[max_name_len];

 

// an array to hold the current_song's title in ram. it needs 1 extra char to

// hold the '\0' that indicates the end of a character string. the song title

// is found in 'get_title_from_id3tag()'.

 

char title[max_title_len + 1];

 

// the program runs as a state machine. the 'state' enum includes the states.

// 'current_state' is the default as the program starts. add new states here.

 

enum state { DIR_PLAY, MP3_PLAY, PAUSED };

state current_state = DIR_PLAY;

 

//---- module functions -----------------------------------------------------

 

// you must open a song file that you want to play using 'sd_file_open' prior

// to fetching song data from the file. you can only open one file at a time.

 

void sd_file_open() {  

  // first, find the file name (that's stored in eeprom) of the current song.

 

  get_current_song_as_fn();

 

  // then open the file using the name we just found (stored in 'fn' global).

 

  sd_file = SD.open(fn, FILE_READ);

 

  // find the current song's title tag (if present) then print it to the lcd. 

 

  print_title_to_lcd();

}

 

// read a number of bytes from the microsd card, then forward them to the Mp3

// library's 'play' function, which streams them out to the decoder chip.

 

void mp3_play() {

  unsigned char bytes[read_buffer]; // buffer to read and send to the decoder

  unsigned int bytes_to_read;       // number of bytes read from microsd card

 

  // first fill the 'bytes' buffer with (up to) 'read_buffer' count of bytes.

  // that happens through the 'sd_file.read()' call, which returns the actual

  // number of bytes that were read (which can be fewer than 'read_buffer' if

  // at the end of the file). then send the retrieved bytes out to be played.

 

  // 'sd_file.read()' manages the index pointer into the file and knows where

  // to start reading the next batch of bytes. 'Mp3.play()' manages the index

  // pointer into the 'bytes' buffer and knows how to send it to the decoder.

 

  bytes_to_read = sd_file.read(bytes, read_buffer);

  Mp3.play(bytes, bytes_to_read);

 

  // 'bytes_to_read' is only smaller than 'read_buffer' when the song's over.

  buttonState = digitalRead(buttonPin);

  if(buttonState == HIGH){

      state = 1;

  }

 

  if( state == 1){

    while(true){

      delay(100);

      buttonState =  digitalRead(buttonPin);

      if(buttonState == HIGH){

        delay(100);

        break;

  if (bytes_to_read < read_buffer) {

    sd_file.close();

 

    // if we've been in the MP3_PLAY state, then we want to pause the player.

 

    if (current_state == MP3_PLAY) {

      current_state == PAUSED;

    }

  }

}

 

// continue to play the current (playing) song, until there are no more songs

// in the directory to play. 2 other sd library methods (that we haven't used

// here) can help track your progress while playing songs: 'sd_file.size()' &

// 'sd_file.position()'. you can use these to show say, the percent of a song

// that has already played.

 

void dir_play() {

  if (sd_file) {

    mp3_play();

  }

  else {

    // since 'sd_file' isn't open, the recently playing song must have ended.

    // increment the index, and open the next song, unless it's the last song

    // in the directory. in that case, just set the state to PAUSED.

 

    if (current_song < (num_songs - 1)) {

      current_song++;

      sd_file_open();

 

    }

    else {

      current_state = PAUSED;

    }

  }

}   

 

// ---- setup and loop ------------------------------------------------------

 

// setup is pretty straightforward. initialize serial communication (used for

// the following error messages), mp3 library, microsd card objects, then the

// graphic lcd. then open the first song in the root library to play.

 

void setup() {

  // if using a graphic lcd, initialize with contrast, then setup the screen.

 

  lcd.begin(50);

  lcd.print("Barebones Mp3!");

  lcd.display();

 

  // initialize the mp3 library, and set default volume. 'mp3_cs' is the chip

  // select, 'dcs' is data chip select, 'rst' is reset and 'dreq' is the data

  // request. the decoder sets the 'dreq' line (automatically) to signal that

  // its input buffer can accommodate 32 more bytes of incoming song data.

 

  // the decoder's default state prevents the spi bus from working with other

  // spi devices, so we initialize it first.

 

  Mp3.begin(mp3_cs, mp3_dcs, mp3_rst, mp3_dreq);

  Mp3.volume(mp3_vol);

 

  // initialize the microsd (which checks the card, volume and root objects).

 

  sd_card_setup();

 

  // putting all of the root directory's songs into eeprom saves flash space.

 

  sd_dir_setup();

 

  // the program is setup to enter DIR_PLAY mode immediately, so this call to

  // open the root directory before reaching the state machine is needed.

 

  sd_file_open();

}

 

// the state machine is setup (at least, at first) to open the microsd card's

// root directory, play all of the songs within it, close the root directory,

// and then stop playing. change these, or add new actions here.

 

// the DIR_PLAY state plays all of the songs in a directory and then switches

// into PAUSED when done. the MP3_PLAY state plays one specific song and then

// switches into PAUSED. this sample player doesn't enter the MP3_PLAY state,

// as its goal (for now) is just to play all the songs. you can change that.

 

void loop() {

  switch(current_state) {

 

    case DIR_PLAY:

      dir_play();

      break;

 

    case MP3_PLAY:

      mp3_play();

      break;

 

    case PAUSED:

      break;

  }

}

 

 

 

IMG_0459.MOV