.nolist .include "m8def.inc" .list .def Temp = r16 .def Counter_R = r17 ; diese Register nicht anders verwenden .def Counter_G = r18 .def Counter_B = r19 .equ XTAL = 16000000 ; 16Mhz MCU Takt .equ REG_SDI_B = PC0 ; Datenleitungen Register SDI .equ REG_SDI_G = PC1 ; nicht anders verschieben, muß immer .equ REG_SDI_R = PC2 ; mit PIN 0 eines Ports beginnen .equ REG_CLK = PC3 ; oder man muß die Timer ISR ändern .equ REG_LE = PC4 .equ REG_PORT = PORTC .equ LED_COUNT = 16 ; Anzahl an LEDs == PIXEL .equ LED_GRAYSCALE = 256 ; Anzahl der Helligkeiten, hier also 24 Bit Farbtiefe .equ LED_INCREMENT = LED_GRAYSCALE / LED_COUNT .equ PIXELS = RAMEND - LED_COUNT * 3 ; Makros .macro outi ldi Temp, @1 out @0, Temp .endmacro ; Code .cseg .org 0 rjmp Reset .org OC2addr rjmp TimerOC2 TimerOC2: ; benötigt 25 + 16 * 20 = 345 Takte ; wird alle 1248 Takte aufgerufen, ergo 28% der Rechenzeit bei 16Mhz wird verbraucht ; man könnte einige PUSH,POP sparen, bingt aber nur ein par Takte und blockiert unnötig Register push Temp in Temp, SREG push Temp push r20 push r21 push XH push XL ldi XL, Low(PIXELS) ldi XH, High(PIXELS) ldi Temp, LED_COUNT TimerOC21: clr r20 ld r21, X+ ; lade Pixel.Red cp r21, Counter_R ; vergleiche mit Counter_R adc r20, r20 ; shift Data und setze Bit abhängig vom Vergleich ld r21, X+ cp r21, Counter_G adc r20, r20 ld r21, X+ cp r21, Counter_B adc r20, r20 out REG_PORT, r20 ; gebe 3 Bit RGB nach REG_SDI_x, 1 Bit REG_CLOCK und 1 Bit REG_LE aus subi Counter_R, LED_INCREMENT subi Counter_G, LED_INCREMENT subi Counter_B, LED_INCREMENT sbi REG_PORT, REG_CLK ; minimal 20ns nach out REG_PORT !! dec Temp brne TimerOC21 cbi REG_PORT, REG_CLK sbi REG_PORT, REG_LE ; 4 Takte = 500ns Pulse LE-/OE auf High dec Counter_R ; die Daten im Latch der Register werden an die dec Counter_G ; Ausgänge gelegt dec Counter_B cbi REG_PORT, REG_LE pop XL pop XH pop r21 pop r20 pop Temp out SREG, Temp pop Temp reti ; Initialization Reset: ; Stack initialisieren, unterhalb unserer PIXEL Daten outi SPL, Low(PIXELS -1) outi SPH, High(PIXELS -1) ; Shiftregister Port initialisieren outi REG_PORT, (1 << REG_LE) | (1 << REG_CLK) | (1 << REG_SDI_R) | (1 << REG_SDI_G) | (1 << REG_SDI_B) outi DDRC, $FF ; Sleep aktivieren im Idle Modus outi MCUCR, (1 << SE) ; Analog Comparator deaktivieren, ergo interne Bandgap wird deaktiviert, ergo weniger Stromverbrauch outi ACSR, (1 << ACD) ; Timer 2 mit 16MHz/8 = 2Mhz takten, Output Compare im CTC Mode auf 2MHz / 156 = 12820Hz macht 12820 / 256 = 50Hz outi TCCR2, (1 << CS21) | (1 << WGM21) outi OCR2, 156 outi TIMSK, (1 << OCIE2) ; Counter initialisieren ldi Counter_R, 0 ldi Counter_G, 1 ldi Counter_B, 2 ; Pixel initalisieren ldi YL, Low(PIXELS) ldi YH, High(PIXELS) ldi Temp, LED_COUNT * 3 clr r20 Reset1: subi r20, Low(-5) st Y+, r20 dec Temp brne Reset1 ; los gehts sei Main: sleep tst Counter_R brne Main ; alle 256 Durchläufe verändern wir alle Pixel ldi YL, Low(PIXELS) ldi YH, High(PIXELS) ldi Temp, LED_COUNT * 3 ldd r0, Y + LED_COUNT * 3 -1 Main1: ld r1, Y st Y+, r0 mov r0, r1 dec Temp brne Main1 rjmp Main