; 01Tiny13_10LEDs.asm ; ; flexible Musterdarstellung mit 10 LEDs via softwaregesteuerter Pulsweitenmodulation ; ; Platine01 ATTINY13 ; ; H. Stephan 05/2008 ; ; --------- ; Datenstruktur (EEPROM, wird ins RAM kopiert) ; Grob: ; ; ; ; ; Fein ; 10 x , ; , ; , ; ; ; --------- .include "tn13def.inc" ; Variablen .EQU LED_count = 10 ; Anzahl LEDs für dieses Programm .EQU PWM_length = 32 ; Länge eines kompletten PWM-Zyklus, das Intervall ist ; Taktfrequenz/IRQ/Anzahl LEDs/PWM_Zyklus ; z.B. bei 9,6 MHz, 10 LEDs: 9600000/256/10/64 = 59 Hz pro komplettem PWM-Zyklus ; d.h. die LEDs "blinken" mit 49 Hz, also nicht sichtbar .EQU pattern_max = 20 ; Geschwindigkeit der Muster-Änderung in LED-Zyklen .DEF effect_speed = r7 ; Geschwindigkeit des Ausblend-Effekts (pattern_speed / 2) .DEF pattern_speed = r8 ; Geschwindigkeit der Musteränderung, wird durch den Taster gesteuert .DEF switch = r9 ; Taster (0=aus, 1=Startsignal) .DEF patternMSBbit = r10 ; Bitnr. innerhalb des Muster-MSB .DEF patternMSB = r11 ; aktuelles Muster, die oberen beiden Bits .DEF patternLSB = r12 ; aktuelles Muster, die unteren 8 Bits .DEF seqnr = r13 ; Nr. der Sequenz (noch nicht benutzt) .DEF patterncount = r14 ; innere Zählschleife für das Muster .DEF seqlength = r15 ; Länge der Sequenz .DEF temp = r16 ; temporärer Speicher .DEF counter = r17 ; Zähler für Schleifen .DEF PWMcount = r18 ; fortlaufender Zähler für PWM .DEF LEDnumber = r19 ; Nr. der aktuellen LED .DEF LEDvalue = r20 ; Helligkeitswert Led1: 0 .. 63 .DEF changer = r21 ; Zähler für Effekt .DEF effect = r22 ; Effekt-Richtung, Helligkeit bei 1 nach oben, bei 0 unten setzen .DEF patternnr = r23 ; Nr. des aktuellen Musters (MSB:1 = abwärts zählen MSB:0 = aufwärts zählen) .DEF patterncount2 = r24 ; äußerer Zähler für Musteränderung .DEF temp2 = r25 rjmp main ; Reset Handler .ORG 0x0003 rjmp timer0_overflow ; Timer Overflow Handler main: cli ldi temp, 1 ; CS00 setzen: Teiler 1 out TCCR0B, temp ldi temp, 2 ; TOIE0: Interrupt bei Timer Overflow out TIMSK0, temp rcall EEPROM_copy ldi XL, 0x60 ; Zeiger auf RAM-Anfang ldi XH, 0x00 ldi changer, 0 clr patterncount ; äußere Zählschleife für Muster löschen clr patterncount2 ; innere Zählschleife für Muster löschen clr patternnr ; erstes Muster laden rcall load_pattern inc patternnr ldi ZL, 0x60+low (seq1) ; Zeiger auf Sequenzlänge ldi ZH, 0x00 ld seqlength, Z ldi temp, pattern_max mov pattern_speed, temp mov effect_speed, temp lsl effect_speed lsl effect_speed clr switch ldi temp, 0b00000100 out PORTB, temp ; pull-up einschalten out ddrb, switch wait: nop in temp, pinb andi temp, 4 brne wait inc switch ; Flag für Taster sei ; Interrrupts erlauben loop: rjmp loop timer0_overflow: ; Timer 0 Overflow Handler tst switch ; Taste nicht gedrückt brne cont rjmp end cont: ldi XL, 0x60 ; Zeiger auf LED-Portwerte für Charlieplexing ldi XH, 0x00 ldi YL, 0x60+low (LEDval) ; Zeiger auf Helligkeitswerte ldi YH, 0x00 inc LEDnumber cpi LEDnumber, LED_count brlo WorkPWM clr LEDnumber inc PWMcount ; den PWM Zähler von 0 bis cpi PWMcount, PWM_length ; 64 zählen lassen brlo WorkEffect clr PWMcount ; Effekt WorkEffect: inc changer cp changer, effect_speed ; Effekt-Zeitsteuerung brlo WorkPattern ; wenn kein Effekt, mit PWM-Steuerung weitermachen clr changer effect_loop: ld LEDvalue, Y ; kombinierten Helligkeitswert Effektbit (MSB) laden mov effect, LEDvalue ; Effektrichtung laden (0 runter, 1 hoch) cbr LEDvalue, 0x80 ; nur Bit 0-6 benutzen cbr effect, 0x7F ; MSB isolieren sbrs effect, 7 ; wenn Bit 7 gesetzt, skip rjmp rjmp down inc LEDvalue cpi LEDvalue, PWM_length ; wenn Helligkeit < PWM-Intervall brlo save ; speichern cbr effect, 0x80 ; ... Bit 7 löschen, Effektrichtung umkehren, wieder nach unten zählen dec LEDvalue ; max. Helligkeit rjmp save down: tst LEDvalue ; Hellikeitswert 0 = LED aus breq save dec LEDvalue ; sbr effect, 0x80 ; Effektrichtung umkehren, wieder nach oben zählen save: ; Werte im RAM speichern or LEDvalue, effect ; Effektbit und Helligkeit wieder verbinden st Y+, LEDvalue inc LEDnumber cpi LEDnumber, LED_count brlo effect_loop ldi YL, 0x60+low (LEDval) ; Zeiger auf Helligkeitswerte wieder zurücksetzen ldi YH, 0x00 clr LEDnumber WorkPattern: ; Muster-Schleife inc patterncount2 ; Muster-Zählschleife cpi patterncount2, 64 brlo WorkPWM clr patterncount2 rcall switch_handler ; Taster abfragen inc patterncount cp patterncount, pattern_speed brlo WorkPWM clr patterncount rcall load_pattern ; aktuelles Muster laden sbrc patternnr, 7 ; rjmp pattern_down ; Muster läuft gerade vorwärts inc patternnr cp patternnr, seqlength brlo WorkPWM ; maximaler Wert erreicht, jetzt rückwärts zählen ; sbr patternnr, 0x80 ; Bit 7 setzen = abwärts zählen ; dec patternnr clr patternnr rjmp WorkPWM pattern_down: cpi patternnr, 0x80 ; Muster Nr. 0 wieder erreicht brne pattern_down_set ; nein ; cbr patternnr, 0x80 ; ja, MSB löschen = wieder aufwärts zählen add patternnr, seqlength dec patternnr rjmp WorkPWM pattern_down_set: dec patternnr WorkPWM: ; PWM-Schleife ldi LEDvalue, 0 ; alle LEDs ausschalten out ddrb, LEDvalue out portb, LEDvalue ldi XL, 0x60 ; Zeiger für LED-Portsteuerung auf RAM-Anfang ldi YL, 0x60+low(LEDval) ; Zeiger für LED-Helligkeit mov temp, LEDnumber ; LED-Nr. laden add YL, temp lsl temp ; mit 2 multiplizieren add XL, temp ; zu Speicherzeiger addieren ld LEDvalue, Y ; kombinierten Helligkeitswert Effektbit (MSB) laden cbr LEDvalue, 0x80 ; nur Bit 0-6 benutzen tst LEDvalue ; wenn Helligkeitswert = 0, nicht einschalten breq end cp LEDvalue, PWMcount ; PWM-Zähler testen brlo end ; wenn Helligkeitswert >= PWMcount , dann LED nicht einschalten ld LEDvalue, X+ ; Port-Datenrichtungsbit laden out ddrb, LEDvalue ld LEDvalue, X ; Portstatus laden ... out portb, LEDvalue ; ... und setzen end: reti load_pattern: ; Muster laden clr counter ; mit Bit 0 anfangen ldi XL, 0x60+low(LEDval) ; Zeiger auf Helligkeitswerte ldi YL, 0x60+low(seq1) + 4 ; Y-Speicherzeiger auf die LSBs des ersten Musters setzen (3*MSB überspringen) ldi YH, 0 ldi ZL, 0x60+low(seq1) + 1 ; Z-Speicherzeiger auf die MSBs des ersten Musters setzen ldi ZH, 0 mov temp2, patternnr ; Nr. des Musters mit Richtungsbit laden cbr temp2, 0x80 ; Richtungsbit ausblenden add YL, temp2 ; Nr. des aktuellen Musters zu LSB-Zeiger addieren ld patternLSB, Y ; jetzt stehen die 8 LSBs des aktuelle Musters in patternLSB clr temp ; --- Modulo 4 von patternnr in patternMSBbit nachbilden sbrc temp2, 0 ; Bit 0 prüfen, wenn nicht gesetzt, nächstes Statement überspringen sbr temp, 1 sbrc temp2, 1 ; Bit 1 prüfen, wenn nicht gesetzt, nächstes Statement überspringen sbr temp, 2 mov patternMSBbit, temp ; patternMSBbit enthält jetzt patternMSB modulo 4 lsr temp2 ; Nr. des Musters / 4 (da das MSB 4 Werte à 2 Bit aufnehmen kann) lsr temp2 add ZL, temp2 ; zu MSB-Speicherzeiger addieren ld patternMSB, Z ; und MSB-Byte laden move_MSB: ; MSB-Bits auf Position 0 und 1 verschieben tst patternMSBbit breq Patternbits lsr patternMSB lsr patternMSB dec patternMSBbit rjmp move_MSB PatternBits: ld LEDvalue, X ; alten Helligkeitswert laden ldi temp2, 0x80 | 16 ; vorbelegen mit Helligkeit + Abwärts-Zählflag lsr patternLSB brcs SetPattern ; Bit in Muster gesetzt? Wenn ja, LED mit max. Helligkeit einschalten tst LEDvalue brne LED_not_zero ; wenn LED noch nicht aus wg. Effekt, nicht ändern ldi temp2, 0 SetPattern: st X, temp2 ; ja: maximale Helligkeit, nein: Helligkeit auf 0 LED_not_zero: inc XL inc counter cpi counter, 8 ; erstes Byte ist durch brne first_byte mov patternLSB, patternMSB ; MSB laden first_byte: cpi counter, LED_count brlo PatternBits ret EEPROM_copy: ldi LEDnumber, 0 ; mit LED 0 starten ldi XL, 0x60 ; Zeiger auf RAM-Anfang ldi XH, 0x00 ldi counter, 0 ; EEPROM-Lesezeiger auf EEPROM-Anfang copy2RAM: ; LED-Daten aus EEPROM ins RAM kopieren sbic EECR, EEPE ; wenn EEPROM nicht geschrieben wird ... rjmp copy2RAM ; ... dieses Kommando überspringen out EEARL, counter ; EEPROM Address Register setzen sbi EECR,EERE ; Lese-Bit in EEPROM-Control-Register setzen ee_read: sbic EECR,EERE ; Lese-Bit in EEPROM-Control-Register setzen rjmp ee_read in temp, EEDR ; Daten lesen st X+, temp ; Daten schreiben inc counter cpi counter, 60 ; insgesamt 60 Werte einlesen (LEDs + Muster) brne copy2RAM ret switch_handler: ; Interrupt für Taste (Port 2) ldi temp, 0b00000100 out PORTB, temp ; pull-up einschalten out ddrb, temp nop sbic PINB, 2 ; PINB4 gesetzt? rjmp end_switch inc switch ; entprellen ldi temp, 10 cp switch, temp brlo end_switch ldi temp, 1 mov switch, temp dec pattern_speed brne end_switch ldi temp, pattern_max mov pattern_speed, temp mov effect_speed, temp lsl effect_speed ldi temp, 0x80 eor patternnr, temp ;Richtung togglen end_switch: ret .ESEG ; Daten im EEPROM ablegen ; Helligkeit Portstatus (DDRB), Portausgabe (PORTB) LED0: .DB 0b00011000, 0b00001000 LED1: .DB 0b00011000, 0b00010000 LED2: .DB 0b00001001, 0b00000001 LED3: .DB 0b00001001, 0b00001000 LED4: .DB 0b00001010, 0b00000010 LED5: .DB 0b00001010, 0b00001000 LED6: .DB 0b00010010, 0b00000010 LED7: .DB 0b00010010, 0b00010000 LED8: .DB 0b00010001, 0b00000001 LED9: .DB 0b00010001, 0b00010000 ; Helligkeitswerte pro LED LEDval: .DB 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ; Sequenz ; , , ; seq2: .DB 3, 0b00001111, 0b00000000, 0b00000000 .DB 0b11111111, 0b11111111, 0b00000000 seq3: .DB 4, 0b11011000, 0b00000000, 0b00000000 .DB 0b00000000, 0b01010101, 0b10101010, 0b11111111 seq1: .DB 10, 0b00000010, 0b00001001, 0b00000100 .DB 0b00000001, 0b10000100, 0b00110000, 0b01001000, 0b00000010, \ 0b00000001, 0b10000100, 0b00110000, 0b01001000, 0b00000010