; ; =========================================================================== ; dds-seq.asm - Schrittsequenzer fuer den ATmega8-Funktionsgenerator von 2003 ; ; Eigenstaendige Quelle. Der Generator von damals (Wellenformtaste, vier ; Stimmtasten, Frequenzanzeige) ist hier nicht mehr enthalten - das Geraet ist ; ein reiner Achtschritt-Sequenzer und spielt ab dem Einschalten. Uebernommen ; sind aus da-test.asm der DDS-Interrupt, die LCD-Ansteuerung und die ; Warteschleifen; alles andere ist neu. ; ; Anzeige, bewusst ohne selbstdefinierte Zeichen: ; ; Zeile 1 acht Schritte zu zwei Zeichen: Notenname und Oktave. ; Grossbuchstabe = Stammton, Kleinbuchstabe = erhoeht, ; also "A2" = A2 und "a2" = Ais2. Pause ist "--". ; Zeile 2 Laufbalken, Auswahl, Note, Akzent, Bindung, Wellenform, Modus. ; ; Die CGRAM-Grafik der Vorgaengerversion sah huebscher aus, kostete aber bei ; jedem Schritt rund 5 ms LCD-Verkehr, und solange kommt die Hauptschleife ; nicht dazu, die Huellkurve nachzufuehren. Jetzt schreibt ein Schritt genau ; ein Zeichen (die Ziffer des Laufbalkens), der Rest der Anzeige nur noch auf ; Tastendruck. ; ; Tasten: ; PC0 -- Wert verringern / ausschalten ; PC1 - Schritt zurueck ; PC2 + Schritt vor ; PC3 ++ Wert erhoehen / einschalten ; PC4 Editierziel: Tonhoehe, Akzent, Bindung, Wellenform ; PC5 Start / Stop (am realen Aufbau die einzige freie Leitung) ; =========================================================================== .include "m8def.inc" ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Konstanten ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; .equ COMPAREVALUE = 24 ; Interrupt alle 25 Takte = 262144 Hz .equ KEY_DOWNF = 0 .equ KEY_DOWN = 1 .equ KEY_UP = 2 .equ KEY_UPF = 3 .equ KEY_MODE = 4 .equ KEY_RUN = 5 .equ SEQLEN = 8 ; Schritte .equ NOTEMAX = 37 ; A2..A5, drei Oktaven .equ SEQTICKS = 1280 ; 200 ms je Schritt (Timer0, 6400 Hz) .equ SWING = 256 ; Shuffle: +/- auf ungeraden Schritten .equ ACCAMP = 255 ; Amplitude mit Akzent .equ NRMAMP = 150 ; Amplitude ohne Akzent .equ ENVTICK = 24 ; Timer0-Schritte je Ausklangschritt .equ ATKSTEP = 4 ; Anstieg je Timer0-Schritt, ~10 ms .equ RELSTEP = 16 ; Abriss vor dem Schritt, <1 ms .equ GLIDESH = 6 ; Bindung: Schritt = Abstand>>6 + 1 .equ KEYTICK = 64 ; Tastenabtastung alle 10 ms ; Zustand im SRAM. Register sind keine mehr frei: nach Phasenakkumulator, ; Huellkurve und Zeigern bleiben nur R14/R15. .equ SEQPAT = 0x0100 ; SEQLEN Notenindizes, 0 = Pause .equ SEQACCENT = 0x0108 ; SEQLEN Akzent-Flags .equ SEQSLIDE = 0x0110 ; SEQLEN Bindungs-Flags .equ SEQWAVE = 0x0118 ; SEQLEN Tabellenseiten (ZH) .equ SEQRUN = 0x0120 .equ SEQSTEP = 0x0121 ; spielender Schritt .equ SEQSEL = 0x0122 ; ausgewaehlter Schritt .equ SEQACCL = 0x0123 ; Taktakkumulator .equ SEQACCH = 0x0124 .equ SEQLAST = 0x0125 ; TCNT0 beim letzten Aufruf .equ SEQDELTA = 0x0126 .equ EDITMODE = 0x0127 ; 0 Tonhoehe 1 Akzent 2 Bindung 3 Form .equ PENDING = 0x0128 ; Schrittwechsel wartet auf Stille .equ ATKTGT = 0x0129 ; Ziel des Anstiegs, 0 = fertig .equ TGTL = 0x012A ; Zielfrequenz der Bindung .equ TGTM = 0x012B .equ TGTH = 0x012C .equ KEYLAST = 0x012D ; Tastenzustand beim letzten Abtasten .equ KEYACC = 0x012E ; Abtast- und Entprelltakt ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Registerdefinitionen ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; .def null = R13 ; immer 0 - bewusst nicht R1, das ; ueberschreibt mul im Interrupt .def ampbias = R8 ; 128 - amp/2, siehe Interrupt .def sregsave = R9 ; Statusregister im Interrupt .def envacc = R10 ; aufsummierte TCNT0-Differenzen .def envlast = R11 ; TCNT0 beim letzten Aufruf .def amp = R19 ; Amplitude 0..255 .def temp1 = R16 .def temp2 = R17 .def temp3 = R18 .def change1 = R3 ; Schrittweite des Phasenakkumulators .def change2 = R4 .def change3 = R5 .def z1 = R28 ; Phasenakkumulator, 24 Bit; .def z2 = R29 ; z3 ist zugleich ZL und damit der .def z3 = R30 ; Index in die Wellenformtabelle ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Makros ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; .MACRO SetZPtr ;(Adresse) ldi ZL, LOW(@0) ldi ZH, HIGH(@0) .ENDMACRO .MACRO locate ;(Zeile,Spalte) ldi temp1, 0b10000000|(((@0)-1)<<6)|((@1)-1) rcall lcd_command .ENDMACRO .MACRO waitms ldi temp1, @0*6 rcall wms .ENDMACRO .MACRO wait10ms ldi temp1, @0 rcall w10ms .ENDMACRO ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Interruptvektoren ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; .org 0x000 rjmp RESET .org OC1Aaddr ; Timer1 Compare Match A ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Timer-Interrupt ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Verzweigungsfrei: alle acht Signalformen liegen als Tabelle im Flash, der ; Z-Pointer zeigt immer schon auf die richtige. Die Amplitude kommt aus einer ; Multiplikation - der ATmega8 hat einen Hardware-Multiplizierer, mul kostet ; also nur zwei Takte: ; ; Ausgabe = 128 + amp * (Tabellenwert - 128) / 256 ; ; gerechnet als (Wert*amp)>>8 + ampbias, wobei die Hauptschleife ; ampbias = 128 - amp/2 mitfuehrt. Bei amp = 0 kommt exakt 128 heraus, also ; Stille in der Mittellage, ohne Gleichspannungssprung. ; ; mul schreibt sein Ergebnis fest nach R1:R0. Deshalb liegt das Null-Register ; hier auf R13 und nicht wie im Original auf R1 - sonst muesste der Interrupt ; es 262144 Mal pro Sekunde mit clr wiederherstellen. timer: in sregsave, SREG ; Statusregister sichern lpm ; R0 = Tabellenwert mul R0, amp ; R1:R0 = Wert * Amplitude add R1, ampbias ; zurueck auf die Mittellage out PORTD, R1 ; an den Digital-Analog-Wandler add z1, change1 ; Phasenakkumulator adc z2, change2 adc z3, change3 out SREG, sregsave reti ; 16 Takte ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Wellenformtabellen ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Je 256 Bytes, auf 256-Byte-Grenzen ausgerichtet, damit ZL unmittelbar als ; Index dienen kann. Die Seitennummer (ZH) waehlt die Form: 2 Sinus, ; 3 Dreieck, 4 Rechteck, 5 Saegezahn, 6 Orgel, 7 Glocke, 8 Puls, 9 Treppe. .org 0x100 SINTABLE: ; Seite 2 - Sinus .db 0x80,0x83,0x86,0x89,0x8c,0x90,0x93,0x96 .db 0x99,0x9c,0x9f,0xa2,0xa5,0xa8,0xab,0xae .db 0xb1,0xb3,0xb6,0xb9,0xbc,0xbf,0xc1,0xc4 .db 0xc7,0xc9,0xcc,0xce,0xd1,0xd3,0xd5,0xd8 .db 0xda,0xdc,0xde,0xe0,0xe2,0xe4,0xe6,0xe8 .db 0xea,0xeb,0xed,0xef,0xf0,0xf1,0xf3,0xf4 .db 0xf5,0xf6,0xf8,0xf9,0xfa,0xfa,0xfb,0xfc .db 0xfd,0xfd,0xfe,0xfe,0xfe,0xff,0xff,0xff .db 0xff,0xff,0xff,0xff,0xfe,0xfe,0xfe,0xfd .db 0xfd,0xfc,0xfb,0xfa,0xfa,0xf9,0xf8,0xf6 .db 0xf5,0xf4,0xf3,0xf1,0xf0,0xef,0xed,0xeb .db 0xea,0xe8,0xe6,0xe4,0xe2,0xe0,0xde,0xdc .db 0xda,0xd8,0xd5,0xd3,0xd1,0xce,0xcc,0xc9 .db 0xc7,0xc4,0xc1,0xbf,0xbc,0xb9,0xb6,0xb3 .db 0xb1,0xae,0xab,0xa8,0xa5,0xa2,0x9f,0x9c .db 0x99,0x96,0x93,0x90,0x8c,0x89,0x86,0x83 .db 0x80,0x7d,0x7a,0x77,0x74,0x70,0x6d,0x6a .db 0x67,0x64,0x61,0x5e,0x5b,0x58,0x55,0x52 .db 0x4f,0x4d,0x4a,0x47,0x44,0x41,0x3f,0x3c .db 0x39,0x37,0x34,0x32,0x2f,0x2d,0x2b,0x28 .db 0x26,0x24,0x22,0x20,0x1e,0x1c,0x1a,0x18 .db 0x16,0x15,0x13,0x11,0x10,0x0f,0x0d,0x0c .db 0x0b,0x0a,0x08,0x07,0x06,0x06,0x05,0x04 .db 0x03,0x03,0x02,0x02,0x02,0x01,0x01,0x01 .db 0x01,0x01,0x01,0x01,0x02,0x02,0x02,0x03 .db 0x03,0x04,0x05,0x06,0x06,0x07,0x08,0x0a .db 0x0b,0x0c,0x0d,0x0f,0x10,0x11,0x13,0x15 .db 0x16,0x18,0x1a,0x1c,0x1e,0x20,0x22,0x24 .db 0x26,0x28,0x2b,0x2d,0x2f,0x32,0x34,0x37 .db 0x39,0x3c,0x3f,0x41,0x44,0x47,0x4a,0x4d .db 0x4f,0x52,0x55,0x58,0x5b,0x5e,0x61,0x64 .db 0x67,0x6a,0x6d,0x70,0x74,0x77,0x7a,0x7d TRIANGLETABLE: ; Seite 3 - Dreieck .db 0x00,0x02,0x04,0x06,0x08,0x0a,0x0c,0x0e .db 0x10,0x12,0x14,0x16,0x18,0x1a,0x1c,0x1e .db 0x20,0x22,0x24,0x26,0x28,0x2a,0x2c,0x2e .db 0x30,0x32,0x34,0x36,0x38,0x3a,0x3c,0x3e .db 0x40,0x42,0x44,0x46,0x48,0x4a,0x4c,0x4e .db 0x50,0x52,0x54,0x56,0x58,0x5a,0x5c,0x5e .db 0x60,0x62,0x64,0x66,0x68,0x6a,0x6c,0x6e .db 0x70,0x72,0x74,0x76,0x78,0x7a,0x7c,0x7e .db 0x80,0x82,0x84,0x86,0x88,0x8a,0x8c,0x8e .db 0x90,0x92,0x94,0x96,0x98,0x9a,0x9c,0x9e .db 0xa0,0xa2,0xa4,0xa6,0xa8,0xaa,0xac,0xae .db 0xb0,0xb2,0xb4,0xb6,0xb8,0xba,0xbc,0xbe .db 0xc0,0xc2,0xc4,0xc6,0xc8,0xca,0xcc,0xce .db 0xd0,0xd2,0xd4,0xd6,0xd8,0xda,0xdc,0xde .db 0xe0,0xe2,0xe4,0xe6,0xe8,0xea,0xec,0xee .db 0xf0,0xf2,0xf4,0xf6,0xf8,0xfa,0xfc,0xfe .db 0xfe,0xfc,0xfa,0xf8,0xf6,0xf4,0xf2,0xf0 .db 0xee,0xec,0xea,0xe8,0xe6,0xe4,0xe2,0xe0 .db 0xde,0xdc,0xda,0xd8,0xd6,0xd4,0xd2,0xd0 .db 0xce,0xcc,0xca,0xc8,0xc6,0xc4,0xc2,0xc0 .db 0xbe,0xbc,0xba,0xb8,0xb6,0xb4,0xb2,0xb0 .db 0xae,0xac,0xaa,0xa8,0xa6,0xa4,0xa2,0xa0 .db 0x9e,0x9c,0x9a,0x98,0x96,0x94,0x92,0x90 .db 0x8e,0x8c,0x8a,0x88,0x86,0x84,0x82,0x80 .db 0x7e,0x7c,0x7a,0x78,0x76,0x74,0x72,0x70 .db 0x6e,0x6c,0x6a,0x68,0x66,0x64,0x62,0x60 .db 0x5e,0x5c,0x5a,0x58,0x56,0x54,0x52,0x50 .db 0x4e,0x4c,0x4a,0x48,0x46,0x44,0x42,0x40 .db 0x3e,0x3c,0x3a,0x38,0x36,0x34,0x32,0x30 .db 0x2e,0x2c,0x2a,0x28,0x26,0x24,0x22,0x20 .db 0x1e,0x1c,0x1a,0x18,0x16,0x14,0x12,0x10 .db 0x0e,0x0c,0x0a,0x08,0x06,0x04,0x02,0x00 SQUARETABLE: ; Seite 4 - Rechteck .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff .db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 .db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 .db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 .db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 .db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 .db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 .db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 .db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 .db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 .db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 .db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 .db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 .db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 .db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 .db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 .db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 SAWTOOTHTABLE: ; Seite 5 - Saegezahn .db 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07 .db 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f .db 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17 .db 0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f .db 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27 .db 0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f .db 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37 .db 0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f .db 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47 .db 0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f .db 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57 .db 0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f .db 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67 .db 0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f .db 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77 .db 0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f .db 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87 .db 0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f .db 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97 .db 0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f .db 0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7 .db 0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf .db 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7 .db 0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf .db 0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7 .db 0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf .db 0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7 .db 0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf .db 0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7 .db 0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef .db 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7 .db 0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff ORGANTABLE: ; Seite 6 - Orgel, additive Harmonische .db 0x80,0x8c,0x98,0xa4,0xb0,0xbb,0xc5,0xce .db 0xd7,0xdf,0xe6,0xec,0xf1,0xf5,0xf9,0xfb .db 0xfd,0xfe,0xff,0xff,0xff,0xfe,0xfd,0xfc .db 0xfb,0xfa,0xf8,0xf7,0xf6,0xf5,0xf4,0xf3 .db 0xf2,0xf1,0xf0,0xef,0xee,0xed,0xeb,0xea .db 0xe8,0xe6,0xe4,0xe1,0xdf,0xdc,0xd9,0xd5 .db 0xd2,0xcf,0xcb,0xc8,0xc5,0xc2,0xbf,0xbc .db 0xba,0xb8,0xb6,0xb4,0xb3,0xb2,0xb1,0xb0 .db 0xb0,0xaf,0xaf,0xaf,0xaf,0xae,0xae,0xae .db 0xad,0xad,0xac,0xac,0xab,0xab,0xaa,0xa9 .db 0xa9,0xa9,0xa8,0xa8,0xa8,0xa8,0xa8,0xa9 .db 0xa9,0xaa,0xaa,0xab,0xab,0xac,0xac,0xac .db 0xac,0xab,0xaa,0xa9,0xa8,0xa5,0xa3,0xa0 .db 0x9c,0x99,0x95,0x90,0x8c,0x88,0x83,0x7f .db 0x7b,0x77,0x74,0x71,0x6e,0x6d,0x6c,0x6b .db 0x6b,0x6c,0x6e,0x70,0x72,0x75,0x79,0x7c .db 0x80,0x84,0x87,0x8b,0x8e,0x90,0x92,0x94 .db 0x95,0x95,0x94,0x93,0x92,0x8f,0x8c,0x89 .db 0x85,0x81,0x7d,0x78,0x74,0x70,0x6b,0x67 .db 0x64,0x60,0x5d,0x5b,0x58,0x57,0x56,0x55 .db 0x54,0x54,0x54,0x54,0x55,0x55,0x56,0x56 .db 0x57,0x57,0x58,0x58,0x58,0x58,0x58,0x57 .db 0x57,0x57,0x56,0x55,0x55,0x54,0x54,0x53 .db 0x53,0x52,0x52,0x52,0x51,0x51,0x51,0x51 .db 0x50,0x50,0x4f,0x4e,0x4d,0x4c,0x4a,0x48 .db 0x46,0x44,0x41,0x3e,0x3b,0x38,0x35,0x31 .db 0x2e,0x2b,0x27,0x24,0x21,0x1f,0x1c,0x1a .db 0x18,0x16,0x15,0x13,0x12,0x11,0x10,0x0f .db 0x0e,0x0d,0x0c,0x0b,0x0a,0x09,0x08,0x06 .db 0x05,0x04,0x03,0x02,0x01,0x01,0x01,0x02 .db 0x03,0x05,0x07,0x0b,0x0f,0x14,0x1a,0x21 .db 0x29,0x32,0x3b,0x45,0x50,0x5c,0x68,0x74 BELLTABLE: ; Seite 7 - Glocke, weit gespreizte Partialtoene .db 0x80,0x90,0xa0,0xaf,0xbd,0xc9,0xd4,0xdd .db 0xe4,0xe9,0xed,0xef,0xf0,0xf0,0xef,0xee .db 0xed,0xeb,0xeb,0xea,0xea,0xea,0xeb,0xec .db 0xec,0xed,0xed,0xed,0xec,0xea,0xe8,0xe5 .db 0xe1,0xdd,0xd9,0xd4,0xd0,0xcc,0xc8,0xc5 .db 0xc3,0xc1,0xc0,0xc0,0xc0,0xc0,0xc1,0xc1 .db 0xc1,0xc0,0xbf,0xbc,0xb9,0xb5,0xb0,0xaa .db 0xa4,0x9e,0x99,0x93,0x8f,0x8c,0x8b,0x8b .db 0x8e,0x92,0x97,0x9e,0xa7,0xb1,0xbb,0xc6 .db 0xd0,0xda,0xe3,0xeb,0xf2,0xf8,0xfc,0xfe .db 0xff,0xff,0xfe,0xfc,0xf9,0xf7,0xf4,0xf1 .db 0xef,0xec,0xeb,0xe9,0xe8,0xe6,0xe5,0xe3 .db 0xe1,0xdf,0xdc,0xd8,0xd4,0xd0,0xcb,0xc5 .db 0xc0,0xbc,0xb7,0xb4,0xb1,0xaf,0xae,0xae .db 0xaf,0xb0,0xb2,0xb4,0xb6,0xb8,0xb9,0xb9 .db 0xb8,0xb6,0xb2,0xac,0xa5,0x9d,0x94,0x8a .db 0x80,0x76,0x6c,0x63,0x5b,0x54,0x4e,0x4a .db 0x48,0x47,0x47,0x48,0x4a,0x4c,0x4e,0x50 .db 0x51,0x52,0x52,0x51,0x4f,0x4c,0x49,0x44 .db 0x40,0x3b,0x35,0x30,0x2c,0x28,0x24,0x21 .db 0x1f,0x1d,0x1b,0x1a,0x18,0x17,0x15,0x14 .db 0x11,0x0f,0x0c,0x09,0x07,0x04,0x02,0x01 .db 0x01,0x02,0x04,0x08,0x0e,0x15,0x1d,0x26 .db 0x30,0x3a,0x45,0x4f,0x59,0x62,0x69,0x6e .db 0x72,0x75,0x75,0x74,0x71,0x6d,0x67,0x62 .db 0x5c,0x56,0x50,0x4b,0x47,0x44,0x41,0x40 .db 0x3f,0x3f,0x3f,0x40,0x40,0x40,0x40,0x3f .db 0x3d,0x3b,0x38,0x34,0x30,0x2c,0x27,0x23 .db 0x1f,0x1b,0x18,0x16,0x14,0x13,0x13,0x13 .db 0x14,0x14,0x15,0x16,0x16,0x16,0x15,0x15 .db 0x13,0x12,0x11,0x10,0x10,0x11,0x13,0x17 .db 0x1c,0x23,0x2c,0x37,0x43,0x51,0x60,0x70 PULSETABLE: ; Seite 8 - Puls, 25% Tastverhaeltnis .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff .db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 .db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 .db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 .db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 .db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 .db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 .db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 .db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 .db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 .db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 .db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 .db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 .db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 .db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 .db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 .db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 .db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 .db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 .db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 .db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 .db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 .db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 .db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 .db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 STAIRSTABLE: ; Seite 9 - Treppe, 8 Stufen statt 256 .db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 .db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 .db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 .db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 .db 0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24 .db 0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24 .db 0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24 .db 0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24 .db 0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49 .db 0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49 .db 0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49 .db 0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49 .db 0x6d,0x6d,0x6d,0x6d,0x6d,0x6d,0x6d,0x6d .db 0x6d,0x6d,0x6d,0x6d,0x6d,0x6d,0x6d,0x6d .db 0x6d,0x6d,0x6d,0x6d,0x6d,0x6d,0x6d,0x6d .db 0x6d,0x6d,0x6d,0x6d,0x6d,0x6d,0x6d,0x6d .db 0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92 .db 0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92 .db 0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92 .db 0x92,0x92,0x92,0x92,0x92,0x92,0x92,0x92 .db 0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6 .db 0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6 .db 0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6 .db 0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6,0xb6 .db 0xdb,0xdb,0xdb,0xdb,0xdb,0xdb,0xdb,0xdb .db 0xdb,0xdb,0xdb,0xdb,0xdb,0xdb,0xdb,0xdb .db 0xdb,0xdb,0xdb,0xdb,0xdb,0xdb,0xdb,0xdb .db 0xdb,0xdb,0xdb,0xdb,0xdb,0xdb,0xdb,0xdb .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Tabellen im EEPROM ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Der DDS-Interrupt besitzt den Z-Pointer, also darf die Hauptschleife kein ; lpm benutzen. Diese Tabellen liegen deshalb im EEPROM und werden ueber die ; EEPROM-Register gelesen. .eseg .org 0x10 notetable: ; change = f * 64, A2 bis A5 .db 0x80,0x1b,0x00 ; A2 110.00 Hz .db 0x23,0x1d,0x00 ; A#2 116.55 Hz .db 0xde,0x1e,0x00 ; B2 123.47 Hz .db 0xb4,0x20,0x00 ; C3 130.81 Hz .db 0xa6,0x22,0x00 ; C#3 138.59 Hz .db 0xb5,0x24,0x00 ; D3 146.83 Hz .db 0xe4,0x26,0x00 ; D#3 155.56 Hz .db 0x34,0x29,0x00 ; E3 164.81 Hz .db 0xa7,0x2b,0x00 ; F3 174.61 Hz .db 0x40,0x2e,0x00 ; F#3 185.00 Hz .db 0x00,0x31,0x00 ; G3 196.00 Hz .db 0xea,0x33,0x00 ; G#3 207.66 Hz .db 0x00,0x37,0x00 ; A3 220.00 Hz .db 0x45,0x3a,0x00 ; A#3 233.08 Hz .db 0xbc,0x3d,0x00 ; B3 246.94 Hz .db 0x68,0x41,0x00 ; C4 261.62 Hz .db 0x4c,0x45,0x00 ; C#4 277.19 Hz .db 0x6b,0x49,0x00 ; D4 293.67 Hz .db 0xc8,0x4d,0x00 ; D#4 311.12 Hz .db 0x68,0x52,0x00 ; E4 329.62 Hz .db 0x4f,0x57,0x00 ; F4 349.23 Hz .db 0x80,0x5c,0x00 ; F#4 370.00 Hz .db 0x00,0x62,0x00 ; G4 392.00 Hz .db 0xd4,0x67,0x00 ; G#4 415.31 Hz .db 0x00,0x6e,0x00 ; A4 440.00 Hz .db 0x8a,0x74,0x00 ; A#4 466.16 Hz .db 0x79,0x7b,0x00 ; B4 493.89 Hz .db 0xd0,0x82,0x00 ; C5 523.25 Hz .db 0x97,0x8a,0x00 ; C#5 554.36 Hz .db 0xd5,0x92,0x00 ; D5 587.33 Hz .db 0x90,0x9b,0x00 ; D#5 622.25 Hz .db 0xd0,0xa4,0x00 ; E5 659.25 Hz .db 0x9d,0xae,0x00 ; F5 698.45 Hz .db 0xff,0xb8,0x00 ; F#5 739.98 Hz .db 0xff,0xc3,0x00 ; G5 783.98 Hz .db 0xa7,0xcf,0x00 ; G#5 830.61 Hz .db 0x00,0xdc,0x00 ; A5 880.00 Hz .org 0x80 lettertable: ; Halbton 0..11 -> Zeichen, .db "AaBCcDdEFfGg" ; klein = erhoeht .cseg ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Initialisierung ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; RESET: ldi temp1, LOW(RAMEND) ; Stackpointer out SPL, temp1 ldi temp1, HIGH(RAMEND) out SPH, temp1 clr null clr envacc clr envlast ldi temp1, 0x00 ; EEPROM-Adresse immer unter 256 out EEARH, temp1 ldi temp1, 128 ; Mittellage einstellen, BEVOR der Port out PORTD, temp1 ; treibt - sonst haengt die R-2R-Leiter ldi temp1, 0xFF ; bis zum ersten Interrupt am unteren out DDRD, temp1 ; Anschlag, und es knackt zweimal: ; beim Einschalten und noch einmal, ; wenn der Interrupt auf 128 springt ldi temp1, 0x00 out DDRC, temp1 ; Port C = Eingang, Tasten ldi temp1, 0xFF out PORTC, temp1 ; mit internen Pullups ldi temp1, 0xFF out DDRB, temp1 ; Port B = Ausgang, LCD ldi temp1, 0x00 out PORTB, temp1 clr change1 ; Phasenakkumulator ruht, bis der clr change2 ; erste Schritt spielt clr change3 clr z1 clr z2 clr z3 SetZPtr(SINTABLE*2) clr amp ; still starten ldi temp1, 128 mov ampbias, temp1 ldi XH, high(SEQPAT) ; Grundmuster ldi XL, low(SEQPAT) ; Noten ldi temp1, 1 st X+, temp1 ldi temp1, 13 st X+, temp1 ldi temp1, 1 st X+, temp1 ldi temp1, 16 st X+, temp1 ldi temp1, 0 st X+, temp1 ldi temp1, 20 st X+, temp1 ldi temp1, 11 st X+, temp1 ldi temp1, 8 st X+, temp1 ldi XL, low(SEQACCENT) ; Akzente ldi temp1, 1 st X+, temp1 ldi temp1, 0 st X+, temp1 ldi temp1, 0 st X+, temp1 ldi temp1, 1 st X+, temp1 ldi temp1, 0 st X+, temp1 ldi temp1, 0 st X+, temp1 ldi temp1, 1 st X+, temp1 ldi temp1, 0 st X+, temp1 ldi XL, low(SEQSLIDE) ; Bindungen ldi temp1, 0 st X+, temp1 ldi temp1, 1 st X+, temp1 ldi temp1, 0 st X+, temp1 ldi temp1, 0 st X+, temp1 ldi temp1, 0 st X+, temp1 ldi temp1, 1 st X+, temp1 ldi temp1, 0 st X+, temp1 ldi temp1, 0 st X+, temp1 ldi XL, low(SEQWAVE) ; Wellenformen ldi temp1, 5 st X+, temp1 ldi temp1, 5 st X+, temp1 ldi temp1, 8 st X+, temp1 ldi temp1, 7 st X+, temp1 ldi temp1, 2 st X+, temp1 ldi temp1, 7 st X+, temp1 ldi temp1, 6 st X+, temp1 ldi temp1, 3 st X+, temp1 clr temp1 sts SEQSTEP, temp1 sts SEQSEL, temp1 sts SEQACCL, temp1 sts SEQACCH, temp1 sts SEQLAST, temp1 sts SEQDELTA, temp1 sts EDITMODE, temp1 sts PENDING, temp1 sts ATKTGT, temp1 sts TGTL, temp1 sts TGTM, temp1 sts TGTH, temp1 sts KEYACC, temp1 ldi temp1, 0b00111111 sts KEYLAST, temp1 ; alle Tasten losgelassen clr temp1 inc temp1 sts SEQRUN, temp1 ; laeuft ab dem Einschalten ldi temp1, COMPAREVALUE ; Timer1: CTC, kein Vorteiler out OCR1AH, null out OCR1AL, temp1 ldi temp1, (1<>GLIDESH + 1; das +1 sorgt dafuer, dass das Ziel exakt erreicht ; und nie ueberschossen wird. glide: lds temp1, SEQRUN tst temp1 breq gl_ret lds temp1, SEQDELTA tst temp1 breq gl_ret lds temp1, TGTL lds temp2, TGTM lds temp3, TGTH sub temp1, change1 sbc temp2, change2 sbc temp3, change3 brcs gl_neg mov XL, temp1 or XL, temp2 or XL, temp3 breq gl_ret ; schon am Ziel rcall gl_scale add change1, temp1 adc change2, temp2 adc change3, temp3 ret gl_neg: com temp1 com temp2 com temp3 subi temp1, -1 sbci temp2, -1 sbci temp3, -1 rcall gl_scale sub change1, temp1 sbc change2, temp2 sbc change3, temp3 gl_ret: ret gl_scale: ldi XL, GLIDESH gl_sh: lsr temp3 ror temp2 ror temp1 dec XL brne gl_sh subi temp1, -1 sbci temp2, -1 sbci temp3, -1 ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Anzeige ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Zeile 1: acht Schritte zu zwei Zeichen, Notenname und Oktave. ; Zeile 2: S W
seqdisplay: locate(1,1) clr temp3 ; temp3 = Schritt sd_step: ldi XL, low(SEQPAT) ldi XH, high(SEQPAT) add XL, temp3 adc XH, null ld temp1, X push temp3 rcall printnote ; zwei Zeichen pop temp3 inc temp3 cpi temp3, SEQLEN brlo sd_step ; fallthrough seqstatus: ; nur Zeile 2 locate(2,1) lds temp2, SEQRUN ; Laufbalken - angehalten steht dort ldi temp1, '-' ; ein Strich, sonst sieht ein Halt tst temp2 ; genauso aus wie eine Pause breq ss_run lds temp1, SEQSTEP ldi temp2, '1' add temp1, temp2 ss_run: rcall lcd_data ldi temp1, ' ' rcall lcd_data ldi temp1, 'S' rcall lcd_data lds temp1, SEQSEL ldi temp2, '1' add temp1, temp2 rcall lcd_data ldi temp1, ' ' rcall lcd_data rcall selnote ; Note des gewaehlten Schritts rcall printnote ldi temp1, ' ' rcall lcd_data ldi XL, low(SEQACCENT) ; Akzent rcall selflag ldi temp1, '-' tst temp2 breq ss_acc ldi temp1, 'A' ss_acc: rcall lcd_data ldi XL, low(SEQSLIDE) ; Bindung rcall selflag ldi temp1, '-' tst temp2 breq ss_sld ldi temp1, 'G' ss_sld: rcall lcd_data ldi temp1, ' ' rcall lcd_data ldi temp1, 'W' ; Wellenform rcall lcd_data ldi XL, low(SEQWAVE) rcall selflag mov temp1, temp2 ; Seite 2..9 -> '1'..'8' ldi temp2, '1'-2 add temp1, temp2 rcall lcd_data ldi temp1, ' ' rcall lcd_data lds temp1, EDITMODE ; Editierziel ldi temp2, 'P' cpi temp1, 1 brne ss_m1 ldi temp2, 'A' ss_m1: cpi temp1, 2 brne ss_m2 ldi temp2, 'G' ss_m2: cpi temp1, 3 brne ss_m3 ldi temp2, 'W' ss_m3: mov temp1, temp2 rcall lcd_data ldi temp1, ' ' ; auf feste Breite auffuellen rjmp lcd_data ; temp1 = Notenindex (0 = Pause). Gibt zwei Zeichen aus: Name und Oktave. ; Grossbuchstabe = Stammton, Kleinbuchstabe = erhoeht. printnote: tst temp1 brne pn_note ldi temp1, '-' rcall lcd_data ldi temp1, '-' rjmp lcd_data pn_note: dec temp1 ; Halbtoene ueber A2, 0..36 push temp1 mov temp3, temp1 ; Halbton innerhalb der Oktave pn_mod: cpi temp3, 12 brlo pn_letter subi temp3, 12 rjmp pn_mod pn_letter: ldi temp2, lettertable add temp3, temp2 out EEARL, temp3 sbi EECR, 0 in temp1, EEDR rcall lcd_data pop temp1 ; Oktave = 2 + (Halbton+9)/12 ldi temp2, 9 add temp1, temp2 ldi temp2, '2' pn_oct: cpi temp1, 12 brlo pn_show subi temp1, 12 inc temp2 rjmp pn_oct pn_show: mov temp1, temp2 rjmp lcd_data selnote: ; temp1 = Note des gewaehlten Schritts ldi XL, low(SEQPAT) rcall selflag mov temp1, temp2 ret selflag: ; XL = Feldbasis -> temp2 = Wert ldi XH, high(SEQPAT) lds temp2, SEQSEL add XL, temp2 adc XH, null ld temp2, X ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Tastenabfrage ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Auswahl und Bearbeitung greifen nie in den klingenden Ton ein: sie aendern ; Muster und Anzeige, hoerbar wird es, wenn der Schritt das naechste Mal an der ; Reihe ist. ; Flankengesteuert und von Timer0 abgetastet: eine Taste loest genau einmal ; je Druck aus, unabhaengig davon wie lange sie gehalten wird. Das ersetzt die ; Warteschleifen der Vorgaengerversion, die zum Entprellen die Hauptschleife um ; zig Millisekunden angehalten haben - und dabei die Huellkurve stehenliessen. ; Das Abtastintervall von KEYTICK dient zugleich als Entprellzeit. seqkeys: lds temp1, KEYACC lds temp2, SEQDELTA add temp1, temp2 cpi temp1, KEYTICK brlo sk_hold subi temp1, KEYTICK sts KEYACC, temp1 rjmp sk_scan sk_hold: sts KEYACC, temp1 ret sk_scan: in temp3, PINC andi temp3, 0b00111111 lds temp2, KEYLAST ; vorher: 1 = losgelassen sts KEYLAST, temp3 mov temp1, temp3 com temp1 ; jetzt: 1 = gedrueckt and temp1, temp2 ; beides -> neu gedrueckt sbrc temp1, KEY_DOWN rjmp sk_prev sbrc temp1, KEY_UP rjmp sk_next sbrc temp1, KEY_DOWNF rjmp sk_less sbrc temp1, KEY_UPF rjmp sk_more sbrc temp1, KEY_MODE rjmp sk_mode sbrc temp1, KEY_RUN rjmp sk_run ret sk_prev: ; - : Schritt zurueck lds temp1, SEQSEL tst temp1 brne sk_p1 ldi temp1, SEQLEN sk_p1: dec temp1 sts SEQSEL, temp1 rjmp seqstatus sk_next: ; + : Schritt vor lds temp1, SEQSEL inc temp1 cpi temp1, SEQLEN brlo sk_n1 clr temp1 sk_n1: sts SEQSEL, temp1 rjmp seqstatus sk_less: ; -- : verringern / aus clr temp2 rjmp seqedit sk_more: ; ++ : erhoehen / ein ldi temp2, 1 rjmp seqedit sk_mode: ; Editierziel weiterschalten lds temp1, EDITMODE inc temp1 cpi temp1, 4 brlo sk_m1 clr temp1 sk_m1: sts EDITMODE, temp1 rjmp seqstatus sk_run: ; Start / Stop lds temp1, SEQRUN ldi temp2, 1 eor temp1, temp2 sts SEQRUN, temp1 rjmp seqstatus seqedit: ; temp2: 0 = ab/aus, 1 = auf/ein mov temp3, temp2 ; Richtung merken - selflag liefert lds temp1, EDITMODE ; seinen Wert ebenfalls in temp2 cpi temp1, 1 breq se_acc cpi temp1, 2 breq se_sld cpi temp1, 3 breq se_wav ldi XL, low(SEQPAT) ; Tonhoehe rcall selflag mov temp1, temp2 tst temp3 brne se_nup tst temp1 breq se_nst dec temp1 rjmp se_nst se_nup: cpi temp1, NOTEMAX brsh se_nst inc temp1 se_nst: st X, temp1 rjmp seqdisplay ; Zeile 1 aendert sich mit se_wav: ldi XL, low(SEQWAVE) ; Wellenform des Schritts rcall selflag mov temp1, temp2 tst temp3 brne se_wup cpi temp1, 3 ; unterste Tabellenseite ist 2 brlo se_wst dec temp1 rjmp se_wst se_wup: cpi temp1, 9 ; oberste ist 9 brsh se_wst inc temp1 se_wst: st X, temp1 rjmp seqstatus se_acc: ldi XL, low(SEQACCENT) rjmp se_flag se_sld: ldi XL, low(SEQSLIDE) se_flag: rcall selflag ; X zeigt auf das Feld st X, temp3 ; 0 oder 1 rjmp seqstatus ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; LCD-Ansteuerung und Warteschleifen ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Woertlich aus da-test.asm uebernommen - dieselben Zeitschleifen, ; die 2003 am echten Display funktioniert haben. lcd_data: mov temp2, temp1 ; "Sicherungskopie" für ; die Übertragung des 2.Nibbles swap temp1 ; Vertauschen andi temp1, 0b00001111 ; oberes Nibble auf Null setzen sbr temp1, 1<<4 ; entspricht 0b00010000 out PORTB, temp1 ; ausgeben rcall lcd_enable ; Enable-Routine aufrufen ; 2. Nibble, kein swap da es schon ; an der richtigen stelle ist andi temp2, 0b00001111 ; obere Hälfte auf Null setzen sbr temp2, 1<<4 ; entspricht 0b00010000 out PORTB, temp2 ; ausgeben rcall lcd_enable ; Enable-Routine aufrufen rcall delay50us ; Delay-Routine aufrufen ret ; zurück zum Hauptprogramm ; sendet einen Befehl an das LCD lcd_command: ; wie lcd_data, nur ohne RS zu setzen mov temp2, temp1 swap temp1 andi temp1, 0b00001111 out PORTB, temp1 rcall lcd_enable andi temp2, 0b00001111 out PORTB, temp2 rcall lcd_enable rcall delay50us ret ; erzeugt den Enable-Puls lcd_enable: sbi PORTB, 5 ; Enable high nop ; 4 Taktzyklen warten nop nop nop cbi PORTB, 5 ; Enable wieder low ret ; Pause nach jeder Übertragung delay50us: ; ungefähr (SEHR ungefähr) 50us Pause ldi temp1, $62 delay50us_: dec temp1 brne delay50us_ ret ; Längere Pause für manche Befehle delay5ms: ; ~5ms Pause ldi temp1, $31 WGLOOP0:ldi temp2, $C9 WGLOOP1:dec temp2 brne WGLOOP1 dec temp1 brne WGLOOP0 ret ; wieder zurück ; Initialisierung des LCDs lcd_init: ldi temp3,50 powerupwait: waitms 5 dec temp3 brne powerupwait ldi temp1, 0b00000011 ; muss 3mal hintereinander gesendet out PORTB, temp1 ; werden zur Initialisierung rcall lcd_enable ; 1 waitms 5 rcall lcd_enable ; 2 waitms 5 rcall lcd_enable ; und 3 waitms 5 ldi temp1, 0b00000010 ; 4bit-Modus einstellen out PORTB, temp1 rcall lcd_enable waitms 5 ldi temp1, 0b00101000 ; noch was einstellen (Cursor, Shift, usw.)... rcall lcd_command ldi temp1, 0b00001100 ; ... rcall lcd_command ldi temp1, 0b00000100 ; fertig rcall lcd_command ret ; Display löschen lcd_clear: ldi temp1, 0b00000001 rcall lcd_command waitms 5 ret ; Cursor zum Anfang lcd_home: ldi temp1, 0b00000010 rcall lcd_command waitms 5 ret ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; sonstige Funktionen ;; ;; =================== ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; Frequenz auf 0 setzen set0: clr change1 clr change2 clr change3 ret ; x ms warten wms: push temp2 out TCNT0, null wms_1: in temp2, TCNT0 cp temp2, temp1 brlo wms_1 pop temp2 ret ; x*10 ms warten w10ms: push temp2 ldi temp2, 10 w10ms_1:dec temp2 rcall wms cpi temp2,0 brne w10ms_1 pop temp2 ret