Paso 4: Crear el firmware para Marioman
El archivo tar adjunto tiene el archivo de código fuente así como firmware compilado para descargar.
Se utilizaron tres matrices en el código c para generar la música
- Freq [] - las frecuencias de cada nota
- [] longitud - longitud de cada nota
- [demora] - pausa entre cada nota
La matriz de frecuencia no tiene las frecuencias reales sino más bien el valor para poner en el registro TTCROB para generar la onda cuadrada de la pin PB0.
Aquí está un breve resumen de los cálculos y la configuración de pines para la generación de la onda cuadrada:
- El attiny13A tiene un oscilador interno a 9,6 MHz
- El reloj interno de IO es el oscilador dividido por 8 o 1,2 MHz
- Un temporizador interno está configurado en un registro de 8 bits a contar cada ciclo de reloj con prescaler de 8.
- Esto se traduce en una señal igual a 1 / (1.2 MHz / 8) =.006667ms
- El attiny13A está configurado para comparar lo que está en el registro de TCCR0B con el temporizador de 8 bits y cambiar un pin cuando coinciden.
- Por ejemplo, con el fin de generar una onda cuadrada a 524 Hz (una octava sobre C media) que tiene un período de 1.908ms.
1.908ms = 286 reloj garrapatas (1.908/.0067)
Dividir 286 por 2 para cambiar el pin en t/2 (286/2 = 143)
Puesto 143 en el registro de TTCR0B para generar esta nota.
Este es todo el código necesario configurar el temporizador, hacer la comparación y una onda cuadrada de salida:
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
Para retrasar los tonos y las pausas entre ellos se utilizó una función de retardo simple:
void sleep(int ms) { int cnt; for (cnt=0; cnt<(ms); cnt++) { int i = 150; while(i--) { __asm("NOP"); } }}
Esta cuenta regresiva de 150 donde cada ciclo NOP es aproximadamente.006667ms.
Lo último que hace el código es recorrer los arreglos de discos, generan la música y parpadean los LEDs.
Esto se hace en un continuo bucle con el siguiente código:
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 }}
Hay 156 elementos en los arreglos de discos de retardo de frecuencias de longitudes, este bucle recorre los. PIN PB3 y PB4 son cada uno fijada por lo que se alternan con cada nota el primer sueño es la longitud de la nota que tocamos después de establecer el registro de OCR0A en el valor adecuado. El segundo sueño es la pausa entre las notas que tocamos.
En el código anterior podría tener aviso las dos funciones pgm_read_byte() y pgm_read_word(), así como la palabra clave PROGMEM.
Con un chip incrustado como el attiny la cantidad de SRAM es muy limitada, en este caso sólo 64bytes. Los arreglos de discos que estamos utilizando para todos los datos de longitud de frecuencia de retardo son mucho más grandes que 64bytes y por lo tanto no pueden ser cargados en memoria. Mediante el uso de la Directiva de avr-gcc PROGMEM especial que estos arreglos de discos de datos de gran tamaño les impide cargar la memoria, en cambio ellos pueden leer flash.