This is an old revision of the document!
Pentru a adăuga un strop de culoare și dinamsim, în ambele moduri, pe ecranul OLED se vor afișa mici animații, care vor alterna constant si vor fi randomizate in modul music player.
Lista piese:
Schema electrică:
Descriere pini:
Mediu de dezvoltare:
Biblioteci:
#include <SD.h> #include <TMRpcm.h> #include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h> #include <SPI.h> #include "Animations.h"
Configurari si variabile globale:
Pentru display, am initializat o instanta a clasei Adafruit_SSD1306, aceasta este variabila care controleaza display-ul. De asemenea, am setat si variabilele de measurements, precum viteza de redare a frame-urilor, latimea si lungimea animatiei in ecran si o variabila currentAnimation, care va stoca o referinta la o animatie aleasa random, pentru partea de music player.
#define SCREEN_I2C_ADDR 0x3C // or 0x3C #define SCREEN_WIDTH 128 // OLED display width, in pixels #define SCREEN_HEIGHT 64 // OLED display height, in pixels #define OLED_RST_PIN -1 // Reset pin (-1 if not available) Adafruit_SSD1306 display(128, 64, &Wire, OLED_RST_PIN); #define FRAME_DELAY (42) #define FRAME_WIDTH (48) #define FRAME_HEIGHT (48) #define FRAME_COUNT (sizeof(recording) / sizeof(recording[0])) const byte (*currentAnimation)[288]; int frame = 0; int frame_music = 0;
Pentru partea de redare a audio-urilor, am setat variabilele necesare butoanelor, pentru controlarea audio-ului (setarea calitatii audiolui, a volumului, porninrea si oprirea acestuia), a directorului in care se afla fisierele .wav si doua variabile care stocheaza numarul de audio-uri si indexul melodiei curente, incepand de la 1.
#define SD_CS_PIN 53 #define SPEAKER_PIN 46 #define PREV_PIN 7 #define PLAY_PIN 6 #define NEXT_PIN 5 #define FILENAME_SIZE 20 TMRpcm audio; File root; int numSongs = 0; int songIdx = 1;
Alte variabile initializate au legatura cu partea de inregistrare a vocii, de la butoanele de control, pana la doua variabile bool care blocheaza folosirea inermitenta a celor doua moduri de functionare.
int rec=2; int play=3; int button_rec=8; int button_play=9; bool music_player_on = false; bool recording_on = false;
Setup:
void setup() { // MUSIC PLAYER PART Serial.begin(9600); // initialize buttons pinMode(PREV_PIN, INPUT_PULLUP); pinMode(PLAY_PIN, INPUT_PULLUP); pinMode(NEXT_PIN, INPUT_PULLUP); Serial.print(F("Initializing SD card...")); // check if card is initialized correctly if (!SD.begin(SD_CS_PIN)) { Serial.println(F("Failed to initialize SD card")); while(true); // stay here. } Serial.println("SD card is OK!"); // open the directory and count the number of .wav/.WAV files root = SD.open("/"); Serial.print(F("Number of .wav files: ")); numSongs = numberAudios(root); Serial.println(numSongs); // set audio audio.speakerPin = SPEAKER_PIN; audio.setVolume(6); audio.quality(0); audio.stopPlayback(); // ISD + DISPLAY PART pinMode(rec,OUTPUT); pinMode(play,OUTPUT); pinMode(button_rec,INPUT_PULLUP); pinMode(button_play,INPUT_PULLUP); // init display display.begin(SSD1306_SWITCHCAPVCC, SCREEN_I2C_ADDR); display.clearDisplay(); display.display(); // init isd digitalWrite(rec,LOW); digitalWrite(play,LOW); // check if any button is pressed at start point, // wait for them to not be pressed, helps for debouncing if (digitalRead(button_rec) == LOW) { while (digitalRead(button_rec) == LOW); } if (digitalRead(button_play) == LOW) { while (digitalRead(button_play) == LOW); } if (digitalRead(PREV_PIN) == LOW) { while (digitalRead(PREV_PIN) == LOW); } if (digitalRead(PLAY_PIN) == LOW) { while (digitalRead(PLAY_PIN) == LOW); } if (digitalRead(NEXT_PIN) == LOW) { while (digitalRead(NEXT_PIN) == LOW); } // for random animations randomSeed(analogRead(0)); }
Pentru cititorul de card SD, am formatat cardul de 1GB in format FAT, iar fisierele le-am convertit in format .wav cu setarile: Samples Per second (Hz): 16000, Channel: Mono, Bits Per Sample: 8PCM, format: PCM unsigned 8-bit.
Implementare:
Functia loop():
void loop() { // put your main code here, to run repeatedly: int prevState = digitalRead(PREV_PIN); int playState = digitalRead(PLAY_PIN); int nextState = digitalRead(NEXT_PIN); // MUSIC PLAYER BUTTONS if (recording_on == false) { if (prevState == LOW) { // debounce delay(100); if (songIdx == 1) { playAudio(numSongs); } else { playAudio(songIdx - 1); } music_player_on = true; selectRandomAnimation(); updateAnimation(); } else if (playState == LOW) { // debounce delay(100); if (audio.isPlaying()) { if(music_player_on) { audio.pause(); music_player_on = false; stopAnimation(); } else { audio.pause(); music_player_on = true; updateAnimation(); } } else { playAudio(songIdx); music_player_on = true; selectRandomAnimation(); updateAnimation(); } } else if (nextState == LOW) { // debounce delay(100); if (songIdx == numSongs) { playAudio(1); } else { playAudio(songIdx + 1); } music_player_on = true; selectRandomAnimation(); updateAnimation(); } } // ISD BUTTONS if (music_player_on == false) { if (digitalRead(button_rec) == LOW) { digitalWrite(rec, HIGH); recording_on = true; while (digitalRead(button_rec) == LOW) { display.clearDisplay(); display.drawBitmap(40, 8, recording[frame], FRAME_WIDTH, FRAME_HEIGHT, 1); display.display(); frame = (frame + 1) % FRAME_COUNT; delay(FRAME_DELAY); } digitalWrite(rec, LOW); recording_on = false; delay(50); // Debounce delay display.clearDisplay(); display.display(); } else if (digitalRead(button_play) == LOW) { digitalWrite(play, HIGH); while (digitalRead(button_play) == LOW) { delay(10); } unsigned long startTime = millis(); unsigned long playbackDuration = 4000; while (millis() - startTime < playbackDuration) { display.clearDisplay(); display.drawBitmap(40, 8, talking[frame], FRAME_WIDTH, FRAME_HEIGHT, 1); display.display(); frame = (frame + 1) % FRAME_COUNT; delay(FRAME_DELAY); } digitalWrite(play, LOW); display.clearDisplay(); display.display(); } } // stop animation when audio stops if (music_player_on && !audio.isPlaying()) { music_player_on = false; stopAnimation(); } // play animation while playing music else if (music_player_on && audio.isPlaying()) { updateAnimation(); } else if (!music_player_on) { display.clearDisplay(); display.display(); } }
Functia numberAudios():
int numberAudios(File dir) { int count = 0; for (File file = dir.openNextFile(); file; file = dir.openNextFile()) { if (!file.isDirectory()) { String name = file.name(); if (name.endsWith(".wav") || name.endsWith(".WAV")) { count++; } } file.close(); } return count; }
Functia playAudio():
void playAudio(int index) { audio.stopPlayback(); songIdx = index; char fileName[FILENAME_SIZE]; snprintf(fileName, FILENAME_SIZE, "song_%d.wav", index); audio.play(fileName); }
Functia selectRandomAnimation():
void selectRandomAnimation() { int animationChoice = random(3); switch (animationChoice) { case 0: currentAnimation = cd; break; case 1: currentAnimation = tape; break; case 2: currentAnimation = music; break; } }
Functia updateAnimation():
void updateAnimation() { display.clearDisplay(); display.drawBitmap(40, 8, currentAnimation[frame_music], FRAME_WIDTH, FRAME_HEIGHT, 1); display.display(); frame_music = (frame_music + 1) % FRAME_COUNT; delay(FRAME_DELAY); }
Functia stopAnimation():
void stopAnimation() { display.clearDisplay(); display.display(); }
Fişierele se încarcă pe wiki folosind facilitatea Add Images or other files. Namespace-ul în care se încarcă fişierele este de tipul :pm:prj20??:c? sau :pm:prj20??:c?:nume_student (dacă este cazul). Exemplu: Dumitru Alin, 331CC → :pm:prj2009:cc:dumitru_alin.