; ; *********************************** ; * (Add program task here) * ; * (Add AVR type and version here) * ; * (C)2021 by Gerhard Schmidt * ; *********************************** ; .nolist .include "tn13adef.inc" ; Define device ATtiny13A .list ; ; ********************************** ; H A R D W A R E ; ********************************** ; ; Device: ATtiny13A, Package: 8-pin-PDIP_SOIC ; ; ; ; / | 100n ; o--|RESET VCC|--o----||--- GND ; max232-TX o--|PB3 PB2|--o 470R -- LEDKette-Pin1 ; Fotodiode A o--|PB4 PB1|--o 470R -- LEDKette-Pin2 ; Fotodiode K o--|GND PB0|--o 470R -- LEDKette-Pin3 ; L_________/ ; ; ; ********************************** ; P O R T S A N D P I N S ; ********************************** ; ; (Add symbols for all ports and port pins with ".equ" here) ; (e.g. .equ pDirD = DDRB ; Define a direction port ; or ; .equ bMyPinO = PORTB0 ; Define an output pin) ; ; ********************************** ; A D J U S T A B L E C O N S T ; ********************************** ; ; (Add all user adjustable constants here, e.g.) .equ clock=1200000 ; Define the clock frequency .equ TIMER0COMPAREVALUE=50 .equ LEDS=6 .equ MAXLEDBRIGHTNESS=7 .equ FADEOUT=1 ; Schrittweite der Helligkeitsstufe für fader .equ ADCTIME=80 ; mit WDT ca. alle zehn Sekunden .equ ADCSCHWELLELOW=50 ; ab dieser Schwelle aufwärts ist es hell .equ HYSTHERESE=10 ; mit Hystherese: von dunkel nach hell ab 60 aufwärts, von hell nach dunkel ab 50 abwärts .equ ADCSCHWELLEHIGH=ADCSCHWELLELOW+HYSTHERESE .equ TX=PB3 ; Serial tx pin .equ TXDELAY=37 ; für bitbanging - abhängig von der clock/Toleranz .equ PASSESTOTAL=6 ; so viele Durchläufe insgesamt .equ PASSESWITHLIGHT=2 ; davon so viele mit Lauflicht, der Rest ist Pause. Hier: 6 Zyklen insgesamt, zwei mal hintereinander Lauflicht, dann vier mal Pause .equ PASSESWITHOUTLIGHT=PASSESTOTAL-PASSESWITHLIGHT ; für data, siehe unten: .equ ISINITIALIZED=0 .equ SLEEPING=1 ; wenn=1 => Stromsparmodus. Andernfalls normalbetrieb (bei Helligkeit) ; ; ********************************** ; F I X & D E R I V. C O N S T ; ********************************** ; ; (Add symbols for fixed and derived constants here) ; ; ********************************** ; R E G I S T E R S ; ********************************** ; ; free: R0 to R14 .def zero=R0 ; Null .def adcvalue=R1 ; der vom ADC gemessene Wert, acht Bit .def ledbyte=R2 ; Datenbyte für Charlieplexing einer LEDs: bit 0-2 für DDRB, bit 5-7 für PORTB, siehe init_sram .def pointeroffset=R3 ; offset für Zeiger auf sram-Position. Enthält beispielsweise "3": Drei Positionen im SRAM weiter .def adcschwelle=R4 ; die aktuelle ADC-Schwelle .def char=R5 ; für serialsend .def rSreg = R15 ; Save/Restore status port .def rmp = R16 ; Define multipurpose register ; data: ; Bit 0 = isinitialized ; Bit 1 = sleeping .def data=R17 .def ledcounter=R18 ; Index der gerade aktiven LED: 0 bis (LEDS-1) .def brightnessvalue=R19 ; aktueller Helligkeitswert aus dem sram .def delaycounter=R20 ; Pause zwischen Duchläufen .def watchdogcounter=R21 .def watchdogmax=R22 ; So viele Runden, danach von vorne .def ledpos=R23 ; Index für die jeweilige LED .def zahl=R24 ; zu konvertierende Zahl für itoa .def temp=R25 .def sramvalue=R27 ; ein Byte Buffer für sram lesen/schreiben .def rmp2=R28 ; free: R17 to R29 ; free: R31:R30 = Z ; ; ********************************** ; S R A M ; ********************************** ; .dseg .org SRAM_START leddaten: .byte 12 ; Charlieplexing-Daten für sechs LEDs plus sechs Helligkeitswerte. sram_einer: .byte 1 ; für itoa sram_zehner: .byte 1 sram_hunderter: .byte 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 ;rjmp isr_pcint0 ; INT0 reti ; PCI0 reti ; OVF0 reti ; ERDY reti ; ACI rjmp isr_timer0comparematch ; OC0A reti ; OC0B rjmp isr_watchdog ; WDT reti ; ADCC ; ; ********************************** ; I N T - S E R V I C E R O U T . ; ********************************** isr_timer0comparematch: ; etwa alle 4,3 ms ; bei jedem Durchgang werden alle LEDs erst mal ausgeschaltet. ; Jeder Durchgang beandelt eine LED. ; Wenn die Maximalzahl der LEDs bei jedem 6. Durchlauf erreicht ist, ; wird der Helligkeitsvergleichswert "brightnessvalue" um eins erhöht. ; dann werden alle LEDs erst mal ausgeschaltet. ; Danach wird geprüft, ob der aktuelle Helligkeitswert der LED ; größer oder gleich dem Wert aus dem sram ist. ; LED an, wenn Helligkeitswert kleiner als der im SRAM. SRAM sagt: so hell soll die LED sein ; ansonsten bleibt sie aus ; Der Helligkeitswert der LED im sram wird hier nicht verändert, das macht der Watchdog. in rSreg,SREG push rmp ; inc watchdogcounter ; WIEDER RAUS sbrc data, SLEEPING ; bit 1 - sleeping rjmp isr_timer0comparematch_ende ; wenn im schlafmodus mach gar nichts inc ledcounter ; kann 0 bis 5 werden cpi ledcounter, LEDS brlo isr_timer0comparematch_leds clr ledcounter inc brightnessvalue cpi brightnessvalue, MAXLEDBRIGHTNESS+1 brlo isr_timer0comparematch_leds clr brightnessvalue isr_timer0comparematch_leds: mov pointeroffset, ledcounter ldi rmp, 6 add pointeroffset, rmp ; +6 Stellen für brightness im SRAM rcall get_from_sram ; befüllt sramvalue rcall clear_leds ; erst mal alle aus cp brightnessvalue, sramvalue brsh isr_timer0comparematch_ende ; wenn brightnessvalue größer als der im sram bleibt die LED aus mov pointeroffset, ledcounter ; ansonsten LED einschalten rcall get_from_sram mov rmp, sramvalue andi rmp,0x07 ; drei lsb aus unterem nibble in temp, DDRB or temp, rmp out DDRB, temp mov rmp, sramvalue swap rmp andi rmp, 0x07 ; drei lsb aus oberem nibble in temp, PORTB or temp, rmp out PORTB, temp isr_timer0comparematch_ende: pop rmp out SREG,rSreg reti isr_watchdog: ; ca. alle 0.125 Sekunden in rSreg,SREG push rmp inc watchdogcounter sbrc data, SLEEPING rjmp isr_watchdog_ende inc ledpos cpi ledpos, LEDS brlo isr_watchdog_weiter ; wenn Druchlauf 1-6 noch nicht fertig, dann weiter clr ledpos ; wenn Durchlaufende erreicht inc delaycounter cpi delaycounter, PASSESTOTAL brlo isr_watchdog_weiter clr delaycounter isr_watchdog_weiter: cpi delaycounter, PASSESWITHOUTLIGHT brlo isr_watchdog_weiter2 ldi ZL, LOW(leddaten+6) ldi ZH, HIGH(leddaten+6) add ZL, ledpos ; diese LED ist gerade aktiv, Zeiger an entsprechende Position verschieben ldi rmp, MAXLEDBRIGHTNESS+1 st Z, rmp ; sram-Helligkeit der LED ledpos mit maximaler Helligkeit füllen isr_watchdog_weiter2: ; ab hier nur noch Helligkeiten verringern ldi rmp, 6 mov pointeroffset, rmp ; leddaten + 6 => Helligkeitsdaten ldi rmp, 12 ; Bei 12 ist die letzte Speicherstelle erreicht isr_watchdog_schleife1: ; läuft sechs mal, Helligkeit aller LEDs verringern rcall get_from_sram ; aktuelle Helligkeitsstufe aus dem sram holen cpi sramvalue, 0 ; Helligkeit schon auf Null? Dann unten weiter. breq isr_watchdog_schleifeweiter subi sramvalue, FADEOUT ;andernfalls Helligkeit verringern brcc isr_watchdog_weiter3 ; wenn "unterlauf" -> auf Null setzen clr sramvalue isr_watchdog_weiter3: st Z, sramvalue isr_watchdog_schleifeweiter: inc pointeroffset cp pointeroffset, rmp ; letzte Speicherstelle erreicht? brlo isr_watchdog_schleife1 isr_watchdog_ende: pop rmp out SREG,rSreg reti get_from_sram: ldi ZL, LOW(leddaten) ldi ZH, HIGH(leddaten) add ZL, pointeroffset ld sramvalue, Z ret init_sram: ; Charlieplexing für sechs LEDs an PB0 bis PB2 ; erste sechs Bytes: LED-Charlieplexing-Daten ; nachfolgende sechs Bytes: Helligkeit der jeweiligen LED push rmp ldi ZL, LOW(leddaten) ldi ZH, HIGH(leddaten) ldi rmp, (0x04<<4)|(0x05) ; 0100 portb 1 st Z+, rmp ; 0101 ddrb 1 ldi rmp, (0x02<<4)|(0x06) ; 0010 portb 2 st Z+, rmp ; 0110 ddrb 2 ldi rmp, (0x04<<4)|(0x06) ; 0100 portb 3 st Z+, rmp ; 0110 ddrb 3 ldi rmp, (0x01<<4)|(0x03) ; 0001 portb 4 st Z+, rmp ; 0011 ddrb 4 ldi rmp, (0x02<<4)|(0x03) ; 0010 portb 5 st Z+, rmp ; 0011 ddrb 5 ldi rmp, (0x01<<4)|(0x05) ; 0001 portb 6 st Z+, rmp ; 0101 ddrb 6 ; ab hier ledbrightness, 6 x "8" (erst mal maximum) ldi rmp, 8 st Z+, rmp st Z+, rmp st Z+, rmp st Z+, rmp st Z+, rmp st Z+, rmp pop rmp ret init_watchdog: push rmp wdr clr rmp out WDTCR, rmp ldi rmp, (1< ca. 18.75 KHz out ADCSRA, rmp sbi ADCSRA, ADSC init_adc_wait: sbic ADCSRA, ADSC rjmp init_adc_wait in adcvalue, ADCH pop rmp ret init_all: rcall init_timer0 clr ledpos clr brightnessvalue clr delaycounter ;clr pointeroffset clr data sbr data,(1< dunkler. ab ADCSCHWELLE aufwärts ist es hell brsh loop_weiter ; wenn es hell ist -> weiter, sonst: ldi rmp2, ADCSCHWELLEHIGH ; es ist dunkel -> Normalbetrieb mov adcschwelle, rmp2 cbr data,(1< sleep-mode idle out MCUCR, rmp sbrs data,ISINITIALIZED ; bit 0 rcall init_all rjmp loop_ende loop_weiter: ; es ist hell -> alles aus, Schlafmodus ldi rmp2, ADCSCHWELLELOW mov adcschwelle, rmp2 rcall clear_leds ; alle LEDs aus sbr data, (1< 1 .... push rmp push rmp2 ldi rmp2, 48 ; für dec to ascii clr rmp itoa_hunderter: cpi zahl, 100 brlo itoa_zehner inc rmp subi zahl, 100 rjmp itoa_hunderter itoa_zehner: add rmp, rmp2 sts sram_hunderter, rmp clr rmp itoa_zehner2: cpi zahl, 10 brlo itoa_einer inc rmp subi zahl, 10 rjmp itoa_zehner2 itoa_einer: add rmp, rmp2 sts sram_zehner, rmp add zahl, rmp2 sts sram_einer, zahl pop rmp2 pop rmp ret serialsend: cli ; nicht unterbrechen push r16 push r17 push r18 ldi r16,10 ; Startbit + 8 Datenbits + ein Stopbit com char TxLoop_0: brcc Tx1_0 cbi PORTB,TX Tx1_0: brcs TxDone_0 sbi PORTB,TX TxDone_0: ldi r18,TXDELAY TxDelay_0: dec r18 brne TxDelay_0 lsr char dec r16 brne TxLoop_0 pop r18 pop r17 pop r16 sei ret