Étape 4: Créer le firmware pour Marioman
Le fichier ci-joint tar a le fichier source, mais aussi les progiciels compilé par téléchargement.
Trois tableaux dans le code c ont servi à produire de la musique
- FREQ [] - fréquences de chaque note
- [longueur] - durée de chaque note
- [retard] - pause entre chaque note
Le tableau de fréquence n’a pas les fréquences réelles mais plutôt la valeur à mettre dans le registre TTCROB pour générer le signal carré sur la broche PB0.
Voici un bref résumé des calculs et la configuration des broches pour la génération de l’onde carrée :
- L’attiny13A a un oscillateur interne de 9,6 MHz
- L’horloge interne pour IO est l’oscillateur divisé par 8 ou 1,2 MHz
- Une horloge interne est configuré dans un registre de 8 bits à compter vers le haut de chaque cycle d’horloge avec Prédiviseur de 8.
- Il en résulte un tick d’égal à 1 / (1,2 MHz / 8) =.006667ms
- L’attiny13A est configuré pour comparer ce qui est dans le registre TCCR0B avec la minuterie de 8 bits et activer/désactiver un NIP lorsqu’ils correspondent.
- Par exemple, afin de générer une onde carrée à 524 Hz (une octave au-dessus du milieu C) qui dispose d’un délai de 1.908ms.
1.908ms = 286 horloge tiques (1.908/.0067)
Diviser les 286 par 2 pour activer/désactiver la code pin à t/2 (286/2 = 143)
Mettre 143 dans le registre TTCR0B pour générer cette note.
Il s’agit de tout le code qui est nécessaire pour mettre en place la minuterie, faire le comparer et sortie un signal carré :
TCCR0A |= (1<<WGM01); // configure timer 1 for CTC mode TCCR0A |= (1<<COM0A0); // toggle OC0A on compare match TCCR0B |= (1<<CS01); // clk/8 prescale TTCR0B = 143; // generate a square wave at 524Hz
Pour retarder les tons et les pauses entre eux une fonction de retard simple a été utilisée :
void sleep(int ms) { int cnt; for (cnt=0; cnt<(ms); cnt++) { int i = 150; while(i--) { __asm("NOP"); } }}
Ce compte à rebours de 150 où chaque cycle NOP est environ.006667ms.
La dernière chose que le code n’est effectuer une boucle sur les baies, générer de la musique et clignoter deux LED.
Cela se fait en continu pour les boucles avec le code suivant :
const uint8_t freq[] PROGMEM = { ... data };const uint8_t length[] PROGMEM = { ... data };const uint8_t delay[] PROGMEM = { ... data };...while (1) { for (cnt=0; cnt<156; cnt++) { OCR0A=pgm_read_byte(&freq[cnt]); output_toggle(PORTB,PB3); output_toggle(PORTB,PB4); sleep( pgm_read_byte(&length[cnt]) ); output_toggle(PORTB,PB3); output_toggle(PORTB,PB4); // stop timer TCCR0B = 0; sleep ( pgm_read_word(&delay[cnt]) ); // start timer TCCR0B |= (1<<CS01); // clk/8 prescale }}
Il y a 156 éléments dans les tableaux de fréquences/longueurs/retard, cette boucle traverse eux. Broche PB3 et PB4 sont chacun activé/désactivé afin qu’ils seront affichent en alternance avec chaque note le premier sommeil correspond à la longueur de la note Qu'on joue après avoir réglé le registre OCR0A la valeur appropriée. Le second sommeil est la pause entre les notes que nous jouons.
Dans le code ci-dessus, vous pourriez avoir des avis les deux fonctions pgm_read_byte() et pgm_read_word() ainsi que le mot clé PROGMEM.
Avec une puce intégrée comme l’attiny la quantité de SRAM est très limitée, dans ce cas 64bytes seul. Les tableaux que nous utilisons pour toutes les données de fréquence/retard/longueur sont beaucoup plus grandes que 64bytes et ne peuvent donc pas être chargés en mémoire. En utilisant la directive spéciale d’avr-gcc PROGMEM que ces tableaux de données volumineuses est empêchés de se charger dans la mémoire, au lieu de cela, ils sont lus de flash.