; *** LED-Dimmer mit 8Bit Timer0 1.0 (c) Oliver Mezger 12.01.2011
.include "tn2313def.inc"

;* LED an PB0 neg. Logik soll gedimmt werden. Timer0 mit OverFlow Interrupt
;* Interner RC-Oszillator mit 8MHz geteilt durch 8 (tiny2313 Spezialitaet)
;* Systemtakt Phi ist somit 1MHz
;* Zaehlertakt von 8Bit-Timer0 sei Phi
;* LED soll nach Initialisierung mit 10% leuchten 25us 0, 230us 1

.def tmp  = R16     ;Hilfsregister
.def itmp = R17     ;Hilfsregister fuer Interrupt
.def led = R18      ;LED Helligkeit
.def innen = R20    ;Hilfsregister fuer Warteschleife
.def aussen = R21   ;Hilfsregister fuer Warteschleife

.equ clk = 1        ;CPU-Takt in MHz

  rjmp reset        ;Sprung zur Initialisierung
  .org OVF0addr     ;naechter Befehl an der Interrupteinsprungadresse
  rjmp isrOVF0      ;Sprung zur Interruptbehandlungsroutine
  .org INT_VECTORS_SIZE ;weiter nach Interrupttabelle

reset:                ;Initialisierung nach Reset
  ldi tmp,low(RAMEND) ;oberste RAM-Adresse laden
  out SPL,tmp       ;Stackpointer initialisieren
  ldi led,25       	;LED 10% Helligkeit
  ldi tmp,$ff
  out PORTB,tmp     ;alle LED aus
  out DDRB,tmp      ;PB als Ausgang
  ldi tmp,1         ;Vorteiler auf Phi
  out TCCR0B,tmp    ;alle 1us ein Zaehl-Impuls
  ldi tmp,1<<TOIE0  ;Timer Overflow Interrupt Enable 0 setzen 
  out TIMSK,tmp     ;Timer kann nun Interrupt ausloesen
  sei               ;globale Interrupt Freigabe
loop:
  rcall warte10ms   ;warte 10ms
  inc led;          ;erhoehe Helligkeit um 1
  rjmp loop         ;Endlos-Schleife

isrOVF0:
  in itmp,SREG   ;laden von SREG
  push itmp      ;retten von SREG
  sbic PORTB,0   ;wenn LED aus
  rjmp ledan	   ;dann LED an
  out TCNT0,led  ;0 = lange aus, 255 = kurz aus
  sbi PORTB,0    ;LED ausschalten 
  rjmp isrend    ;zum Ende
ledan:
  ldi itmp,255   ;lade 255
  sub itmp,led   ;255-led ist an
  out TCNT0,itmp ;in den Timer schreiben
  cbi  PORTB,0   ;LED einschalten
isrend:
  pop itmp       ;SREG wieder herstellen
  out SREG,itmp
  reti           ;Interruptbehandlung ist zu Ende

warte10ms:          ;Unterprogramm 10ms warten
  ldi aussen,clk*10 ;anpassen an CPU-Takt
loop_aussen:
  ldi innen,250
loop_innen:
  nop
  dec innen
  brne loop_innen
  dec aussen
  brne loop_aussen
  ret
