; ****************************************************************** ; * Musik mit dem STK200 und einem R/2R-Netzwerk * ; * PortD hat acht Tasten (active low), PortB generiert die Ausgabe* ; * fuer das R/2R-Netzwerk, spielt Noten wenn die Tasten betaetigt * ; * werden, fuer ATMEL AT90S8515 bei 4 MHz * ; * (C)2005 by info@avr-asm-tutorial.net * ; ****************************************************************** ; .NOLIST .INCLUDE "8515def.inc" .LIST ; ; Konstanten ; .EQU clock = 4000000 ; Processortakt .EQU cNSine = 32 ; Tabellelaenge Sinustabelle ; .DEF rLen = R1 ; Register fuer Dauer der Ausgabe .DEF rCnt = R2 ; Zaehler fuer die Verzoegerung .DEF rmp = R16 ; Multipurpose Register .DEF rTab = R17 ; Zaehler fuer Tabellenlaenge ; ldi rmp,0xFF ; Alle Bits von Port B Ausgang => R/2R Netzwerk out DDRB,rmp ; an Datenrichtungsregister wtloop: in rmp,PIND ; lese die Tasten cpi rmp,0xFF ; alle Tasten inaktiv? breq wtloop ; je, weiter warten bis aktiv ldi ZH,HIGH(2*MusicTable) ; Z auf Tonhoehentabelle setzen ldi ZL,LOW(2*MusicTable) tabloop: rol rmp ; Rotiere naechstes Bit in Carry brcc tabfound ; gedrueckte Taste gefunden adiw ZL,1 ; Z auf nachsten Tabellenwert rjmp tabloop ; Pruefe naechstes Bit tabfound: lpm ; Lese Tonhoehenwert aus Tabelle in R0 mov rlen,R0 ; Kopiere in delay, R0 wird anderweitig benutzt ; ; Spiele einen Ton, bis die Tasten alle inaktiv sind ; startsine: ldi ZH,HIGH(2*SineTable) ; Z auf die Sinustabelle setzen ldi ZL,LOW(2*SineTable) ldi rTab,cNSine ; Laenge der Sinustabelle ; ; Der folgende Code ist timing-maessig optimiert, damit alle ; Teilschritte gleich lang dauern, die benoetigten Taktzyklen ; sind angegeben, wenn die Instruktion abgearbeitet ist, ; Taktzyklen waehrend Tabellenlesen / Taktzyklen am Tabellenende ; loopsine: in rmp,PIND ; 1/- Pruefe ob Tasten noch aktiv ist cpi rmp,0xFF ; 2/- breq wtloop ; 3/- Taste nicht mehr aktiv, gehe zurueck nop ; 4/- verzoegern fuer Synchronisation loopnext: lpm ; 7/3 Lese Sinustabelle in R0 out PORTB,R0 ; 8/4 Kopiere zum R/2R-Netzwerk mov rCnt,rLen ; 9/5 Setze Verzoegerungszaehler ; Verzoegerungsschleife, braucht 3*rLen-1 Taktzyklen loopdelay: dec rCnt ; (1) naechster Zaehlerwert brne loopdelay ; (2/1) noch nicht Null ; 3*rLen+8/3*rLen+4 am Ende der Verzoegerung adiw ZL,1 ; 3*rLen+10/3*rLen+6 naechster Tabellenwert dec rTab ; 3*rLen+11/3*rLen+7 Anzahl Tabellenwerte brne loopsine ; 3*rLen+13/3*rLen+8 naechster Tabellenwert ldi ZH,HIGH(2*SineTable) ; -/3*rLen+9 Neuanfang Tabelle ldi ZL,LOW(2*SineTable) ; -/3*rLen+10 ldi rTab,cNSine ; -/3*rLen+11 Laenge der Sinustabelle rjmp loopnext ; -/3*rLen+13 Neustart (ohne Tasten!) ; ; Tabelle fuer Verzoegerung zur Tonerzeugung der 8 Frequenzen ; ; Frequenz = clock / Tabellenlaenge / ( 3 * rLen + 13 ) ; rLen = ( clock /Tabellenlaenge / Frequenz - 13 ) / 3 ; MusicTable: ; f=261.6 293.7 329.6 349.2 392.0 440.0 493.9 523.2 (Sollwert) .DB 155, 138, 122, 115, 102, 90, 80, 75 ; f=261.5 292.7 329.8 349.2 391.9 441.7 494.1 525.2 (Istwert) ; Unterschiede zwischen Soll und Ist wegen Rundung und Aufloesung) ; ; Sinustabelle fuer 8 Bits D/A ; Tabellenlaenge = 32 Werte ; VCC=5.000V, uLow=0.000V, uHigh=2.500V ; (mit sinewave.pas erzeugt) ; Sinetable: .DB 64,76,88,99,109,117,123,126 .DB 128,126,123,117,109,99,88,76 .DB 64,51,39,28,19,11,5,1 .DB 0,1,5,11,19,28,39,51 ; ; Ende des Programms ;