Blinkar, sång, Marioman (4 / 5 steg)
Steg 4: Skapa firmware för Marioman
Bifogade tar-filen har den källfil som kompilerade firmware för nedladdning.
Tre matriser i c kod användes för att generera musik
- [] freq - frekvenser för varje not
- [längd] - längd för varje not
- dröjsmål [] - paus mellan varje ton
Arrayen frekvens har inte de faktiska frekvenserna men ganska värdet som placeras i TTCROB register att generera fyrkantsvåg off PB0 PIN-koden.
Här är en kort sammanfattning av de beräkningar och pin-konfiguration för fyrkantsvåg generation:
- Attiny13A har en intern oscillator inställd 9.6MHz
- Den interna klockan för IO är oscillatorn dividerat med 8 eller 1.2 MHz
- En inre timer är setup i ett 8-bitars register att räkna upp varje klockcykel med prescale av 8.
- Detta resulterar i en fästing motsvarar 1 / (1.2 MHz / 8) =.006667ms
- Attiny13A är konfigurerad för att jämföra vad som finns i 8-bitars TCCR0B register med timer och växla en PIN-kod när de matchar.
- Till exempel, för att generera en fyrkantsvåg på 524 Hz (en oktav över mitten C) som har en period av 1.908ms.
1.908ms = 286 klocka fästingar (1.908/.0067)
Dela upp 286 av 2 för att växla den PIN-kod på t/2 (286/2 = 143)
Sätta 143 i TTCR0B register att generera denna anmärkning.
Detta är all kod som behövs för att ställa in timern, jämför och utgång en fyrkantsvåg:
TCCR0A | = (1 << WGM01); Konfigurera timer 1 för CTC läge TCCR0A | = (1 << COM0A0); Växla OC0A på Jämför matcha TCCR0B | = (1 << CS01); CLK/8 prescale TTCR0B = 143; Generera en fyrkantsvåg på 524Hz
För att fördröja tonen och pauser mellan dem användes en enkel dröjsmål funktion:
Annullera sömn (int ms) {int cnt; för (cnt = 0; cnt < (ms), cnt ++) {int jag = 150, while(i--) {__asm("NOP");}}}
Detta räknar ner från 150 där varje NOP cykel är cirka.006667ms.
Det sista koden gör är loopa igenom arrayer, skapa musik och blinka två lysdioder.
Detta görs fortlöpande för slinga med följande kod:
CONST uint8_t freq [] PROGMEM = {... data}; const uint8_t längd [PROGMEM] = {... data}; const uint8_t fördröja [PROGMEM] = {... data};.. medan (1) {för (cnt = 0; cnt < 156; cnt ++) {OCR0A = pgm_read_byte (& freq[cnt]); output_toggle(PORTB,PB3); output_toggle(PORTB,PB4); sömn (pgm_read_byte(&length[cnt])); output_toggle(PORTB,PB3); output_toggle(PORTB,PB4); / / stopp tidtagare TCCR0B = 0; sömn (pgm_read_word(&delay[cnt])); / / start timer TCCR0B | = (1 << CS01); / / clk/8 prescale}}
Det finns 156 element i frekvenser/längder/fördröjning matriser, denna loop korsar dem. PIN PB3 och PB4 är varje växlas så de kommer att varvas med varje not första sömnen är längden på anteckningen vi spelar efter att OCR0A registret till lämpligt värde. Andra sömnen är paus mellan de anteckningar vi spelar.
I koden ovan kanske du måste märka två funktionerna pgm_read_byte() och pgm_read_word() samt nyckelordet PROGMEM.
Med en inbäddad chip som attiny är mängden SRAM mycket begränsad, i detta fall endast 64bytes. De matriser som vi använder för alla frekvens/fördröjning/längd data är mycket större än 64bytes och därför kan inte läsas in i minnet. Genom att använda särskilda PROGMEM avr-gcc direktivet dessa stora datamatriser hindras från att laddas in i minnet, i stället läses de från flash.