.nolist
.include "tn13adef.inc" ; Define device ATtiny13A
.list
; Hinweise
; Verwendet den internen 128KHz-Oszillator
; 
;
; Device: ATtiny13A, Package: 8-pin-PDIP_SOIC
;
;                   _________
;                1 /         |8
;               o--|RESET  VCC|--o--\
;               o--|PB3    PB2|--o  |
; Taster--------o--|PB4    PB1|--o--^-------[5K]-- >|- LED---Gnd
; |       100n--o--|GND    PB0|--o--^-------[5K]-- >|- LED---Gnd
; |       |      4 |__________|5    |
;Gnd      |                         |
;         \-------------------------/
; **********************************
;  F I X  &  D E R I V.  C O N S T
; **********************************
.equ F_CPU=128000 ; interner 128KHz-Oszillator
.equ LED1 = PB0 ; physischer PWM-Port
.equ LED2 = PB1 ; nur die zweit-LED
.equ LEDPORT = PORTB
.equ TASTER = PINB4
.equ TASTERPORT = PINB
.equ PROGRAMMAX = 5  ; Programmanzahl plus eins
.equ COUNTERVALUE=30 ; ca. zwei Sekunden bei Watchdog
.equ MINIMUM=40   ; minimum für zufallszahl -> mindest-LED-Helligkeit
.equ FAKTOR=80    ; Zeitfaktor für die Morsegeschwindigkeit. Je höher desto langsamer.
.equ COUNTERDIT=80 ; Dauer eines Morse-Dit
.equ COUNTERDAH=3*COUNTERDIT ; üblicherweise drei mal dit
.equ STEPMAX=15 ; Bitmaske für step = fading-Geschwindigkeit
.equ COUNTERMAX=800 ; für 16-Bit-counter r24 und r25
.equ P3STEP=20
.equ SAVE_COUNTER=200  ; ca. 20 Sekunden
.equ COUNTERISZERO=0
.equ PROGRAMHASCHANGED=1
.equ SAVENEEDED=2
; **********************************
;       R E G I S T E R S
; **********************************
.def zufallszahl = r0
.def zero=r1  ; immer Null
.def rueckf1=r2
.def rueckf2=r3
.def sollwert=r4 ; Für die mindest-LED-Helligkeit
.def rueckf4=r5
.def eins=r6
.def number1 = r7 ; 32-Bit-LFSR
.def number2 = r8
.def number3 = r9
.def number4 = r10
.def eeprombyte = r11 ; ein Byte als Zwischenspeicher
.def eepromcounter=r12 ; Zähler für den Z-Pointer
.def countermaxlow=r13
.def countermaxhigh=r14

.def rSreg = r15 ; Save/Restore status port
.def rmp = r16 ; Define multipurpose register
.def rmp2 = r17
.def statusbits=r18 ; einzelne Bits: Bit 0 = ist "1", wenn Entprell-counter_=_0 (Watchdog-ISR)
                    ;                Bit 1 = ist "1", wenn Programmnummer sich geändert hat
                    ;                Bit 2 = ist "1" wenn Programmnummer neu gespeichert wird (nach Ablauf von ca. 13 Sekunden nach einem Tastendruck automatisch)
.def step = r19
.def counter=r20
.def letter=r21
.def dreibit=r22
.def programmnummer=r23 ; Nummer aktuelles Programm, derzeit 0 bis 4
.def lowbyte=r24
.def highbyte=r25
.def savecounter=r26
;
; **********************************
;           S R A M
; **********************************
;
.dseg
.org SRAM_START

.eseg
.org 0
textdaten:
.db "ein kleiner "
.db "testtext  "
.db 0
eepromadresse:
.db 1

; **********************************
;         C O D E
; **********************************
.cseg
.org 000000
; **********************************
; R E S E T  &  I N T - V E C T O R S
; **********************************
	rjmp Main ; Reset vector
	reti ; INT0
	reti ; PCI0
	rjmp isr_timeroverflow ; OVF0
	reti ; ERDY
	reti ; ACI
	rjmp isr_comparematch ; OC0A
	reti ; OC0B
	rjmp isr_watchdog ; WDT
	reti ; ADCC

; **********************************
;  I N T - S E R V I C E   R O U T .
; **********************************
isr_timeroverflow:
 push rmp
 push rmp2
 in rsReg,SREG
 add lowbyte, eins
 adc highbyte, zero
 cp lowbyte,countermaxlow
 cpc highbyte, countermaxhigh
 brne keinreset
 clr lowbyte
 clr highbyte

 keinreset:
 cpi programmnummer, 2 ; flackern
 breq continue
 rjmp isr_ende2

 continue:
 cbi PORTB, LED2
 in rmp, OCR0A
 cp zufallszahl, rmp
 breq neuezahl
 cp zufallszahl, rmp
 brlo abwaerts ; OCR0A ist größer als Zahl -> runter zur Zahl zählen
 aufwaerts:
  ; zufallszahl ist groesser als OCR0A
  ; rmp2 = zufallszahl
  mov rmp2, zufallszahl
  ;inc rmp2 ; für den Fall Differenz - step = 0
  sub rmp2, rmp ; zufallszahl - OCR0A
  cpc rmp2, step
  brlo neuezahl
  add rmp, step
  rjmp isr_ende

 abwaerts:
  ;OCR0A ist groesser als zufallszahl
  ; Differenz zufannszahl und OCR0a groesser als step?
  ; rmp2 = OCR0A, davon zufallszahl abziehen
  ; wenn Ergebnis kleiner als step: neue Zahl (carry?)
  mov rmp2, rmp
  sub rmp2, zufallszahl
  cpc rmp2, step
  brlo neuezahl
  sub rmp, step
  rjmp isr_ende

 neuezahl:
  rcall zufallszahl32
  mov step, number2
  andi step,STEPMAX
  cp step, zero
  brne isr_ende
  inc step

 isr_ende:
  out OCR0A, rmp

 isr_ende2:
  out SREG, rSreg
  pop rmp2
  pop rmp
  reti


isr_comparematch:
 push rmp
 in rSreg, SREG
 cpi programmnummer, 2 ; flackern
 breq cmp_weiter
 rjmp compareende
 cmp_weiter:
 sbi PORTB, LED2
 compareende:
 out SREG, rSreg
 pop rmp
 reti

isr_watchdog:
 in rSreg, SREG
 cp savecounter, zero
 breq isr_weiter
 dec savecounter
 cp savecounter, zero
 brne isr_weiter
 sbr statusbits,(1<<SAVENEEDED)

 isr_weiter:
 rcall countercompare
; wenn statusbits0 = 1 und Taste gedrückt, dann löse Aktion aus
; setze statusbits0 auf 0, setze counter auf seinen Startwert, programm+1
 sbis TASTERPORT,TASTER ; wenn Taster nicht gedrückt überspringe
 rcall tastegedrueckt
 out SREG, rSreg
 reti

; **********************************
;  M A I N   P R O G R A M   I N I T
; **********************************
Main:
 ldi rmp,Low(RAMEND)
 out SPL,rmp ; Init LSB stack pointer
 clr zero
 clr step
 clr eepromcounter
 ldi counter,10
 clr statusbits
 inc step ; erst mal "1"
 clr rmp2
 ldi rmp, 78
 mov number1, rmp
 ldi rmp, 107
 mov number2, rmp
 ldi rmp, 208
 mov number3, rmp
 ldi rmp, 42
 mov number4, rmp
 ldi rmp, 128
 mov rueckf1, rmp
 ldi rmp, 32
 mov rueckf2, rmp
 ldi rmp, 3
 mov rueckf4, rmp
 ldi rmp, MINIMUM
 mov sollwert, rmp
 ldi rmp, LOW(COUNTERMAX)
 mov countermaxlow, rmp
 ldi rmp, HIGH(COUNTERMAX)
 mov countermaxhigh, rmp
 sbi DDRB, 0
 sbi DDRB, LED2
 sbi LEDPORT,TASTER
 ldi rmp, 1
 mov eins, rmp
 mov step, rmp
; mov programmnummer, rmp
 rcall init_watchdog
 ldi ZL, LOW(EEPROMADRESSE)
 rcall eeprom_read
 mov programmnummer, eeprombyte
 clr eepromcounter
 clr savecounter
 sbr statusbits, (1<<PROGRAMHASCHANGED)
 sei

;
; **********************************
;    P R O G R A M   L O O P
; **********************************
;
Loop:
 sbrc statusbits, SAVENEEDED
 rcall write2eeprom
 sbrc statusbits, PROGRAMHASCHANGED     ; Bit 1 = Programmchange
 rcall case
 sbis TASTERPORT,TASTER ; wenn Taster nicht gedrückt überspringe
 rcall tastegedrueckt
 cpi programmnummer, 1
 breq morsen
 cpi programmnummer, 3
 breq programm3
 loopsleep:
 rcall initsleep
 sleep
 rjmp Loop

 morsen:
  rcall getfromeeprom
  mov letter,eeprombyte
  cpi letter, 32 ; Leerzeichen
  breq langepause
  cpi letter, 0 ; Stringende
  breq langepause
  rcall getletterfromflash

  letterausgabe:
   mov dreibit, letter
   andi letter, 31   ; 5 bit maskieren
   swap dreibit
   lsr dreibit
   andi dreibit, 7   ; erste drei bit => Anzahl an Symbolen

   morsezeichen:
   sbi PORTB,LED1
   lsr letter
   brcs sendedah

   sendedit:
    ldi rmp, COUNTERDIT
    rcall beep
    rjmp symbolende

   sendedah:
    ldi rmp, COUNTERDAH
    rcall beep

   symbolende:
    cbi PORTB,LED1
    ldi rmp, COUNTERDIT
    rcall beep
    dec dreibit
    brne morsezeichen
    rjmp pause

  langepause: ; zwischen zwei Buchstaben
   cbi PORTB,LED1
   ldi rmp, COUNTERDIT
   rcall beep
   rcall beep
   rcall beep
   rcall beep
   rcall beep

  pause:
   rcall beep
   rcall beep
  rjmp loopsleep

 programm3:
  ldi rmp, LOW(P3STEP)
  ldi rmp2, HIGH(P3STEP)
  cp lowbyte, rmp
  cpc highbyte, rmp2
  breq p3_ledan

  ldi rmp, LOW(2*P3STEP)
  ldi rmp2, HIGH(2*P3STEP)
  cp lowbyte, rmp
  cpc highbyte, rmp2
  breq p3_ledaus

  ldi rmp, LOW(3*P3STEP)
  ldi rmp2, HIGH(3*P3STEP)
  cp lowbyte, rmp
  cpc highbyte, rmp2
  breq p3_ledan

  ldi rmp, LOW(4*P3STEP)
  ldi rmp2, HIGH(4*P3STEP)
  cp lowbyte, rmp
  cpc highbyte, rmp2
  breq p3_ledaus

  ldi rmp, LOW(5*P3STEP)
  ldi rmp2, HIGH(5*P3STEP)
  cp lowbyte, rmp
  cpc highbyte, rmp2
  breq p3_ledan

  ldi rmp, LOW(6*P3STEP)
  ldi rmp2, HIGH(6*P3STEP)
  cp lowbyte, rmp
  cpc highbyte, rmp2
  breq p3_ledaus
  rjmp loopsleep

 p3_ledan:
  sbi LEDPORT, LED1
  rjmp p3_ende

 p3_ledaus:
  cbi LEDPORT, LED1

 p3_ende:
 rjmp loopsleep


beep:
 ldi rmp2,FAKTOR
 beep1:
  dec rmp2
  brne beep1
 beep2:
  ldi rmp2, FAKTOR
  dec rmp
  brne beep1
  ldi rmp, COUNTERDIT
 ret

case:
 push rmp
 ldi ZL,LOW(sprungtabelle)
 ldi ZH,HIGH(sprungtabelle)
 add ZL, programmnummer
 adc ZH, zero
 ijmp

 sprungtabelle:
  rjmp case0
  rjmp case1
  rjmp case2
  rjmp case3
  rjmp case4

 case0: ; Blinker
  rcall cleartimer0
  ldi rmp, (1<<COM0A0)|(1<<COM0A1)|(WGM00)|(WGM01)
  out TCCR0A, rmp
  ldi rmp, (1<<CS02)
  out TCCR0B, rmp
  ldi rmp, 2
  out TIMSK0, rmp
  ldi rmp,128
  out OCR0A, rmp
  rjmp caseende

 case1: ; Morsen
  cbi LEDPORT,LED2
  rcall cleartimer0
  rjmp caseende

 case2: ; Flackern
  rcall init_timer0
  rjmp caseende

 case3: ; manuelles Flackern; timer nur als Zähler ohne Ausgang
  rcall init_timer0
  ldi rmp,(1<<WGM00)|(1<<WGM01)   ; keine PWM-Ausgabe
  out TCCR0A,rmp
  out TCCR0B, eins ;kein prescaler
  cbi PORTB,LED1
  cbi LEDPORT,LED2
  rjmp caseende

 case4:  ; Dauerlicht
  sbi LEDPORT,LED1

 caseende:
  cbr statusbits,(1<<PROGRAMHASCHANGED)    ; bits, nicht bit. 2 = Programchange auf Null
  pop rmp
  ret


cleartimer0:
 out TCCR0A, zero
 out TCCR0B, zero
 out TIMSK0, zero
 ret


countercompare:
 cp counter,zero
 brne weiter
 sbr statusbits,(1<<COUNTERISZERO)
 ret

 weiter:
  dec counter
  ret


initsleep:
 push rmp
 in rmp,MCUCR
 ori rmp,(1<<SE)
 out MCUCR,rmp
 pop rmp
 ret

tastegedrueckt:
 push rmp
 cpi counter, 0  ; erst wenn counter=0 Aktion auslösen, sonst mach gar nichts
 brne tastefertig
 ; setze statusbits0 auf 0, setze counter auf seinen Startwert, programm+1
 cbr statusbits, (1<<COUNTERISZERO) ; bits, nicht bit. 1 = counteriszero
 ldi counter, COUNTERVALUE
 inc programmnummer
 sbr statusbits,(1<<PROGRAMHASCHANGED)
                  ;Bit Programmchange auf "1" setzen
 cpi programmnummer, PROGRAMMAX
 brne tastefertig
 clr programmnummer

 tastefertig:
  ldi savecounter,SAVE_COUNTER
  pop rmp
 ret


getfromeeprom:
 ldi ZL, low(textdaten)
 add ZL, eepromcounter

 eeprom_read:
  sbic EECR, EEWE
  rjmp eeprom_read
  out EEARL, ZL
  sbi EECR, EERE
  in eeprombyte, EEDR
  inc eepromcounter
  tst eeprombyte
  breq reset
  ret

  reset:
   clr eepromcounter
  ret

write2eeprom:
 push rmp
 in rSreg,SREG
 out EEDR, programmnummer
 writestart:
 sbic EECR, EEWE
 rjmp writestart
 ldi ZL, LOW(EEPROMADRESSE)
 out EEARL, ZL
 cli
 sbi EECR, EEMWE
 sbi EECR, EEWE
 writeende:
 sbic EECR, EEWE
 rjmp writeende
 cbr statusbits,(1<<SAVENEEDED)
 ldi savecounter, SAVE_COUNTER
 sei
 out SREG,rSreg
 pop rmp
 ret

zufallszahl32:
 ror number1
 ror number2
 ror number3
 ror number4
 brcs one
 ;zero
 mov zufallszahl, number4
 cp zufallszahl,sollwert
 brlo set_minimum
 ret

 one:
  eor number1,rueckf1
  eor number2,rueckf2
  eor number4,rueckf4
  mov zufallszahl, number4
  cp zufallszahl,sollwert
  brlo set_minimum
  ret

 set_minimum:
  add zufallszahl,sollwert
 ret


getletterfromflash:
 push rmp
 cpi letter,65
 brlo ziffer
 ldi ZL,LOW(buchstaben*2)
 ldi ZH,HIGH(buchstaben*2)
 mov rmp,ZL
 subi letter,'A'
 rjmp getletter_ende

 ziffer:
  ldi ZL,LOW(ziffern*2)
  ldi ZH,HIGH(ziffern*2)
  mov rmp,ZL
  subi letter,'0'

  getletter_ende:
  add rmp,letter
  mov ZL,rmp
  lpm letter,Z
  pop rmp
 ret


init_timer0:
 push rmp
 ldi rmp,(1<<WGM00)|(1<<WGM01)|(1<<COM0A1) ; clear OC0A on cpmpare match, set at top + 3 = fast-PWM-mode
 out TCCR0A,rmp
 ldi rmp,2  ; prescaler 8
 out TCCR0B,rmp
 ldi rmp,6     ; timer overflow und compare match enable
 out TIMSK0,rmp
 pop rmp
 ret

init_watchdog:
 cli
 push rmp
 push rmp2
 wdr
 in rmp,MCUSR
 andi rmp,(0xff - (1<<WDRF))
 out MCUSR, rmp
 in rmp,WDTCR
 ori rmp,(1<<WDTIE)|(1<<WDP1) ; 64ms
 out WDTCR, rmp
 pop rmp2
 pop rmp
 sei
 ret

buchstaben:
.db 0b01000010,0b10000001,0b10000101,0b01100001,0b00100000,0b10000100,0b01100011,0b10000000
.db 0b01000000,0b10000111,0b01100101,0b10000010,0b01000011,0b01000001,0b01100111,0b10000110
.db 0b10001011,0b01100010,0b01100000,0b00100001,0b01100100,0b10001000,0b01100110,0b10001001
.db 0b10001101,0b10000011

ziffern:
.db 0b10111111,0b10111110,0b10111100,0b10100011,0b10110000,0b10100000,0b10100001,0b10100011,0b10100111,0b10101111