MICPRG opdracht 4a.

© Harry Broeders.

Deze pagina is bestemd voor studenten van de Haagse Hogeschool - Academie voor Technology, Innovation & Society Delft groep EQ1.2.

Muziek-generator.

De AVR STK500 systemen van de opleiding Elektrotechniek aan de Academie voor Technology, Innovation & Society Delft zijn uitgerust met een luidspreker die aangestuurd kan worden met pin PD5 = OC1A van de ATmega32. Maak een muziek-generator waarmee een (monofoon) melodietje via de luidspreker ten gehore kan worden gebracht.

Uitleg en tips.

Muziek bestaat uit tonen. Elke toon heeft zijn eigen frequentie = toonhoogte. De frequentie van de zogenaamde kamertoon (A') is 440Hz. Een octaaf bestaat uit 12 noten. De frequentie van een noot bij een gelijkzwevende stemming is exact 21/12 = 1,05946309... hoger dan de frequentie van de vorige noot. De twaalf noten heten: A, AIS, B, C, CIS, D, DIS, E, F, FIS, G en GIS. Na 12 noten begint de volgende octaaf (met weer opnieuw 12 noten). De frequentie van de A'', die een octaaf hoger is dan A', is dus exact (21/12)12 = 2 maal zo hoog als de A'.

De file noten@3686000.h bevat een groot aantal #define's waar aan de naam van elke noot een waarde wordt toegekend. Deze waarde komt overeen met het aantal perioden - 1 van de klokfrequentiue van de ATmega32 (3.686000 MHz) dat een halve periode van die betreffende toon duurt. Dit is dus de waarde die in het OCR1A register geladen moet worden als Timer/Counter1 in de CTC mode wordt gebruikt. Telkens als de timer gereset wordt moet pin PD5 geïnverteerd worden.

De kamertoon A' is in C gedefinieerd als:

#define A1  4188

Even narekenen: De frequentie van de A' is 440Hz. Een periode duurt dus 1/440 = 2272,72... µs. Dit zijn 2272,72 * 3,686 = 8377,27 perioden van de clock als de ATmega32 op 3,686 MHz draait. Een halve periode van de A' duurt dus 8377,27/2 = 4188,64 perioden van de clock van de ATmega32. Omdat we alleen maar hele perioden van de clock van de ATmega32 kunnen tellen ronden we dit af tot 4189. In de tabel staat deze waarde - 1 = 4188. Klopt dus :-)

De muziek die de muziek-generator gaat maken is exact in de maat. Dat wil zegen dat elke noot exact even lang (een "tel") gespeeld wordt. Bij een tijdsduur van 0,25 s per noot klinkt de muziek heel redelijk. Je kunt Timer/Counter0 gebruiken om 0,25 s af te tellen.

De muziek die moet worden gespeeld wordt in een tabel in het geheugen opgeslagen. Een tabel die het herkenningsmuziekje van de Adams Family definieerd ziet er als volgt buit:

/* ADDAMS FAMILY */
uint16_t muziekTabel[] = {
    F1,G1,A1,AIS1,AIS1,R,R,R,R,
    G1,A1,B1,C2,C2,R,R,R,R,
    G1,A1,B1,C2,C2,G1,A1,B1,C2,C2,F1,G1,A1,AIS1,AIS1,R,R,R,R,R,R,
    AIS2,D3,AIS2,G2,DIS2,C3,R,
    GIS2,A2,C2,A2,F2,D2,AIS2,R,
    F2,AIS2,D3,AIS2,G2,DIS2,C3,R,
    AIS2,A2,F2,G2,A2,AIS2,AIS2,R,
    F2,AIS2,D3,AIS2,G2,DIS2,C3,R,
    GIS2,A2,C2,A2,F2,D2,AIS2,R,
    F2,AIS2,D3,AIS2,G2,DIS2,C3,R,
    AIS2,A2,F2,G2,A2,AIS2,AIS2,F1,G1,A1,AIS1,AIS1,R,R,R,R,
    G1,A1,B1,C2,R,R,R,R,
    G1,A1,B1,C2,C2,G1,A1,B1,C2,C2,F1,G1,A1,AIS1,AIS1,R,R,R,R,R,R,
    AIS2,D3,AIS2,G2,AIS1,C3,GIS2,A2,C3,A2,F2,D2,AIS2,R,
    F2,AIS2,D3,AIS2,G2,AIS1,C3,R,
    AIS2,A2,A2,F2,F2,G2,G2,A2,A2,AIS2,AIS2,S
}; 

Om de muziek uit de tabel te kunnen spelen moet de muziekgenerator dus eerst 0,25 seconde noot F1 opwekken, daarna 0,25 seconde noot G1 enz. Naast de constanten voor de noten zijn nog drie speciale constanten gedefinieerd die in de muziek tabel gebruikt kunnen worden. Dit zijn:

#define H   1   /*  herhaal */
#define R   2   /*  rust    */
#define S   3   /*  stop    */

De betekenis van deze speciale labels staat in het commentaar achter de constante definitie. Let op: De muziektabel wordt nu afgesloten door een S (stop). Als deze S vervangen wordt door een H moet het muziekje continue blijven spelen!

Tijdens de tel rust kun je PD5 het beste hoog maken omdat anders (als je PD5 tijdens een rust laag maakt) aan het einde van de rust een vervelende tik uit de luidspreker komt. Als je helemaal geen tikken op de speaker wilt horen moet je het OCR1A register alleen laden als er net een Compare Match is geweest.

Aanpak.

Maak een stappenplan en maak voordat je een (deel)programma gaat coderen eerst een ontwerp op papier. De practicumdocent zal naar dit stappenplan en ontwerp vragen bij het aftekenen van je opdracht.

Alternatief deuntje.

Ben je het "Addams Family" muziekje ook een beetje zat? Probeer dan deze eens:

/* POPCORN */
uint16_t muziekTabel[] = {
    A2,G2,A2,E2,C2,E2,A1,R,
    A2,G2,A2,E2,C2,E2,A1,R,
    A2,B2,C3,B2,C3,A2,B2,A2,B2,G2,A2,G2,A2,F2,A2,R,
    A2,G2,A2,E2,C2,E2,A1,R,
    A2,G2,A2,E2,C2,E2,A1,R,
    A2,B2,C3,B2,C3,A2,B2,A2,B2,G2,A2,G2,A2,B2,C3,R,
    E3,D3,E3,C3,G2,C3,E2,R,
    E3,D3,E3,C3,G2,C3,E2,R,
    E3,FIS3,G3,FIS3,G3,E3,FIS3,E3,FIS3,D3,E3,D3,E3,C3,E3,R,
    E3,D3,E3,C3,G2,C3,E2,R,
    E3,D3,E3,C3,G2,C3,E2,R,
    E3,FIS3,G3,FIS3,G3,E3,FIS3,E3,FIS3,D3,E3,D3,E3,C3,E3,R,
    A2,G2,A2,E2,C2,E2,A1,R,
    A2,G2,A2,E2,C2,E2,A1,R,
    A2,B2,C3,B2,C3,A2,B2,A2,B2,G2,A2,G2,A2,F2,A2,R,
    A2,G2,A2,E2,C2,E2,A1,R,
    A2,G2,A2,E2,C2,E2,A1,R,
    A2,B2,C3,B2,C3,A2,B2,A2,B2,G2,A2,G2,B2,G2,C3,C3,C3,S
};

Of deze:

/* SCOOP */
uint16_t muziekTabel[] = {
    C2,C2,R,R,
    C2,C2,A1,B1,B1,R,
    B1,B1,B1,G1,A1,G1,A1,A1,R,R,
    A1,A1,C2,A1,A1,R,
    A1,A1,A1,G1,A1,G1,
    C2,C2,R,R,
    C2,C2,A1,B1,B1,R,
    B1,B1,B1,G1,A1,G1,A1,A1,R,R,
    A1,A1,C2,A1,A1,R,A1,A1,R,R,R,R,H
};

Wie opent de eerste website voor AVR muziek? (Weer eens wat anders dan MP3 of beltoontjes ;-).

Hier is een test tabel:

/* TEST */
uint16_t muziekTabel[] = {
    A1,A1,A1,R,R,R,
    C0,CIS0,D0,DIS0,E0,F0,FIS0,G0,GIS0,A0,AIS0,B0,
    C1,CIS1,D1,DIS1,E1,F1,FIS1,G1,GIS1,A1,AIS1,B1,
    C2,CIS2,D2,DIS2,E2,F2,FIS2,G2,GIS2,A2,AIS2,B2,
    C3,CIS3,D3,DIS3,E3,F3,FIS3,G3,GIS3,A3,AIS3,B3,
    R,R,R,A1,A1,A1,S
};