.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