Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: Pavetic_BuzzerLib Pavetic_MusicLib
main.cpp
- Committer:
- dpavetic
- Date:
- 2022-11-27
- Revision:
- 0:e9d0eb34d345
File content as of revision 0:e9d0eb34d345:
// Program koji simulira božične lampice //
// Gumb - Mijenja melodiju na klik (1...n) - Hardverski interrupt
// Potenciometar - Mjerenje vrijednosti na ulazu (0.0-1.0) - Potrebno za
// mjerenje vremena promjene pjesme Zvučnik - Reprodukcija melodije Zuta LED -
// Signalizacija da traje melodija jingle bells Crvena LED - Signalizacija da
// traje melodija We wish you a merry christmas Zelena LED - Signalizacija da
// traje melodija Silent night
// Ticker - Automatsko mijenjanje melodije u vremenu ovisnom o potenciometru
// (samo u modu MODE_AUTO)
// --> 0V = 5s
// --> 1V = 25s
// --> f(x) = 5 + 20*x [s] - Skaliranje funkcije pomaknute za 5s (min =
// 5s, max = 25s)
// Timer #1 - Mjerenje vremena trajanja melodije
// Timer #2 - Debounce efekt za gumb
// Opis rada programa:
// Postoje 3 moda rada:
// --> MODE_OFF - Sustav je ugašen - Buzzer ugašen kao i sve LEDice
// --> MODE_SONG - Repetetivno ponavljanje odabrane melodije - Buzzer
// svira, te svijetli jedna od pripadajucih LEDica za trenutnu melodiju
// --> MODE_AUTO - Automatsko mijenjanje melodije u vremenskom
//razmaku odabranom putem potenciometra - Buzzer svira, te svijetli jedna od
//pripadajucih LEDica za trenutnu melodiju
//
// Postoje 3 melodije: Jingle bells, We wish you, Silent night. Ovisno o
// trenutnoj melodiji, svijetli pripadajuca LEDica.
//
// Na početku programa postavljen je mod MODE_OFF te je sustav ugašen.
// Pritiskom na gumb u modu MODE_OFF (prvi pritisak gumba), mijenja se mod u
// MODE_SONG te počinje svirati prva od ponudenih melodija. Nakon sto melodija
// zavrsi, ukoliko nije došlo do promjene melodije ili prekida, ponovno se
// započinje sa reprodukcijom iste melodije. Ukoliko tijekom reprodukcije dođe
// do promjene moda ili melodije, trenutna melodija prekida sa reprodukcijom te
// počinje reprodukcija sljedeće melodije, ili se sustav gasi ukoliko je došlo
// do promjene moda u MODE_OFF.
//
// Program je u modu MODE_SONG te svira prva pjesma i upaljena je zuta LEDica.
// Drugim pritiskom gumba, mode ostaje isti, no mijenja se melodija te svira
// druga melodija i svijetli crvena LEDica. Trećim pritiskom gumba, mod i dalje
// ostaje isti i svira treca melodija uz upaljenu zelenu LEDicu.
//
// Cetvrtim pritiskom gumba mijenja se mod u MODE_OFF te se resetira ciklus
// melodija i započinje reprodukcija prve melodije. Melodija se reproducira
// ovisno o vremenu izračunatom iz vrijednosti na potenciometru prema određenoj
// formuli koja je navedena na vrhu. Nakon isteka vremena, mijenja se melodija i
// započinje reprodukcija sljedeće melodije, te tako u krug sa svim melodijama.
// - Vrijednost potenciometra očitava se cijelo vrijeme na zasebnom
// Threadu.
// - Vrijeme reprodukcije melodije u modu MODE_OFF izračunava se kod
// dolaska u taj mode.
//
// Petim pritiskom gumba, prekida se reprodukcija melodije te se mod mijenja u
// MODE_OFF i program nastavlja ispočetka.
#include "DigitalOut.h"
#include "Music.h"
#include "PinNameAliases.h"
#include "PinNames.h"
#include "ThisThread.h"
#include "Thread.h"
#include "Buzzer.h"
#include "mbed.h"
#include "mbed_rtc_time.h"
#include "mbed_thread.h"
#include "rtos.h"
#include <chrono>
#include <cmath>
#include <cstdio>
#include <cstring>
#define SONG_COUNT 3
#define MODE_OFF 0
#define MODE_SONG 1
#define MODE_AUTO 2
#define JINGLE_BELLS 1
#define WISH 2
#define SILENT_NIGHT 3
DigitalOut jingleBellsLed(PA_10); // Yellow
DigitalOut wishLed(PB_5); // Red
DigitalOut silentNightLed(PA_9); // Green
// -- START Sounds and music -- //
Timer songMeasure; // Measuring how long did song play
// PwmOut buzzer(D5);
Buzzer buzzer(D5);
void playMusic(int array[], float rithm[], int size);
// -- END Sounds and music -- //
// -- START Mode changing -- //
InterruptIn button(D7); // Button for changing melodies
Timer debounce; // Debounce timer for the button
void onButtonPress();
// -- END Mode changing -- //
// -- START Main variables -- //
int currentMode = MODE_OFF; // Mode that is currently selected
int currentMelody = JINGLE_BELLS; // Melody that is currently being played
int songStartedOnMode = -1; // Variable ensuring mode change is detected
int songStartedOnMelody = -1; // Vriable ensuring melody change is detected
// -- END Main variables -- //
// -- START Auto changing transitions -- //
AnalogIn potenciometer(
A0); // Analog input for potenciometer - detecting song change speed
Ticker changeSongTicker; // Ticker for changing song every x time - depends on
// measuredVoltage
Thread analogMeasureThread(osPriorityNormal, 300, nullptr, nullptr);
float measuredVoltage = 0; // Currently measured voltage on potenciometer - For
// determining time between transitions
void readValue();
// -- END Auto changing transitions -- //
// -- START Common functions -- //
void changeMode();
void changeSong();
void toggleLeds(int song);
// -- END Common functions -- //
int main() {
debounce.start();
button.mode(PullUp); // Required - otherwise button does not work properly
button.rise(&onButtonPress);
analogMeasureThread.start(readValue);
while (true) {
toggleLeds(currentMelody);
// If MODE_OFF, turn off buzzer and skip the code
if (currentMode == MODE_OFF) {
buzzer.silence();
continue;
}
songStartedOnMode = currentMode;
songStartedOnMelody = currentMelody;
switch (currentMelody) {
case JINGLE_BELLS: {
int size = (unsigned int)sizeof jingle_bells_melody /
sizeof jingle_bells_melody[0];
playMusic(jingle_bells_melody, jingle_bells_note_durations, size);
break;
}
case WISH: {
int size = (unsigned int)sizeof wish_melody / sizeof wish_melody[0];
playMusic(wish_melody, wish_note_durations, size);
break;
}
case SILENT_NIGHT: {
int size = (unsigned int)sizeof silent_night_melody /
sizeof silent_night_melody[0];
playMusic(silent_night_melody, silent_night_note_durations, size);
break;
}
}
}
}
void playMusic(int array[], float rithm[], int size) {
songMeasure.start();
int i = 0;
for (i = 0; i < size; i++) {
// Stop executing if mode or song change in the meantime
// Otherwise song would remain playing after mode or song is changed
if (currentMode != songStartedOnMode ||
currentMelody != songStartedOnMelody)
break;
printf("Entering iteration %d for song %d. Measured voltage: %f\n", i,
currentMelody, measuredVoltage);
buzzer.buzz(array[i], rithm[i]);
}
// Printing how long did song played in seconds
int elapsedTime_sec =
duration_cast<std::chrono::seconds>(songMeasure.elapsed_time()).count();
printf("Song played for %d seconds\n", elapsedTime_sec);
songMeasure.stop();
songMeasure.reset();
// Pause for 1 second after song has finished WITHOUT interruption - Silent
// transition Otherwise, move straight to the next song
buzzer.silence();
if (i == size)
ThisThread::sleep_for(1s);
}
// Callback executed when button is pressed - initiated by the Interrupt.
// Uses debounce effect of 200ms and if button really pressed following code is
// executed.
// 1. If any song is currently playing in MODE_SONG AND it is not last song,
// change song.
// 2. Otherwise, if any other mode, or it is last song - Change mode.
void onButtonPress() {
if (debounce.elapsed_time() > 200ms) {
if (currentMode == MODE_SONG && currentMelody < SONG_COUNT)
changeSong();
else
changeMode();
debounce.reset();
}
}
void changeMode() {
// Reset melody because mode has changed - Initial melody should be played
// (Melody cycle reset)
currentMelody = JINGLE_BELLS;
// Temp var used to prevent multiple mode changes at once because new mode
// could be unknown.
int newMode = currentMode + 1; // Increase temp mode variable
switch (newMode) {
case MODE_AUTO: {
// Calculate time base on potenciometer reading and attach Ticker
// 0V = 5s
// 1V = 25s
// f(x) = 5 + 20*x [s] - Skaliranje funkcije pomaknute za 5s (min = 5s,
// max = 25s)
int changeTime_sec = 5 + (20 * measuredVoltage);
changeSongTicker.attach_us(&changeSong, changeTime_sec * 1000000);
break;
}
case MODE_SONG:
case MODE_OFF:
// Detach timer to prevent song change after time expires
changeSongTicker.detach();
break;
default:
// Unrecognised mode - Turn off + detach timer to prevent song change
changeSongTicker.detach();
newMode = MODE_OFF;
}
// Change source of truth mode
currentMode = newMode;
}
// Changes current song.
// If current melody is the last melody, reset the cyle of the songs and
// play the first song.
void changeSong() {
int newMelody = currentMelody + 1;
if (newMelody > SILENT_NIGHT)
newMelody = 1;
currentMelody = newMelody;
}
// Constantly reads the analog input value in separate thread.
void readValue() {
while (true) {
measuredVoltage = potenciometer.read();
}
}
// Toggles LEDs based on the current song.
// If MODE_OFF, turn off all LEDs.
// Only 1 LED can be turned on at the same time.
void toggleLeds(int song) {
if (currentMode == MODE_OFF) {
jingleBellsLed.write(false);
wishLed.write(false);
silentNightLed.write(false);
return;
}
jingleBellsLed.write(song == JINGLE_BELLS);
wishLed.write(song == WISH);
silentNightLed.write(song == SILENT_NIGHT);
}