Mélodies avec un Arduino UNO
Mélodie
Arduino
UNO
Voici un programme écrit par Pierre-Yves Rochat, professeur du MOOC sur les µcontrôleurs de l’EPFL qui montre comment utiliser les timers et les interruptions de l’Arduino UNO (ou du Diduino) pour jouer des mélodies.
Le fonctionnement du programme est décrit dans ce document :
Voir aussi la vidéo d’introduction au MOOC :
/*
* JOUER DES MÉLODIES SUR ARDUINO UNO
*
* Programme original de Pierre-Yves Rochat — pyr.ch
* Source :
* https://d396qusza40orc.cloudfront.net/microcontroleurs/lecture_doc/MelodieDoc.pdf
*
* Modifié par Nicolas Jeanmonod, décembre 2014
*
*/
#define HPPin PORTD1 // Le HP du LearnCBot est sur la pin PORTD1
#define HautParleurEnSortie DDRD |= ( 1 << HPPin )
#define TicHautParleur PORTD ^= ( 1 << HPPin )
// DURÉE DES NOTES
// La durée des notes est définie sur les 3 bits de poids forts. La Noire doit
// être définie à la valeur 0. Cela permet de ne pas devoir la spécifier
// explicitement dans les partitions. Les valeurs des autres durées sont sans
// importance.
#define TripleCroche 0b00100000
#define DoubleCroche 0b01000000
#define Croche 0b01100000
#define Noire 0b00000000
#define NoireP 0b10000000
#define Blanche 0b10100000
#define BlancheP 0b11000000
#define Ronde 0b11100000
#define tCr DoubleCroche
#define dCr DoubleCroche
#define Cr Croche
#define Nr Noire
#define Np NoireP
#define Bl Blanche
#define Blp BlancheP
#define Ro Ronde
#define Fin 0
#define Reprise 0xFE
#define DivTimer8 0b010
const unsigned int NotePeriode[] =
{
4545, 4290, 4050, 3822, 3608, 3405, 3214, 3034, 2863, 2703, 2551, 2408,
2273, 2145, 2025, 1911, 1804, 1703, 1607, 1517, 1432, 1351, 1276, 1204,
1136, 1073, 1012, 956, 902, 851, 804, 758
};
const byte NoteFrequenceDiv8[] =
{
28, 29, 31, 33, 35, 37, 39, 41, 44, 46, 49, 52,
55, 58, 62, 65, 69, 73, 78, 82, 87, 92, 98, 104,
110, 117, 123, 131, 139, 147, 156, 165
};
enum notes
{
, la1d, si1, do2, do2d, re2, re2d, mi2, fa2, fa2d, sol2, sol2d,
la1, la2d, si2, do3, do3d, re3, re3d, mi3, fa3, fa3d, sol3, sol3d,
la2, la3d, si3, do4, do4d, re4, re4d, mi4
la3};
unsigned int Pique;
= 0b11100000;
byte MasqueDuree = 0b00011111;
byte MasqueNote
* DebutMelodie;
byte* PtMelodie;
byteunsigned int PeriodesRestantes;
unsigned int PeriodeCourante;
unsigned int PeriodesOff;
;
byte NoteCourante
[] =
byte FrereJacques{
+Cr, re3+Cr, mi3+Cr, do3+Cr, do3+Cr, re3+Cr, mi3+Cr, do3+Cr,
do3+Cr, fa3+Cr, sol3, mi3+Cr, fa3+Cr, sol3,
mi3+dCr, la3+dCr, sol3+dCr, fa3+dCr, mi3+Cr, do3+Cr, sol3+dCr, la3+dCr, sol3+dCr, fa3+dCr, mi3+Cr, do3+Cr,
sol3+Cr, sol2+Cr, do3, do3+Cr, sol2+Cr, do3,
do3
// Fin ou Reprise
Reprise};
// https://books.google.ch/books?id=RCYakK7vmoEC&pg=PA459&lpg=PA459&dq=jingle+bells+garageband&source=bl&ots=Nxg1Yr-DCE&sig=4DhKrlQlvWNL8qNni7kGt5UcWss&hl=fr&sa=X&ei=H46YVI_eDoHlaLqqgYAF&ved=0CGIQ6AEwCQ#v=onepage&q=jingle%20bells%20garageband&f=false
[]=
byte JingleBells{
// Intro
+Cr, fa3+Cr, fa3+Cr, fa3+Cr, fa3+Cr, mi3+Cr, mi3+Cr, mi3+dCr, mi3+dCr,
fa3+Cr, sol3+Cr, fa3+Cr, re3+Cr, do3, sol3,
sol3
// Verse
+Cr, mi3+Cr, re3+Cr, do3+Cr, sol2+Np, mi2+dCr, fa2+dCr,
sol2+Cr, mi3+Cr, re3+Cr, do3+Cr, la2+Bl,
sol2+Cr, fa3+Cr, mi3+Cr, re3+Cr, si2+Bl,
la2+Cr, sol3+Cr, fa3+Cr, re3+Cr, mi3+Bl,
sol3+Cr, mi3+Cr, re3+Cr, do3+Cr, sol2+Bl,
sol2+Cr, mi3+Cr, re3+Cr, do3+Cr, la2+Np, la2+Cr,
sol2+Cr, fa3+Cr, mi3+Cr, re3+Cr, sol3+Cr, sol3+Cr, sol3+Cr, sol3+Cr,
la2+Cr, sol3+Cr, fa3+Cr, re3+Cr, do3, sol3,
la3
// Chorus / Refrain
+Cr, mi3+Cr, mi3, mi3+Cr, mi3+Cr, mi3,
mi3+Cr, sol3+Cr, do3+Cr, re3+Cr, mi3+Bl,
mi3+Cr, fa3+Cr, fa3+Cr, fa3+Cr, fa3+Cr, mi3+Cr, mi3+Cr, mi3+dCr, mi3+dCr,
fa3+Cr, re3+Cr, re3+Cr, mi3+Cr, re3, sol3,
mi3+Cr, mi3+Cr, mi3, mi3+Cr, mi3+Cr, mi3,
mi3+Cr, sol3+Cr, do3+Cr, re3+Cr, mi3+Bl,
mi3+Cr, fa3+Cr, fa3+Cr, fa3+Cr, fa3+Cr, mi3+Cr, mi3+Cr, mi3+dCr, mi3+dCr,
fa3+Cr, sol3+Cr, fa3+Cr, re3+Cr, do3+Bl,
sol3
// Outro
+Cr, fa3+Cr, fa3+Cr, fa3+Cr, fa3+Cr, mi3+Cr, mi3+Cr, mi3+Cr,
fa3+Cr, sol3+Cr, fa3+Cr, re3+Cr, do3+Bl,
sol3
// Fin ou Reprise
Fin};
/*
*
*/
( TIMER1_COMPA_vect )
ISR{
if( PeriodesRestantes == 0 )
{
= *PtMelodie;
NoteCourante switch( NoteCourante )
{
case Fin:
&= ~( 1 << OCIE1A );
TIMSK1 return;
case Reprise:
= DebutMelodie;
PtMelodie = *PtMelodie;
NoteCourante break;
default:
break;
}
++;
PtMelodie= NotePeriode[ NoteCourante & MasqueNote ];
PeriodeCourante = NoteFrequenceDiv8[ NoteCourante & MasqueNote ];
PeriodesRestantes
&= MasqueDuree;
NoteCourante switch( NoteCourante )
{
case TripleCroche: PeriodesRestantes *= 1; break;
case DoubleCroche: PeriodesRestantes *= 2; break;
case Croche: PeriodesRestantes *= 4; break;
case 0: PeriodesRestantes *= 8; break;
case NoireP: PeriodesRestantes *= 12; break;
case Blanche: PeriodesRestantes *= 16; break;
case BlancheP: PeriodesRestantes *= 24; break;
case Ronde: PeriodesRestantes *= 32; break;
}
= ( PeriodesRestantes * Pique ) / 100;
PeriodesOff }
= TCNT1 + PeriodeCourante;
OCR1A if( PeriodesRestantes > PeriodesOff ){ TicHautParleur; }
--;
PeriodesRestantes}
/*
*
*/
void
()
InitMelodie{
;
HautParleurEnSortie= ( DivTimer8 << CS10 ); // choix de la fréquence : 16 MHz / 8 = 2 MHz
TCCR1B |= ( 1 << OCIE1A ); // enclenche l’interrupt du timer
TIMSK1 (); // activation générale des interruptions
sei}
/*
*
*/
void
( byte* melodie )
JoueMelodie{
= melodie;
DebutMelodie = DebutMelodie;
PtMelodie = 0;
PeriodesRestantes ();
InitMelodie}
/*
*
*/
int
()
mainInit{
// Nécessaire pour utiliser la pin PORTD1 sur le Diduino.
.end();
Serial
// Toutes les pins de tous les ports en INPUT-PULLUP
= 0b00000000;
DDRB = 0b11111111;
PORTB = 0b00000000;
DDRC = 0b11111111;
PORTC = 0b00000000;
DDRD = 0b11111111;
PORTD
// Excepté la LED du board
|= ( 1<<PORTB5 );
DDRB &=~( 1<<PORTB5 );
PORTB }
/*
*
*/
int
()
main{
();
mainInit= 20;
Pique switch( 1 )
{
case 0:
( FrereJacques );
JoueMelodiebreak;
case 1:
( JingleBells );
JoueMelodiebreak;
default:
break;
}
volatile unsigned int i;
while( true )
{
// Clignote la LED du board
for( i=0; i<65535; i++ ){}
^= ( 1<<PORTB5 );
PORTB }
}
© ouilogique.com