;============================================================================= ; Name: MELODIE.A ; Ver.: 1.01 ; Fkt.: Assembler Demo - gibt Melodie über Lautsprecher an PT0 aus ; Auth: Andreas Dannenberg, Oliver Thamm ; Bem.: übersetzen mit "A12 MELODIE" ;============================================================================= cpu 68hc12 ; Assemblerspezifische Anweisungen für padding off ; das Erzeugen von HC12-Code include "reghc12.inc" ; Registerdefinitionen einbinden org $0800 ; Variablenbereich BuzzPeriod ds.w 1 ; Merkzelle für Periodendauer akt. Note org $f000 ; Programm im EEPROM unterbringen ;----------------------------------------------------------------------------- ; Ausführung div. Initialisierungen ;----------------------------------------------------------------------------- lds #$0b00 ; Stack Pointer initialisieren ldaa #$06 ; JMP Opcode laden und in Interrupt- staa $0be8 ; Vektortabelle schreiben (TC0) ldd #isrOC0 ; Zeiger auf Int. Service-Routine std $0be9 ; in Vektortabelle schreiben movb #$32,TMSK2 ; TimerPrescaler=4 (tick=0.5µs) movb #$80,TSCR ; Timer System einschalten bset TIOS,$01 ; PT0 auf Output Compare stellen bclr TCTL2,$03 ; Timer vom PT0 Pin trennen (Ton aus) bset TMSK1,$01 ; lokalen Interrupt für OC0 freigeben cli ; globale Interruptfreigabe ldy #song ; Zeiger auf 1. Notenwert setzen ;----------------------------------------------------------------------------- ; Hauptprogramm-Schleife (spielt Notenwerte aus Tabelle song) ;----------------------------------------------------------------------------- playLoop ldab 0,y ; nächste Note aus Songtabelle holen cmpb #$80 ; Songende schon ereicht? blo nextTone ; wenn nicht, weiterspielen ende bra ende ; wenn ja, Programmende=Endlosschleife nextTone pshb ; Notenwert auf Stack sichern andb #%00001111 ; Notenbits 0..3 isolieren clra ; oberes Byte des Akkus D löschen lsld ; mit 2 multiplizieren addd #freqTBL ; Offset der Frequenztabelle addieren tfr d,x ; ins Indexregister laden ldx 0,x ; und Frequenz aus Tabelle holen pulb ; Notenwert vom Stack zurückholen cpx #0 ; Frequenz auf 0 prüfen beq pause ; Wenn Note=0, Pause einlegen andb #%00010000 ; Note auf tiefe Oktave prüfen (Notenbit 4) beq hoheOkt ; wenn nicht, Frequenz nicht halbieren tfr x,d ; x => d Register lsrd ; Frequenz halbieren tfr d,x ; d => x Register hoheOkt pshx ; Frequenz auf Stack retten ldd #62500 ; 1,000,000 / 16 idiv ; x = d/x, Rest in Akku D xgdx ; d <=> x lsld lsld ; Ergebnis der Division mit lsld ; 16 multiplizieren lsld xgdx ; d <=> x stx BuzzPeriod ; in der Periodendauerzelle merken pulx ; Frequenz vom Stack zurückholen lsld lsld lsld ; Rest obiger Division lsld ; mit 16 multiplizieren idiv ; nochmal durch Frequenz teilen tfr x,d ; und in Akku D übertragen orab BuzzPeriod+1 ; die letzten 4 Bit der Gesamtdivision stab BuzzPeriod+1 ; auch in die Periodendauerzelle übertragen bset TCTL2,$01 ; OC0 action: toggle PT0 Pin (Ton an) pause ldab 0,y ; Notenwert nocheinmal holen andb #%01100000 ; Tondauer-Bits isolieren lsrb ; durch 16 Teilen, um daraus den lsrb ; Offset der Tonlänge (word) in lsrb ; der Tabelle zu bestimmen lsrb clra ; oberes Halbbyte v. Akku D löschen addd #durTBL ; Offset der Tondauer-Tabelle addieren tfr d,x ; Wert ins Indexregister laden ldx 0,x ; Tonlängenwert aus Tabelle holen ldaa #$ff ; verschachtelte Schleife wartet, ploop dbne a,ploop ; bis Note zu Ende gespielt ist dbne x,ploop bclr TCTL2,$03 ; Timer vom PT0 Pin trennen (Ton aus) ldx #1300 ; bis zum Spielen der nächsten Note ldaa #$ff ; noch einen Moment warten ploop2 dbne a,ploop2 ; verschachtelte Schleife dbne x,ploop2 iny ; Notenzeiger um 1 erhöhen bra playLoop ; und nächste Note spielen ;----------------------------------------------------------------------------- ; Interrupt-Service-Routine (ISR) für die Output Compare (OC) 0 Funktion ;----------------------------------------------------------------------------- isrOC0 movb #$01,TFLG1 ; OC0 Interrupt-Flag durch Beschreiben löschen ldd TC0 ; alten Zählwert aus Timer-Register holen addd BuzzPeriod ; dazu Periodendauer der akt. Frequenz addieren std TC0 ; und in OC0-Register zurückschreiben rti ; Rückkehr zur Unterbrechungsstelle im Programm ;----------------------------------------------------------------------------- ; Tabelle zur Umwandlung eines Notenwertes (Zahl 0..12) in eine Frequenz ;----------------------------------------------------------------------------- freqTBL dc.w 0 ; pause dc.w 523 ; c dc.w 554 ; cis dc.w 587 ; d dc.w 622 ; dis dc.w 659 ; e dc.w 698 ; f dc.w 740 ; fis dc.w 784 ; g dc.w 830 ; gis dc.w 880 ; a dc.w 932 ; ais dc.w 987 ; h ;----------------------------------------------------------------------------- ; Tabelle zur Umwandlung der Notendauer in einen Zeitschleifen-Wert ;----------------------------------------------------------------------------- durTBL dc.w 1200 ; 1/4 dc.w 600 ; 1/8 dc.w 2400 ; 1/2 dc.w 1800 ; 3/8 ;----------------------------------------------------------------------------- ; Notendefinitionen (gesamter Notenwert passt in einzelnes Byte) ; ; Die Erzeugung eines Musikstückes erfolgt durch Addition der gewünschten ; Symbolischen Konstanten und Ablage im Speicher per "dc.b"-Anweisung. ; Das Ende des Liedes ist mit der Symbolischen Marke "_STOP" zu kennzeichnen. ; ; Beispiel: song dc.b _A + _DEEP ; Kammerton A, 1/4-Note ; dc.b _PP + _1_2 ; Pause, Länge 1/2-Note ; dc.b _GIS ; G#, hohe Oktave ; dc.b _STOP ; Ende ;----------------------------------------------------------------------------- _PP equ 0 ; Code für Pause (Ton stummgeschaltet) _C equ 1 ; Werte der 12 Töne einer Oktave _CIS equ 2 _D equ 3 _DIS equ 4 _E equ 5 _F equ 6 _FIS equ 7 _G equ 8 _GIS equ 9 _A equ 10 _AIS equ 11 _H equ 12 _HIGH equ $00 ; Oktaven-Codes (Bit 4), hohe Oktave ist voreingest. _DEEP equ $10 ; Tiefe Oktave = Bit 4 gesetzt _1_8 equ $20 ; Tondauer-Codes, Bits 5 und 6 _1_4 equ $00 ; 1/4-Noten sind voreingestellt _3_8 equ $60 _1_2 equ $40 _STOP equ $80 ; Marke für Songende ;----------------------------------------------------------------------------- ; Demosong: "Love Story Theme" ;----------------------------------------------------------------------------- song dc.b _AIS dc.b _D dc.b _D dc.b _AIS dc.b _AIS +_1_2 dc.b _PP dc.b _D dc.b _D dc.b _AIS dc.b _AIS dc.b _D dc.b _DIS dc.b _D dc.b _C dc.b _C dc.b _C dc.b _A dc.b _A +_1_2 dc.b _PP dc.b _C dc.b _C dc.b _A dc.b _A dc.b _C dc.b _D dc.b _C dc.b _AIS +_DEEP dc.b _AIS +_DEEP dc.b _AIS +_DEEP dc.b _G dc.b _G +_1_2 dc.b _PP dc.b _AIS +_DEEP dc.b _AIS +_DEEP dc.b _G dc.b _G dc.b _AIS +_DEEP dc.b _C dc.b _AIS +_DEEP dc.b _A +_DEEP dc.b _A +_DEEP dc.b _A +_DEEP dc.b _FIS dc.b _FIS +_1_2 dc.b _PP dc.b _G +_DEEP dc.b _A +_DEEP dc.b _DIS +_DEEP dc.b _D +_1_2 +_DEEP dc.b _STOP ; Marke für Songende ;-----------------------------------------------------------------------------