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
Diff: main.cpp
- Revision:
- 0:e9d0eb34d345
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp Sun Nov 27 13:01:54 2022 +0000
@@ -0,0 +1,282 @@
+// 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);
+}