Contactloze Handwas-timer met Muzikale Alerts
Onderdelen en benodigdheden
| Arduino UNO | × | 1 |
| ProtoStax Behuizing voor Arduino | × | 1 |
| ProtoStax Behuizing voor Breadboards/Aangepaste Boards | × | 1 |
| ProtoStax Horizontale Stapelkit | × | 1 |
| Ultrasone Sensor - HC-SR04 (Generiek) | × | 1 |
| ProtoStax Kit voor Ultrasonische Sensor HC-SR04 | × | 1 |
| Adafruit 0.56" 4-Digit 7-Segment Display met I2C Backpack - Blauw | × | 1 |
| Adafruit Piezo Buzzer - PS1240 | × | 1 |
| Solderloos Breadboard Half Size | × | 1 |
Apps en online diensten
- Arduino IDE
Over dit project
Terwijl handwassen altijd een belangrijk wapen was in ziektepreventie en algemene gezondheid, heeft het een nieuwe prominentie gekregen als preventieve maatregel om de verspreiding van de COVID-19-pandemie te remmen.
De CDC-richtlijn voor goed handwassen stelt dat men idealiter 20 seconden lang de handen moet schuiven. CDC Richtlijnen
🤓📚** Extra info ** 🤓📚 Hier is wat wetenschap achter handwassen als je geïnteresseerd bent! - Wetenschap van handwassen
In deze herziene versie van een handwas-timer wordt onze muzikale handwas-timer geactiveerd door onze hand voor een ultrasone sensor te bewegen, en toont de aftelling op een 7-segmentdisplay. Om het interessanter te maken, speelt het ook een roulerende selectie van 20-seconden jingles uit een lijst met voorgeprogrammeerde jingles af. Je kunt gemakkelijk je eigen muziek toevoegen door elke bladmuzieknotatie te transcriberen!
Hier is een kijkje op de Contactloze MuzikaleHandwas-timer in actie, met alle 4 jingles die ik geprogrammeerd heb:
- Happy Birthday (Lang zal ze leven)
- Do-Re-Mi (The Sound of Music)
- We Will Rock You (Queen)
- Jeopardy Theme Music
Jongen, mijn handen waren super-schoon aan het eind! 😊
🤓📚** Extra info ** 🤓📚 We weten allemaal dat het zingen van "Happy Birthday to You" twee keer ongeveer 20 seconden duurt, en het is een de facto standaard voor handwas-timing geworden, zelfs gezongen door Canada's premier Justin Trudeau! Dr. Theresa Tam, Canada's Hoofd Volksgezondheidsfunctionaris, heeft haar eigen favorieten als We Will We Will Wash You! 😊 Bekijk dit fascinerende interview van CBC Kids News-bijdrager Arjun Ram.
Ik presenteer beide nummers in onze Contactloze Muzikale Handwas-timer, plus nog een paar! 😊
Stap 1 - Schema
Dit project gebruikt een Arduino Uno, een 7-segment LED Backpack (I2C), een HC-SR04 Ultrasone Sensor en een Piezo Buzzer. Raadpleeg het schema hieronder.

Stap 2 - Plannen en Opzetten
Naast het schema en de programmering wilde ik ook nadenken over het "eindproduct" en hoe het bruikbaar te maken - dus in een behuizing stoppen en daarvoor plannen.
Ik gebruikte ProtoStax Behuizingen - ze zijn stapelbaar, en komen met ondersteuning voor Arduino, Raspberry Pi en Breadboard. Aangezien ik een Arduino met een breadboard-circuit gebruikte, koos ik voor ProtoStax Behuizing voor Arduino en ProtoStax Behuizing voor Breadboard/Aangepaste Boards. Ik wilde ook dat de ultrasone sensor vanaf buiten toegankelijk was en dus aan de behuizing vastgezet - ik gebruikte de ProtoStax Kit voor Ultrasonische Sensor HC-SR04.
Ik begon met het horizontaal stapelen van de Arduino en Breadboard basisplatforms met horizontale stekconnectors om prototypen te vergemakkelijken:

Zodra ik mijn prototyperingsplatform had, kon ik beginnen met het plaatsen van de componenten volgens het schema. Ik bevestigde de HC-SR04 Ultrasone Sensor aan de zijwand van de ProtoStax Kit voor Ultrasonische Sensor HC-SR04 om het toegankelijk te maken zodra de behuizing na het prototype compleet was. De zijwand met de sensor gaat in de sleuf van het basisplatform zoals getoond:


Stap 3 - Programmeren en Testen
Nu ik een werkend prototyperingsplatform had, kon ik de code ervoor ontwikkelen. Ik ga dieper in op de code-functionaliteit en -layout in een apart gedeelte hieronder. Hier is een video van de test. Het is verrassend dat de iPhone 11 die ik gebruikte voor de opname het distincte sonar-pingen van de ultrasone sensor daadwerkelijk opnam, wat heel duidelijk te horen is in de onderstaande video (hoewel het ultrasone pulsen nauwelijks anders zichtbaar is dan een onschuldelijke klik-klik-klik)! 😊
Zodra alles bevestigd was als werkend, voegde ik de zijwanden en de overige connectors en deksels toe om mijn behuizing af te maken:

De video bovenaan toont het eind "product" in gebruik! 😊

De code begrijpen
Componenten initialiseren:
We gebruiken de Adafruit_7segment-klasse uit de LED Backpack-bibliotheek om ons 7-segmentdisplay te initialiseren en ermee te communiceren.
Adafruit_7segment matrix = Adafruit_7segment();
We initialiseren ook de trig- en echo-pinnen op de HC-SR04 als respectievelijk output en input.
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
matrix.begin(0x70);
In de main loop gebeurt op hoog niveau het volgende:
- Controleer de ultrasone sensor afstandsmeting om te zien of de Handwas-timer getriggerd is.
- Als ja, noteer dan de huidige tijd, initialiseer de aftel-timer (ik stel het in op 20 voor 20 seconden), en kies de volgende muzikale jingle om af te spelen. Ik gebruikte eerst random() om een willekeurige melodie te kiezen, maar veranderde het in "round-robin" over de array van melodieën (terugcyclend naar de eerste), en stelde startMusic in op 1 (om de aftelling en muziekspelen in gang te zetten).
if (distance < 10 && !startMusic) {
startMusic = 1; // initializeTimer1();
countDown = 20;
currentTime = millis();
melodyNum = (melodyNum+1)%(NUM_MELODIES(melodies));
}
Kijk ma, geen delay()!
Hier doen we twee dingen tegelijkertijd - we willen de aftelklok periodiek bijwerken met hoeveel seconden er nog over zijn voor handwassen. We willen ook de jingle verwerken en op het juiste moment afspelen.
We kunnen geen delay() gebruiken.
Het typische voorbeeld van muziek afspelen gebruikt de tone()-functie van de Tone-bibliotheek, en wacht de juiste vertraging af voordat het doorgaat naar de volgende noot. Dat werkt niet, want we willen nog steeds de aftelklok bijwerken!
tone() is een non-blocking call. Het gebruikt Timer2 om het signaal voor de gespecificeerde lengte te sturen, wat betekent dat we in de tussentijd vrij zijn om andere verwerking te doen.
We gebruiken millis() en lokale variabelen om uit te rekenen hoeveel tijd verstreken is, in plaats van delay(), en kunnen doorgaan met andere controles en operaties in de tussentijd. We kijken straks naar de exacte code.
Muziek transcriberen op de makkelijke manier - Hele noten, Kwartnoten, etc.
We willen een gegeven melodie afspelen, en ook makkelijk meer melodieën kunnen transcriberen. Arduino muziekvoorbeelden slaan meestal twee verschillende arrays op, één voor de noten, en één array voor de duur van de noten (in milliseconden).
Om dingen te vereenvoudigen, heb ik een struct gemaakt om een noot en de gegeven duur te associëren. En in plaats van absolute duur, gebruikte ik relatieve duur die ik met #defines heb gemaakt.
typedef struct Note {
int frequency;
float duration;
} Note;
#define NOTE_WHOLE 1
#define NOTE_HALF 0.5f
#define NOTE_QUARTER 0.25f
#define NOTE_EIGHTH 0.125f
#define NOTE_SIXTEENTH 0.0625f
#define DOTTED(X) (X * 1.5f)
Laten we het voorbeeld van Happy Birthday (Lang zal ze leven) nemen.

Dit kan als volgt getranscribeerd worden, min of meer noot voor noot. Als je geen bladmuziek kunt lezen, zoek dan de daadwerkelijke noten op. 🤓📚 Maar leren bladmuziek lezen is altijd een handige vaardigheid, en je hoeft niet erg goed te zijn - net genoeg om te weten wat de noten zijn, stelt je in staat de muziek naar je Arduino te transponeren! 🤓📚
// Happy Birthday Noot melodie[] = {
{NOTE_G6, DOTTED(NOTE_EIGHTH)},
{NOTE_G6, NOTE_SIXTEENTH},
{NOTE_A6, NOTE_QUARTER},
{NOTE_G6, NOTE_QUARTER},
{NOTE_C7, NOTE_QUARTER},
{NOTE_B6, NOTE_HALF},
{NOTE_G6, DOTTED(NOTE_EIGHTH)},
{NOTE_G6, NOTE_SIXTEENTH},
{NOTE_A6, NOTE_QUARTER},
{NOTE_G6, NOTE_QUARTER},
{NOTE_D7, NOTE_QUARTER},
{NOTE_C7, NOTE_HALF},
{NOTE_G6, DOTTED(NOTE_EIGHTH)},
{NOTE_G6, NOTE_SIXTEENTH},
{NOTE_E7, NOTE_QUARTER},
{NOTE_D7, NOTE_QUARTER},
{NOTE_C7, NOTE_QUARTER},
{NOTE_B6, NOTE_QUARTER},
{NOTE_A6, NOTE_HALF},
{NOTE_F7, DOTTED(NOTE_EIGHTH)},
{NOTE_F7, NOTE_SIXTEENTH},
{NOTE_E7, NOTE_QUARTER},
{NOTE_C7, NOTE_QUARTER},
{NOTE_D7, NOTE_QUARTER},
{NOTE_C7, NOTE_HALF},
};
Let op (pun intended!) dat ik geen echte duur gebruikte, ik specificeerde de relatieve duur van de noten als kwartnoten, achtstenoten, zestiende noten, etc. Ik heb zelfs een DOTTED()-macro om een gepunte noot weer te geven (1,5x de duur van de voorafgaande noot).
Een melodie zelf bestaat uit deze array, evenals aanvullende informatie over wat de duur van een hele noot moet voorstellen.
typedef struct Melody {
Note *notes;
int numNotes;
int wholeNoteDurationMs;
} Melody;
Omdat C-arrays niet gesizeerd kunnen worden met een pointer naar de array, voeg ik numNotes toe als de grootte van de Note-array. Dit kan eenvoudig geïnitialiseerd worden met de MELODY_LENGTH-macro - dus je hoeft je geen zorgen te maken over hoeveel noten je in je Note-array hebt gemaakt tijdens het transcriberen van je favoriete liedje!
Ik definieer vervolgens een array van dergelijke Melody om in mijn programma te gebruiken.
Melody melodies[] = {
{melody, MELODY_LENGTH(melody), 1250},
{melody3, MELODY_LENGTH(melody3), 1000},
{melody4, MELODY_LENGTH(melody4), 1000}
};
In de loop, bij het starten van de aftel-timer en de muziek, gebruik ik de bovenstaande informatie over noten, relatieve duur, en de daadwerkelijke duur van een hele noot, om uit te rekenen hoe de muziek moet worden afgespeeld. Tussen het afspelen van de muziek door, controleer en update ik ook de aftel-timer en toon het getal op het 7-segmentdisplay.
Omdat ik me voorstel dat mensen de hele jingle willen uitluisteren, speel ik de jingle door tot het einde, zelfs als de 20 seconden voorbij zijn (de countDown wordt negatief tot het liedje eindigt). Zodra de jingle voorbij is, stopt het tot het opnieuw getriggerd wordt door je hand voor de ultrasone sensor te bewegen. Als de jingle te kort is, speelt het nog een keer af, tot 20 seconden verstreken zijn EN de muziek is uitgekomen! Simpel.
if (startMusic) {
// Kies de melodie om af te spelen
Melody mel = melodies[melodyNum];
Note *m = mel.notes;
int mSize = mel.numNotes;
// speedUp is een makkelijke manier om het afspelen van de noten te versnellen. De beste manier zou zijn om
// wholeNoteDurationMs op de juiste waarde in te stellen.
int speedUp = 1;
noTone(TONE_PIN); // Begin met een schone lei
for (int thisNote = 0; thisNote < mSize; thisNote++) {
// Om de nootduur te berekenen, neem de duur van de hele noot en vermenigvuldig met het noottype.
// bv. kwartnoot = wholeNoteDurationMs * 0.25, achtstenoot = wholeNoteDurationMs * 1/8 (0.125), etc.
// Verminder de duur met de speedup-factor om de afspeelsnelheid met een passend bedrag te verhogen
int noteDuration = mel.wholeNoteDurationMs * m[thisNote].duration / speedUp;
unsigned long noteTime = millis();
tone(TONE_PIN, m[thisNote].frequency, noteDuration);
// Om de noten te onderscheiden, stel een minimumtijd tussen ze in.
// de nootduur + 30% lijkt goed te werken:
int pauseBetweenNotes = noteDuration * 1.30;
unsigned long nowTime = millis();
countDown = 20 - (int)((nowTime - currentTime)/1000);
// Kijk ma, geen delay()!
// Gebruik geen delay(), want we willen nog steeds de aftel-timer bijwerken
// en het display updaten
while(millis() - noteTime <= pauseBetweenNotes) {
countDown = 20 - (int)((millis() - currentTime)/1000);
matrix.print(countDown);
matrix.writeDisplay();
delay(10);
}
noTone(TONE_PIN);
matrix.print(countDown);
matrix.writeDisplay();
}
}
De complete code is te vinden op GitHub en de link naar de repository is opgenomen. Ik raad aan de code daar vandaan te halen, in plaats van code hier te kopiëren en plakken.
Het project verder uitbreiden
Zodra je comfortabel bent met het spelen met het codevoorbeeld en de code begrijpt, is het altijd leuk om je leerproces uit te breiden door meer te doen.
Hier zijn een paar suggesties om dit project voort te zetten:
1) Je kunt je favoriete liedje zoeken en het transcriberen met de NOTE en NOOTduur macro's zoals hierboven beschreven. Onthoud om een of meer van de andere jingles die al gedefinieerd zijn, uit te commentariëren, om het geheugengebruik laag te houden (tenzij je de Note- en Melody-arrays succesvol naar PROGMEM hebt verplaatst zoals hieronder beschreven! 😊)
2) De melodieën nemen ruimte in het SRAM in beslag en kunnen de beschikbare geheugen snel opvreten. Bijvoorbeeld, ik transcibeerde 4 melodieën (Happy Birthday, Do-Re-Mi, We Will Rock You, en Jeopardy!). Maar deze duwden het SRAM-gebruik naar 96%, niet genoeg overlatend voor het functioneren van de 7-segmentdisplay-bibliotheek, en het werkte niet meer goed! Ik moest er een van de melodieën uit de Melody-array halen voor alles goed te laten werken.
De Arduino Uno komt met 2k SRAM, maar 32k Flash-geheugen (waar het programma in woont). Als je sommige globale variabelen naar Flash-geheugen kunt verplaatsen, niet alleen maak je SRAM vrij voor de rest van het programma, maar je hebt ook meer ruimte om nog meer liedjes op te slaan! Probeer de Note- en Melody-arrays in Flash te definiëren als PROGMEM. [Let op: dit is een geavanceerde onderneming en niet-triviaal. JezultdearrayvanstructsnaarPROGMEMverplaatsenendanmoetenlezenvanprogmemomtoegangtekrijgentotdedata.]
Om je een idee te geven van de verschillen: dit programma (met 3 melodieën) nam 31% van programma-opslag en 76% van dynamisch geheugen in beslag op een Uno. Met de bovenstaande variabelen gedefinieerd in PROGMEM, nam het 32% van programma-ruimte in beslag (dat is slechts een lichte toename in Flash-geheugengebruik met nog veel meer beschikbaar) en slechts 22% (van 76% af) van dynamisch geheugen! Dat betekent dat je gemakkelijk veel meer liedjes aan deze Contactloze Muzikale Handwas-timer kunt toevoegen zodra je dingen naar PROGMEM verplaatst! 😊
Kun je andere manieren bedenken om dit project uit te breiden? Deel het met ons hieronder! 😊
Veel plezier met maken! 😊
Code
ProtoStax Contactloze Muzikale Handwas-timer Demo
Schema's
Dit toont het schema voor de schakeling die gebruikt wordt in de Contactloze Muzikale Handwas aftel-timer
Productieproces
- Bewezen Best Practices Voor Het Inspecteren Van Handwasstations
- Bluetooth-gecontroleerde Arduino Spybot bouwen
- FlickMote: Gebarengecontroleerde IR-afstandsbediening voor Slimme Huizen
- DIY Arduino TV-B-Gone: Universele TV-uit-schakelaar
- De Watchdog Timer begrijpen: Hoe het microcontroller-ophangen voorkomt
- Bouw een Aangepaste LED Hoofdklok met Alarm – Zichtbaar vanaf 12 Meter
- Find Me: Slimme Item Locator met Arduino en Bluetooth
- Geoptimaliseerde Voedingsoplossingen voor Arduino Projecten
- Arduino Boter-Kaas-Eieren met MAX7219 LED Matrix en Kartonnen Behuizing
- Bouw een Slimme Arduino Vierpotige Robot: Stap-voor-Stap Handleiding
- Bouw een Betrouwbare Arduino Afteltimer met SparkFun 7‑Segment Display