![]() |
Anwendungen der AVR Single chip controller AT90S, ATtiny, ATmega and ATxmega Audiosensor mit einem ATtiny45 Assembler-Quellcode |
;
; ****************************************
; * Folge mir Audio Sensor mit *
; * ATtiny25/45/85, Version 1 April 2018 *
; * (C)2018 by avr-asm-tutorial.net *
; ****************************************
;
; Arbeitet wahlweise mit einem ATtiny45 oder
; einem ATtiny85 ohne Aenderungen,
; kann an einen ATtiny25 angepasst werden
; durch Setzen des entsprechenden Schal-
; ters indem das Speichern der 16-Bit-Zeit-
; stempel unterbunden wird.
;
; **********************************
; T Y P E N A U S W A H L
; **********************************
;
; Waehlt den Zieltyp aus, entweder den
; ATtiny 45 oder den ATtiny85, bei Auswahl
; des ATtiny25 werden Zeitstempel abge-
; schaltet
.equ dev_sel = 45 ; kann 25, 45 oder 85 sein
;
;
.nolist
.if dev_sel == 25
.include "tn25def.inc"
.set tstmp = 0
.endif
.if dev_sel == 45
.include "tn45def.inc"
.set tstmp = 1
.endif
.if dev_sel == 85
.include "tn85def.inc"
.set tstmp = 1
.endif
.list
;
; Erzwingen der Zeitstempel-Einstellung
; ueberschreibt die Einstellung bei der
; Typauswahl
.set tstamp = 1 ; 0 = keine Zeitstempel
;
.if (tstamp == 1)&&(dev_sel == 25)
.error "Nicht genug Platz im EEPROM!"
.endif
;
; **********************************
; D E B U G - S C H A L T E R
; **********************************
; Alle Debug-Schalter = 0 in der Endversion
;
; Testen der angeschlossenen Hardware
;
; Schalte beide roten LEDs ein und
; unendliche Schleife
.equ debug_ledsRed = 0 ; 0 oder 1
;
; Schalte gruene LED an und unendliche
; Schleife
.equ debug_ledGreen = 0 ; 0 oder 1
;
; Schalte den Lautsprecher an und
; unendliche Schleife
.equ debug_speaker = 0 ; 0 oder 1
;
; Teste das Mikrofon und die ADC-Funktion
;
; Sammle AD-Wandler-Datensets, mittele und
; verwende den Durchschnitt als Pulsweiten-
; modulation fuer beide LEDs
.equ debug_mikeadc = 0
;
; Sammle die Maxima bei 64 AD-Wandler-Daten-
; sets, schalte die Interrupts aus, kopie-
; re die Daten in das EEPROM und unendliche
; Schleife
.equ debug_eep = 0
;
; Sammle 64 AD-Wandler-Datensets-Rohdaten,
; schalte die Interrupts aus, kopiere die Daten
; ins EEPROM, schalte die rote LED an und
; unendliche Schleife
.equ debug_eep_raw = 0
;
; **********************************
; H A R D W A R E
; **********************************
;
; AVR-Typen: ATtiny25/45/85
; Packung: 8-pin-PDIP_SOIC
;
; ________
; 1 / |8
; RESET o--|RES VCC|--o VCC
; 2| |7
; Udiff - o--|ADC3 PB2|--o R/G-Led rote anode
; 3| |6
; UMike + o--|ADC2 PB1|--o R/G-Led gruene Anode
; 4| |5
; GND o--|GND OC0A|--o Lautsprecher, R-Led Kathode
; |_________|
;
;
; **********************************
; P O R T S U N D P I N S
; **********************************
;
; LED-Ports und -Pins
.equ pLedO = PORTB ; Led-Port Output
.equ bLedRCO = PORTB0 ; Rote Led Kathodenpin
.equ bLedRGRAO = PORTB2 ; Rot/gruen Led rote Anode Pin
.equ bLedRGRCO = PORTB1 ; Rot/gruen Led rote Kathode Pin
.equ bLedRGGAO = PORTB1 ; Rot/gruen LED gruene Anode Pin
.equ bLedRGGCO = PORTB2 ; Rot/gruen LED gruene Kathode Pin
.equ pLedD = DDRB ; Led-Port Richtung
.equ bLedRCD = DDB0 ; Rote Led Kathode Richtung Pin
.equ bLedRGRAD = DDB2 ; Rot/gruene Led rote Anode Richtung Pin
.equ bLedRGGAD = DDB1 ; Rot/gruene Led gruene Anode Richtung Pin
; Lautsprecher-Port und -Pins
.equ pSpkO = PORTB ; Lautsprecher Ausgangsport
.equ bSpkO = PORTB0 ; Lautsprecher Ausgangspin
.equ pSpkD = DDRB ; Lautsprecher Richtungsport
.equ bSpkD = DDB0 ; Lautsprecher Richtungspin
;
; ***********************************
; E I N S T E L L K O N S T A N T E N
; ***********************************
; Taktfrequenz Prozessor, wird zu Beginn durch
; Schreiben in den CLKPR-Port eingestellt
.equ clock=2000000 ; Taktfrequenz
;
; Anzahl der Triggerwertueberschreitungen die zu
; Alarm fuehren, zwischen 1 und 100
.equ cTriggr = 50 ; Triggerpegelueberschreitungen in %
;
; Alarmdauer in Zehntel-Sekunden
; Kann zwischen 1 und 41 eingestellt werden
.equ cAlrm = 10 ; Vielfache von 0,1 Sekunden
;
; Alarmtonhoehe, 62 Hz .. 15 kHz
.equ cTone = 880 ; Ton in Hz
;
; **********************************
; F E S T K O N S T A N T E N
; **********************************
;
; Alarmzaehler fuer TC1
.equ cAlrmC = clock / 128 /256 * cAlrm / 10
;
; Alarmtonumrechnung
.equ cToneC = clock / 64 / cTone ; CTC-A TC0
;
; Triggerpegelschwelle
.equ cTrigger = (64*cTriggr+50)/100 ; Triggerschwelle
;
;
; Pruefe Einstellungen
.if cAlrmC > 255
.error "Alarmdauer-Konstante zu gross!"
.endif
.if (cToneC<1)||(cToneC>255)
.error "Alarmfrequenz ausserhalb zulaessiger Bereich!"
.endif
.if (cTrigger<1) || (cTrigger>64)
.error "Triggerschwelle ausserhalb zulaessiger Bereich!"
.endif
;
; **********************************
; T I M I N G
; **********************************
;
; Timing des AD-Wandlers:
; Der AD-Wandler wird mit einem Vorteiler
; von 2 getaktet. Er wandelt das 20-fach
; verstaerkte Differenzsignal an den Ein-
; gaengen (ADC2 - ADC3) aus.
; Takt Controller = 2 MHz
; Vorteiler ADC = 2
; Wandlungstakt = 1 MHz
; Wandlungsschritte = 13
; Wandlungszeit = 13 us
; Zeit von Wandlungsstart bis
; ADC-Interrupt = 13 us
; Controllertakte hierfuer = 26
; Takte bis zum Neustart: 21/23/25/26/35/38
; Minimum bis zum Neustart = 10,5 us
; Maximum bis zum Neustart = 19 us
; Wandlungszeit Minimum = 23,5 us
; Wandlungszeit Maximum = 32 us
; Wandlungszeit mit TC0-Int = 39 us
; Minimum Wandlungsfrequenz = 25,64 kHz
; Maximum Wandlungsfrequenz = 42,55 kHz
;
; 8-Bit Timer TC0 als Zeitbasis und als Tongenerator
; Als Zeitbasis waehrend Messphase:
; Modus: 8-Bit Normalbetrieb
; Kontrollertakt = 2 MHz
; Prescaler = 256
; TC0-Tick = 128 us
; Ueberlaufzeit = 32,77 ms
; Ueberlauffrequenz = 30,5 Hz
; Ueberlauf MSB in TC0H = 8,38 s
;
; Als Tongenerator in der Alarmphase:
; Modus: 8-Bit CTC mit OCR0A und OC0A-Togglen
; Controller Takt = 2 MHz
; Precaler = 64
; Tonfrequenz, OCR0A=0x01 = 15,6 kHz
; Tonfrequenz, OCR0A=0xFF = 61 Hz
;
; 8-Bit Timer TC1 als PWM fuer Pegelanzeige
; zeigt auf der rot/gruenen LED den Pegel an
; und stellt Dauer in der Alarmphase fest
; Als LED-PWM (Normalbetrieb):
; Controllertakt = 2 MHz
; Prescaler = 128
; Zeit pro Timertick = 64 us
; Zeit fuer 256 Timerticks = 16.384 ms
; Zeit bis Ueberlauf = 16,4 ms
; PWM-Frequenz rot/gruene LED = 61 Hz
;
; Als Alarmzeit Timer (bei Alarm):
; Controllertakt = 2 MHz
; Prescaler = 128
; Zeit pro Timertick = 64 us
; Zeit fuer 256 Timerticks = 16,384 ms
; Zaehlwert fuer 1 Sekunde = 61
; Zaehlwert fuer 4 Sekunden = 244
;
; **********************************
; R E G I S T E R
; **********************************
;
; Verwendet: R1:R0 fuer Addierer Pegelwerte
; Verwendet: R2 fuer Maximalwert
; frei: R3 bis R8
.def rMaxA = R9 ; Maximum Analogwert
.def rLast = R10 ; Letzter gemessener Wert
.def rTrigger = R11 ; Triggerwert
.def rTc0L = R12 ; TC0-Zeitstempel, LSB
.def rTc0H = R13 ; TC0-Zeitstempel, MSB
.def rTop = R14 ; Spitzenwert innerhalb von Ints
.def rSreg = R15 ; Sichern/Wiederherstellen Statusregister
.def rmp = R16 ; Vielzweckregister
.def rimp = R17 ; Vielzweckregister innerhalb Ints
.def rFlag = R18 ; Flaggenregister
.equ bOvf = 0 ; Ueberlauf ADC-Wertepuffer, nicht verwendet
.equ bDwn = 1 ; Signalwert am ADC abwaerts
.equ bDsc = 2 ; Pufferende, werte Datensaetze aus
.equ bAlrm = 3 ; Alarmphase aktiv
.def rOvfC = R19 ; Ueberlaufzaehler, nicht verwendet
.def rDscC = R20 ; Datensatzzaehler
.def rAlrmC = R21 ; Alarmzaehler
; frei: R22 bis R27
; Verwendet: R27:R26 = X fuer EEPROM-Schreiben
; Verwendet: R29:R28 = Y als Pufferzeiger
; Verwendet: R31:R30 = Z fuer diverse Zwecke
;
; **********************************
; S R A M
; **********************************
;
.dseg
.org SRAM_START
.equ nDataSets = 64 ; Datenset=zwei Byte Zeit, ein Byte AD-Wert
sBuffer:
.if tstmp == 1
.byte 3*nDataSets ; Reserviere 192 Bytes fuer Datensaetze
.else
.byte nDataSets ; Reserviere 64 Bytes fuer Daten
.endif
sBufferDataEnd:
.byte 1 ; Durschschnitt
.byte 1 ; Maximalwert
.byte 1 ; Triggerwert
sBufferEnd:
;
; **********************************
; C O D E
; **********************************
;
.cseg
.org 000000
;
; *************************************
; R E S E T & I N T - V E K T O R E N
; *************************************
rjmp Main ; ResetveKtor
reti ; INT0
reti ; PCI0
reti ; OC1A
rjmp Ovf1Int ; OVF1
rjmp Ovf0Int ; OVF0
reti ; ERDY
reti ; ACI
rjmp AdcRdy ; ADCC
reti ; OC1B
reti ; OC0A
reti ; OC0B
reti ; WDT
reti ; USI_START
reti ; USI_OVF
;
; **********************************
; I N T - S E R V I C E R O U T .
; **********************************
;
; Ueberlauf-Interrupt TC0: 8-Bit-Zaehler
; Messphase: Normaler Zaehler, liefert Zeitstempel MSB
; Alarmphase: Interrupt aus, CTC fuer Lautsprecherausgang
Ovf0Int: ; 7 Takte fuer Interrupt&Vektorsprung
in rSreg,SREG ; Sichere SREG, +1=8
inc rTc0H ; Erhoehe MSB, #1=9
out SREG,rSreg ; Stelle SREG wieder her, +1=10
reti ; +4=14
;
; Ueberlauf-Interrupt TC1
; Messphase: 8-Bit PWM, Interrupt aus
; Alarmphase: Normalbetrieb, Alarmdauer zaehlen
Ovf1Int:
in rSreg,SREG ; Sichern SREG
tst rAlrmC ; Alarmzeit aktiv?
breq Ovf1Int1 ; Alarmzeit aus
dec rAlrmC ; Abwaerts zaehlen
Ovf1Int1:
out SREG,rSreg ; Stelle SREG wieder her
reti
;
; ADC-Wandlung komplett Interrupt
; Taktzyklen: +n=nc: ISR-Ausfuehrungstakte
; #n: Taktzyklen vom letzten ADC-Start bis Neustart
AdcRdy: ; 7 Takte fuer Interrupt, #12
in rTc0L,TCNT0 ; Lese LSB Zeit, +1=8, #13
in rSreg,SREG ; Sichern SREG, +1=9, #14
in rimp,ADCH ; Lese MSB ADC, +1=10, #15
.if debug_eep_raw == 0
tst rimp ; Null? +1=11, #16
breq AdcZero ; Ja, loesche Abwaertsflagge +1/2=12/13, #17/18
cp rimp,rLast ; Vergleiche mit letztem Wert, +1=13, #18
mov rLast,rimp ; Letzter=Aktueller Wert, +1=14, #19
brcc AdcGreater ; Wert steigt, +1/2=15/16, #20/21
cp rimp,rTop ; Kleiner als ITop?, +1=16, #21
brcc AdcGreater ; Steigt wieder, +1/2=17/18, #22/23
sbrc rFlag,bDwn ; Ueberspringe wenn bDwn-Flagge Null, +1/2=18/19, #23/24
rjmp AdcRet ; +2=20, #25
.endif
.if tstmp == 1 ; Speichere Zeitstempel in Puffer
st Y+,rTc0L ; LSB Zeit in Puffer, +2=21, #26
st Y+,rTc0H ; MSB Zeit in Puffer, +2=23, #28
.endif
.if debug_eep_raw == 1
st Y+,rimp ; Speichere Messwert in Puffer, +2=25, #30
.else
st Y+,rTop ; Speichere Maximalwert in Puffer, +2=25, #30
.endif
sbr rFlag,1<<bDwn ; Setze Datenflagge, +1=26, #31
dec rDscC ; Vermindere Datensatzzaehler, +1=27, #32
brne AdcRet ; Nicht am Pufferende, +1/2=28/29, #33/34
ldi YH,High(sBuffer) ; Y-Zeiger neu beginnen, +1=29, #34
ldi YL,Low(sBuffer) ; +1=30, #35
ldi rDscC,nDataSets ; Datensatzzaehler neu beginnen, +1=31, #36
sbr rFlag,1<<bDsc ; Datenpuffer voll Flagge, +1=32, #37
AdcRet: ; 19/20/21/30/32 Takte, #23/24/25/34/37
; Neustart ADC
ldi rimp,(1<<ADEN)|(1<<ADSC)|(1<<ADIE)|(1<<ADPS0); +1=20/21/22/31/33, #25/26/27/35/38
out ADCSRA,rimp ; Start naechste Wandlung, +1=22/32/34, #0
out SREG,rSreg ; Stelle SREG wieder her, +1=23/33/35, #1
reti ; +4=27/37/39, #5
AdcGreater: ; 16/18 Takte, #21/23
cpi rimp,0x10 ; Ignore Kleinstwerte, +1=17/19, #22/24
brcs AdcClrTop ; Loesche rTop, +1/2=18/19/20/21, #23/24/25/26
mov rTop,rimp ; Setze neuen Top-Wert, 1=19/21, #24/26
ldi rimp,(1<<ADEN)|(1<<ADSC)|(1<<ADIE)|(1<<ADPS0); +1=20/22, #25/27
out ADCSRA,rimp ; Starte naechste Wandlung, +1=19/21, #0
out SREG,rSreg ; Stelle SREG wieder her, +1=20/22, #1
reti ; +4=24/26, #5
AdcZero: ; ADC ist Null, 13 cycles, #18
cbr rFlag,1<<bDwn ; Loesche bDwn-Flagge, +1=14, #19
AdcClrTop:
clr rTop ; Loesche rTop-Wert, +1=15, #20
ldi rimp,(1<<ADEN)|(1<<ADSC)|(1<<ADIE)|(1<<ADPS0); +1=16, #21
out ADCSRA,rimp ; Starte naechste Wandlung, +1=17, #0
out SREG,rSreg ; Stelle SREG wieder her, +1=18, #1
reti ; +4=22, #5
;
; *************************************
; H A U P T P R O G R A M M, I N I T
; *************************************
;
Main:
.if dev_sel != 25 ; Nicht bei ATtiny25
ldi rmp,High(RAMEND) ; Init MSB Stapel
out SPH,rmp ; Init MSB Stapelzeiger
.endif
ldi rmp,Low(RAMEND) ; Init LSB Stapel
out SPL,rmp ; Init LSB Stapelzeiger
; Setze Controllertakt auf 2 MHz
ldi rmp,1<<CLKPCE ; Taktvorteiler-Enable
out CLKPR,rmp
ldi rmp,1<<CLKPS1 ; Taktvorteiler auf 4
out CLKPR,rmp
; Init rote LED Portpin
sbi pLedD,bLedRCD ; Rote Led Kathode als Ausgang
sbi pLedO,bLedRCO ; Rote Led Kathode high
; Init rot/gruene Duo-LED
sbi pLedD,bLedRGRAD ; Rot/gruen rote Anode Ausgang
sbi pLedD,bLedRGGAD ; Rot/gruen gruene Anode Ausgang
cbi pLedO,bLedRGRAO ; Rot/gruen rote Anode low
cbi pLedO,bLedRGGAO ; Rot/gruen gruene Anode low
.if debug_ledsRed == 1 ; Test der beiden roten LEDs
cbi pLedO,bLedRCO ; Rote Led-Kathode an
sbi pLedO,bLedRGRAO ; Rote Anode high
cbi pLedO,bLedRGGAO ; Gruene Anode low
test_leds_Red_Loop:
rjmp test_leds_Red_Loop ; Unendliche Schleife
.endif
.if debug_ledGreen == 1 ; Teste die gruene LED
sbi pLedO,bLedRGGAO ; Gruene Anode high
cbi pLedO,bLedRGRAO ; Rote Anode low
test_led_green_loop:
rjmp test_led_green_loop ; Unendliche Schleife
.endif
; Init Lautsprecher Portpin
sbi pSpkD,bSpkD ; Lautsprecher Portpin Ausgang
sbi pSpkO,bSpkO ; Lautsprecher Portpin high (rote LED aus)
.if debug_speaker == 1 ; Lautsprecher testen
ldi rmp,clock / 8 / 2000 ; Vergleicher A auf 1000 Hz
out OCR0A,rmp
ldi rmp,(1<<COM0A0)|(1<<WGM01) ; CTC bei OCR0A, Toggle OC0A
out TCCR0A,rmp
ldi rmp,(1<<CS01) ; Prescaler = 8
out TCCR0B,rmp
test_speaker_loop:
rjmp test_speaker_loop ; Unendliche Schleife
.endif
; Abschalten der Portpin-Treiber ADC2 und ADC3
ldi rmp,(1<<ADC2D)|(1<<ADC3D)
out DIDR0,rmp
; Init des ADC und des Timers zum Start im Messmodus
rcall InitAdcTimer
; Interrupts und sleep mode idle
ldi rmp,1<<SE ; Sleep mode idle
out MCUCR,rmp
sei ; Enable Interrupts
;
; **********************************
; P R O G R A M M S C H L E I F E
; **********************************
;
Loop:
sleep ; Schlafen legen
nop ; Dummy fuer Wecken
sbrc rFlag,bAlrm ; Alarm aktiv?
rcall Alarm ; Ja, behandle Alarm
sbrc rFlag,bDsc ; Datensaetze komplett Flagge?
rcall Update ; Ja, behandle Update
rjmp loop
;
; Aktiver Alarm
Alarm:
tst rAlrmC ; Alarmzaehler auf Null?
brne AlarmRet ; Nein, warte weiter
ldi rmp,0 ; Alarm zu Ende, loesche Puffer
ldi ZH,High(sBuffer) ; Z auf Puffer
ldi ZL,Low(sBuffer)
Alarm1:
st Z+,rmp ; Nullen schreiben
cpi ZH,High(sBufferDataEnd) ; Ende Puffer MSB?
brcs Alarm1 ; Nein, weiter
cpi ZL,Low(sBufferDataEnd) ; Ende Puffer LSB?
brcs Alarm1 ; Nein, weiter
ldi rmp,0xFF ; Alarm naechste Runde aus
mov rTrigger,rmp ; in Triggerwert
cbr rFlag,1<<bAlrm ; Loesche Alarmflagge
rcall InitAdcTimer ; Neustart Timer und ADC
AlarmRet:
ret
;
; Behandle Datentabelle
Update:
cbr rFlag,1<<bDsc ; Loesche Puffer-Komplett-Flagge
.if (debug_eep == 1)||(debug_eep_raw == 1) ; EEPROM-Schalter
clr rmp ; ADC, Timer und Interrupts abschalten
out ADCSRA,rmp
out TCCR0A,rmp
out TCCR0B,rmp
out TCCR1,rmp
out GTCCR,rmp
out TIMSK,rmp ; Timer-Interrupts aus
.endif
; Berechne Durchschnitt, Maximum und Triggerueber-
; schreitungen im SRAM-Puffer
.if tstmp == 1 ; Mit Zeitstempeln
ldi XH,High(sBuffer+2) ; Zeige auf ersten Wert mit Zeitstempel
ldi XL,Low(sBuffer+2)
.else
ldi XH,High(sBuffer) ; Zeige auf ersten Wert ohne Zeitstempel
ldi XL,Low(sBuffer)
.endif
clr ZH ; Loesche die Summe
clr ZL
clr rMaxA ; Loesche Maximalwert
clr R1 ; Loesche MSB Addierer
clr R2 ; Anzahl Ueberschreitungen
ldi rmp,nDataSets ; Anzahl Datensaetze
UpDate1:
ld R0,X+ ; Lese Datenbyte aus Puffer
cp R0,rMaxA ; Vergleiche mit Maximum
brcs UpDate2 ; Kleiner
mov rMaxA,R0 ; Speichere neues Maximum
Update2:
cp R0,rTrigger ; Vergleiche mit Triggerwert
brcs UpDate3 ; Kleiner
inc R2 ; Zaehle Ueberschreitung
UpDate3:
add ZL,R0 ; Addiere LSB zu Summe
adc ZH,R1 ; Addiere MSB wenn Carry
.if tstamp == 1
adiw XL,2 ; Zeige auf naechstes Datenbyte
.endif
dec rmp ; Anzahl Datensaetze abwaerts
brne Update1 ; Nicht fertig, weiter
lsl ZL ; Multipliziere Summe mit zwei
rol ZH
lsl ZL ; Multipliziere Summe mit vier
rol ZH
mov rTrigger,ZH ; Kopiere das MSB
out OCR1A,ZH ; Schreibe in TC1 Vergleichswert A
mov ZL,ZH ; Kopiere MSB
lsr ZL ; Dividiere durch zwei
add rTrigger,ZL ; Addiere zum MSB
brcc UpDate4 ; Kein Carry
ldi ZL,0xFF ; Setze Triggerwert auf Maximum
mov rTrigger,ZL ; Und in rTrigger
UpDate4:
.if (debug_eep==0)&&(debug_eep_raw==0) ; Debug-Schalter sind aus
mov rmp,rTrigger ; Kopiere Triggerwert
cpi rmp,0xFF ; Am Maximum?
breq UpDate5 ; Alarm aus
ldi rmp,cTrigger ; Anzahl Ueberschreitungen fuer Alarm
cp R2,rmp ; Vergleiche Ueberschreitungen
brcs UpDate5 ; Kleiner, kein Alarm
; Alarm-Bedingung erreicht, starte Alarmphase
cbi ADCSRA,ADIE ; ADC-Interrupts aus
ldi rmp,cToneC ; Alarmton-Frequenz
out OCR0A,rmp ; Auf Vergleicher TC0
ldi rmp,(1<<COM0A0)|(1<<WGM01) ; CTC, toggle OC0A
out TCCR0A,rmp ; An TC0 Control A
ldi rmp,(1<<CS01)|(1<<CS00) ; Prescaler =64
out TCCR0B,rmp ; An TC0 Control B
ldi rAlrmC,cAlrmC ; Setze Alarmdauer-Wert
ldi rmp,1<<TOIE1 ; Nur TC1-Interrupts
out TIMSK,rmp ; In Timer-Int-Maske
sbi pLedO,bLedRGRAO ; Setze RG rote Anode high
cbi pLedO,bLedRGGAO ; RG gruene Anode low
sbr rFlag,1<<bAlrm ; Alarmflagge
Update5:
ret ; Ende des Puffer-Updates
.else
; Schreibe den SRAM-Inhalt ins EEPROM
Write2Eep:
st X,rTrigger ; Haenge Triggerwert an
.if tstmp == 0
adiw XL,2 ; Ohne Zeitstempel zwei Byte vorwaerts
.endif
st -X,rMaxA ; Speichere Maximum
st -X,ZH ; Speichere Durchschnitt
clr rmp ; Abschalten ADC und Interrupts
out ADCSRA,rmp
out TIMSK,rmp ; Abschalten Timer-Interrupts
cli ; Keine Interrupts mehr
EepWait:
sbic EECR,EEPE ; Warte bis EEPROM bereit
rjmp EepWait
ldi rmp,0 ; Setze EEPROM Atomic loeschen/schreiben
out EECR,rmp
ldi XH,0 ; Zeiger in EEPROM
ldi XL,0
ldi ZH,HIGH(sBuffer) ; Z auf Puffer
ldi ZL,Low(sBuffer)
EepWr:
sbic EECR,EEPE ; Warte bis EEPROM bereit
rjmp EepWr
.if dev_sel != 25 ; Nur bei ATtiny45/85
out EEARH,XH ; Setze EEPROM Adresse MSB
.endif
out EEARL,XL ; Setze LSB Adresse
ld rmp,Z+ ; Lese Datenbyte aus SRAM
out EEDR,rmp ; Setze EEPROM-Datenport
sbi EECR,EEMPE ; Program Enable
sbi EECR,EEPE ; Program EEPROM
adiw XL,1 ; Naechste Adresse
cpi ZH,High(sBufferEnd) ; MSB Pufferende?
brne EepWr ; Nein, weiter
cpi ZL,Low(sBufferEnd) ; LSB Pufferende?
brne EepWr ; Nein, weiter
EepLedOn:
cbi pLedO,bLedRCO ; Rote Led an
EepLoop:
rjmp EepLoop ; Unendliche Schleife
.endif
;
; Init des ADC und der Timer fuer Messbetrieb
; beim Beginn und im Anschluss an Alarmphasen
InitAdcTimer:
; Init ADC
ldi YH,High(sBuffer) ; Y-Zeiger auf SRAM-Puffer-Start
ldi YL,Low(sBuffer)
ldi rDscC,nDataSets ; Anzahl Daten setzen
; ADC mit interner Reference 1.1V, ADLAR, Differential ADC2-ADC3, gain=20
ldi rmp,(1<<REFS1)|(1<<ADLAR)|(1<<MUX2)|(1<<MUX1)|(1<<MUX0)
out ADMUX,rmp ; ADC-Multiplexer
; Enable, Start conversion, int enable, clock/2
ldi rmp,(1<<ADEN)|(1<<ADSC)|(1<<ADIE)|(1<<ADPS0)
out ADCSRA,rmp ; ADC starten
; Starte TC0 als 8-Bit-Zaehler als Zeitbasis mit Prescaler 256
ldi rmp,(1<<COM0A1)|(1<<COM0A0); 8-Bit-Zaehler, Compare setzt OC0A, Mode normal
out TCCR0A,rmp
ldi rmp,1<<CS02 ; Prescaler = 256
out TCCR0B,rmp
; Starte TC1 als invertierte PWM mit prescaler 128
ldi rmp,0x00 ; Compare-Match-Wert kurz
out OCR1A,rmp
ldi rmp,0xFF ; Zaehlen bis 256
out OCR1C,rmp
ldi rmp,(1<<COM1A1)|(1<<CS13)|(1<<PWM1A) ; PWM-Signal an OC1A, prescaler 128
out TCCR1,rmp
clr rmp ; Kein PWM-Signal auf OC1B
out GTCCR,rmp
ldi rmp,1<<TOIE0 ; Nur Ueberlauf-Interrupt TC0
out TIMSK,rmp
cbi pLedO,bLedRGRAO ; Rote Anode low
sbi pLedO,bLedRGGAO ; Gruene Anode high
ret
;
; Copyright
.db "(C)2018 by Gerhard Schmidt "
.db "C(2)10 8ybG reahdrS hcimtd "
;
; Ende Quellcode
;