; *** LED Helligkeitssteuerung mit PWM 1.0 (c) Oliver Mezger 22.6.2014
.include "tn2313def.inc"

;* mit STK 200 (LED neg. Logik) und ATtiny2313 @ 1MHz

.dseg  ;Datenbereich
helligkeit: .byte 7 ;Platz fuer Helligkeitsfeld {7,15,14,0,1,2,3}
.cseg  ;Programmbereich

.equ clk = 1    ;CPU-Takt in MHz 
.equ TIMERVORSPANN = 256-83 ;Wert mit dem der Zaehler startet

.def tmp  = R16     ;Hilfsregister
.def itmp = R17     ;Hilfsregister fuer Interrupt
.def ii   = R18     ;Register fuer Interrupt
.def iaus = R19     ;Register fuer Interrupt
.def ilevel = R20   ;Register fuer Interrupt
.def innen = R21    ;Hilfsregister fuer Warteschleife
.def aussen = R22   ;Hilfsregister fuer Warteschleife 
.def up = R23

.def keyold = R2    ;Taster die gedrueckt waren
.def keynew = R25   ;Taster die gedrueckt sind R>=16
.def keyenter = R3  ;Taster, die neu gedrueckt wurden
.def keyexit = R4   ;Taster, die neu losgelassen wurden

  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 tmp,$ff
  out PORTB,tmp     ;alle LED aus
  out DDRB,tmp      ;PB als Ausgang
  ldi tmp,2         ;Vorteiler auf Phi/8 setzen
  out TCCR0B,tmp    ;alle 8us ein Zaehl-Impuls
  ldi tmp,1<<TOIE0  ;Timer Overflow Interrupt Enable 0 setzen 
  out TIMSK,tmp     ;Timer kann nun Interrupt ausloesen
 ;* Helligkeitsfeld mit Startwerten initialisieren
  ldi XH,HIGH(helligkeit) ;Datenzeiger High
  ldi XL,LOW(helligkeit)  ;Datenzeiger Low
  ldi tmp,7  ;
  st x+,tmp  ;
  ldi tmp,15
  st x+,tmp
  ldi tmp,14
  st x+,tmp
  ldi tmp,0
  st x+,tmp
  ldi tmp,1
  st x+,tmp
  ldi tmp,2
  st x+,tmp
  ldi tmp,3
  st x+,tmp
  sei               ;globale Interrupt Freigabe
loop:
  ldi YH,HIGH(helligkeit) ;Datenzeiger High
  ldi YL,LOW(helligkeit)  ;Datenzeiger Low
  ldd tmp,Y+6 ;lade helligkeit[6]
  cpi up,1
  brne coutdown
  inc tmp
  cpi tmp,14
  brne moon
  clr up
  rjmp moon
coutdown:
  dec tmp
  brne moon
  ldi up,1
moon:
  std Y+6,tmp
  ldi tmp,50
nana:
  rcall warte10ms
  dec tmp
  brne nana
  rjmp loop           ;Endlos-Schleife

isrOVF0:         // Aufruf alle 654us Dauer 92us
  ldi itmp,TIMERVORSPANN    ;Wert zum Vorspannen des Timers laden
  out TCNT0,itmp ;in den Timer schreiben
  sbi PINB,7     ;PB7 invertieren zwechs Zeitmessung
  in itmp,SREG   ;Statusregister sichern
  push itmp
  clr iaus
  ldi ii,1
  ldi XH,HIGH(helligkeit) ;Datenzeiger High
  ldi XL,LOW(helligkeit)  ;Datenzeiger Low
ifor:
  cpi ii,0b10000000
  breq iendfor
  ld itmp,x+  ;lade Feldelement
  cp ilevel,itmp
  brlo iendif
  or iaus,ii
iendif:
  lsl ii
  rjmp ifor
iendfor:
  in itmp,PORTB   ;ausgeben
  andi itmp,0b10000000
  or itmp,iaus
  out PORTB,itmp
  inc ilevel
  cpi ilevel,14
  brlo iend
  clr ilevel
iend:
  pop itmp
  out SREG,itmp  ;Statusregister wieder herstellen
  sbi PINB,7     ;PB7 invertieren zwechs Zeitmessung
  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 

keycheck:                ;Unterprogramm zur Tastaturabfrage
  clr keyenter
  clr keyexit
  in keynew,PIND         ;Lade PD
  com keynew             ;invertieren
  andi keynew,0b00111111 ;Maskieren der nicht verwendeten Pins
  cpse keyold,keynew     ;Test ob Veraenderung
  rjmp keyaction         ;Veraenderung
  ret                    ;alles gleich
keyaction:
  rcall warte10ms       ;etwas warten
  in tmp,PIND           ;nochmal einlesen
  com tmp               ;invertieren bei neg. Logik
  andi tmp,0b00111111   ;maskieren der nicht verwendeten Pins
  cpse keynew,tmp       ;ist es stabil
  ret                   ;war nix, da nicht stabil
  mov keyenter,keyold
  com keyenter          ;invertieren
  and keyenter,keynew   ;steigende Flanken, !alt & neu
  mov keyexit,keynew
  com keyexit           ;invertieren
  and keyexit,keyold    ;fallende Flanken, alt & !neu
  mov keyold,keynew     ;alt := neu
  ret
