; Programm liest periodisch ein Datenfeld aus und generiert daraus ein PWM-Signal ; Wird das Datenfeldende erreicht, wird zurück zur Anfangsadresse gesprungen. ; Testprogramm: LED (mit R gegen VCC) an Pb1, d.h. lo-aktiv ; ; PB0: Taster (Ein/Aus) ; PB1: PWM-Ausgang für LED ; PB2: Soundmodul E1 ; PB3: Soundmodul E2 ; (PB5: Reset-Taster) ; .INCLUDE "tn13def.inc" ;Include-Datei für Pseudonyme einbinden .def temp = r16 ;temporäres Register deklarieren .def pwm_periode = r17 ;Anzahl der PWM-Perioden pro Intensitäts-Wert .def ocr_wert = R18 ;Vergleichswert zur erzeugung des PWM-Signals .def betrieb = r19 ;Anzeige des Betriebszustands ;Bit0=0 -> aus, Bit0=1 -> an ;Bit1 = einflankige Tasterauswertung .org 0x0000 rjmp main ;Einsprungadresse für einen Reset definieren .org 0x0001 ;INT0addr reti .org 0x0002 ;PCINT0addr rjmp isr_taster ; Einsprungadresse für Interrupt .org OVF0addr rjmp TIMER0_OVERFLOW ;ISR-Adresse für Timer-Überlauf definieren main: ldi temp, LOW(RAMEND) ;mit Stackpointer-low (0x3d) auf out SPL, temp ;niedriges Byte der Adresse 0x009f zeigen ldi temp, 0b00111110 ;PB0 als Eingang, Rest Ausgang out DDRB, temp ;gesamten PortB als Ausgang setzen ldi pwm_periode, 0 ;Zählregister für Anzahl der PWM-Perioden ;initialisieren. ldi betrieb,0b00000000 ;Betriebszustand ldi temp, 0b00000010 ; out TIMSK0, temp ;TOIE0: Interrupt bei Timer-Overflow konfigurieren ldi temp, 0b00100000 ;Pin Change Interrupt enabled out GIMSK, temp ldi temp, 0b00000001 ;PCINT0 maskieren out PCMSK, temp sbi PortB, 1 ; PB1 auf hi setzen (T1 sperrt Klinge) sei ;Interrupts freigeben (setzt Bit7 im SREG) loop: ;Endlosschleife, wenn keine Interrupt Service rjmp loop ;Routine ausgeführt wird. Warten auf Ein-/Aus-Taster. start_pwm: ldi temp, 0b00000001 ;FOC0A FOC0B --- --- WGM02 CS02 CS01 CS00 out TCCR0B, temp ; 0 0 0 0 0 0 0 1 ; CS00=1--> Timer startet rcall Z_INIT ;Z-Pointer initialieren rcall LOAD_DATA ;Datenfeld auslesen ldi temp, 0b11110011 ;COM0A1 COM0A0 COM0B1 COM0B0 --- --- WGM01 WGM00 out TCCR0A, temp ; 1 1 1 1 0 0 1 1 ret stop_pwm: ldi temp, 0b00000000 ;FOC0A FOC0B --- --- WGM02 CS02 CS01 CS00 out TCCR0B, temp ; 0 0 0 0 0 0 0 0 ; CS00=0--> Timer stoppt sbi PinB, 1 ; PB1 auf hi setzen (T1 sperrt LED) nop nop nop nop nop nop nop nop ret TIMER0_OVERFLOW: inc pwm_periode ;inkrementiere pwm_periode cpi pwm_periode, 156 ;wenn pwm_periode gleich dem angegebenen Wert breq OCR0B_UPDATE ;führe OCR0B_update aus (neuer Vergleichswert) reti ;gehe zurück zur Stelle des Aufrufs OCR0B_UPDATE: rcall LOAD_DATA ;Datenfeld auslesen andi pwm_periode,0 ;Zähl-Register für ausgeführte Perioden ;wieder auf Null setzen. reti ;gehe zurück zur Stelle des Aufrufs LOAD_DATA: CPI ZL,0x3D ;überprüfe, ob Ende des Datenfeldes erreicht. brsh Z_RESET ;Wenn ja, setze Z_Pointer auf Anfangsadresse LOAD_Z: lpm ocr_wert, Z+ ;hole Datum von aktueller Speicheradresse out OCR0B, ocr_wert ;neuen Compare-Wert setzen ret ;gehe zurück zur Stelle des Aufrufs Z_RESET: rcall Z_INIT ;Hilsroutine um Z_INIT aus LOAD_DATA rjmp LOAD_Z ;aufrufen zu können. ( ;-) fehlendes Knowhow? ) Z_INIT: ldi ZH, high(INTENSITY<<1) ;oberes Z-Pointer Register auf obere Start-Adresse ldi ZL, low(INTENSITY<<1) ;unteres Z-Pointer Register auf untere Start-Adresse ret ;gehe zurück zur Stelle des Aufrufs ;ISR------------------------------------------------------------------------------ isr_taster: sbic pinb, 0 ;Abfrage, ob PB0=hi rjmp betriebszustand sbis pinb, 0 ;Abfrage, ob PB0=lo rcall soundout_lo reti betriebszustand: sbrs betrieb, 0 ;überspinge, wenn Bit0 = 1 (wenn Schaltung an) rcall einschalten sbrc betrieb, 0 ;überspinge, wenn Bit0 = 0 (wenn Schaltung aus) rcall ausschalten ldi temp, 0b00000001 eor betrieb, temp ;Betriebszustand umschalten reti einschalten: sbi PortB,2 ;Ausgang PB2 auf HI setzen (Soundmodul) rcall start_pwm ret ausschalten: sbi PortB,3 ;Ausgang PB3 auf HI setzen (Soundmodul) rcall stop_pwm ret soundout_lo: cbi PortB,2 ;Ausgang PB2 auf LO setzen (Soundmodul) cbi PortB,3 ;Ausgang PB3 auf LO setzen (Soundmodul) ret ;--------------------------------------------------------------------------------- ;--------------------------------------------------------------------------------- ; Datenbereich ;--------------------------------------------------------------------------------- ;Helligkeiten zwischen 122 und 252 .org 0x0100 INTENSITY: .db 252,228,196,173,152,231,193,161,252,221 ;Startadresse 0x0100 .db 166,183,195,217,222,223,169,210,228,235 ;logarithmische Stufung .db 252,252,219,180,216,252,150,189,228,154 ;Helligkeitsstufen von 0 bis 255 .db 206,188,252,252,252,186,252,145,228,206 ;für die Flackerfunktion werden .db 206,252,228,206,252,252,188,195,148,208 ;ab der Speicheradresse 0x0100 .db 163,143,122,179,228,205,167,155,196,241 ;jeweils byteweise abgelegt. .db 205,165,252,252,252,252,176,222,185,151 ;Da die Speicher des ATtiny13 ;End-Adresse: 0x013D in 16bit-Adressen mit jeweils ;zwei Byte organisiert ist, wird ;bei ungeraden Anzahlen von ;Byte-Werten das letzte Byte einer ;16Bit-Adresse auf 0x00 gesetzt.