/* CLIP-Dekoder, ATtiny25, extremes Energiesparen */
#define __SFR_OFFSET 0
#include <avr/io.h>
#define TAU_SH 4 // 0, 4, 6 oder 8: Ausprobieren!
#define SUBSAMP 0 // 1 oder 0: Ausprobieren!
#define IRQMODE 1 // Beides funktioniert.
// Theoretisch müsste IRQMODE etwas Strom sparen
// Der Energiespeicher-Elko muss im IRQMODE 2200 µF haben,
// ohne 4700 µF. Aber das kann ein Beobachtungsfehler sein …
// Sicher ist sicher, ich muss wohl 4700 µF empfehlen.
// … Nee, alles Quatsch!
#define MEANL r8
#define MEANH r9
#if TAU_SH > 6
# define MEANE r10 // 18 Bit
#endif
#define DIFFL r12
#define DIFFH r13
#define TLEVEL r14 // Gefundener Schwellwert
#if SUBSAMP
# define TBEFORE r15 // 0..1
#endif
// Erstinitialisierung von AKKU mittels ADLAR
// CPU-Taktfrequenz: 1 MHz
// Zeit zwischen 2 Abtastwerten: 52 Takte
.global acInit,acMean,acOnes,acByte
acInit:
#if IRQMODE
ldi r24,0x21 // ADC-Störunterdrückung
out MCUCR,r24
ldi r24,0xFA
#else
ldi r24,0xF2 // Start; ADC-Takt = 250 kHz (4 µs), ADC-Rate = 19,23 kHz (52 µs)
#endif
out ADCSRA,r24
1:
#if IRQMODE
sei // ADC = einzige Interruptquelle
sleep // Die ISR sperrt die Interrupts, sonst nichts
#else
sbis ADCSRA,4
rjmp 1b
sbi ADCSRA,4 // Interruptflag löschen
#endif
#if TAU_SH == 6
in MEANL,ADCL
in MEANH,ADCH
cbi ADMUX,ADLAR // ab jetzt rechtsbündig
#elif TAU_SH == 4
cbi ADMUX,ADLAR // rechtsbündig auslesen
in r24,ADCL
in r25,ADCH
swap r24
swap r25
eor r25,r24
andi r24,0xF0
eor r25,r24
movw MEANL,r24 // x 16
#elif TAU_SH == 8
cbi ADMUX,ADLAR // rechtsbündig
clr MEANL
in MEANH,ADCL
in MEANE,ADCH
#elif TAU_SH == 0 // nur differenzieren (1. Ableitung)
cbi ADMUX,ADLAR // immer rechtsbündig
in MEANL,ADCL
in MEANH,ADCH
#else
# error TAU_SH fehlt oder falsch!
#endif
#if SUBSAMP
clr TBEFORE
#endif
ret
// kehrt bei Flanke zurück und liefert die Zeit in 26-µs-Schritten seit der letzten Flanke
// VR: W20-R24
acEdge: clr r24
1: movw r20,DIFFL // vorherigen Messwert retten
subi r24,-2
// Nächsten A/D-Wert holen und Flanke feststellen
// NZ = Flanke, Takte: 19 + (CallRet)7 = 24
0:
#if IRQMODE
sei
sleep
#else
sbis ADCSRA,4
rjmp 0b
sbi ADCSRA,4 // Interruptflag löschen
#endif
in DIFFL,ADCL
in DIFFH,ADCH
#if TAU_SH == 6 // R23 R22
movw r22,MEANL // AAAA BBBB CCCC DDDD
lsl r22 // CCCD DDD0
rol r23 // AAAB BBBC
rol r22 // CCDD DD0A
rol r23 // AABB BBCC
rol r22 // CDDD D0AA
andi r22,3 // 0000 00AA
sub DIFFL,r23 // τ = 64
sbc DIFFH,r22 // Differenz ermittelt
add MEANL,DIFFL
adc MEANH,DIFFH
#elif TAU_SH == 4 // R23 R22
movw r22,MEANL // 00AA BBBB CCCC DDDD
swap r22 // DDDD CCCC
swap r23 // BBBB 00AA
andi r22,0x0F // 0000 CCCC
eor r22,r23 // BBBB CCčč č = C^A
andi r23,3 // 0000 00AA
eor r22,r23 // BBBB CCCC
sub DIFFL,r22 // τ = 16 (mehr Hochpasswirkung)
sbc DIFFH,r23 // Differenz ermittelt
add MEANL,DIFFL
adc MEANH,DIFFH
#elif TAU_SH == 8
sub DIFFL,MEANH // 8 bit, τ = 256
sbc DIFFH,MEANE
sbc r22,r22
add MEANL,DIFFL
adc MEANH,DIFFH
adc MEANE,r22
#elif TAU_SH == 0
sub DIFFL,MEANL
sbc DIFFH,MEANH
add MEANL,DIFFL
adc MEANH,DIFFH
#else
# error
#endif
movw r22,DIFFL
eor r23,r21
brpl 1b // weitersuchen wenn keine Flanke
#if SUBSAMP
// W22 = neuer Messwert, W20 = alter Messwert
eor r23,r21
tst r21
brpl 5f
// W22 positiv, W20 negativ
com r20
com r21 // positiv machen
rjmp 20f
5:// W22 negativ, W20 positiv
com r22
com r23
20: cp r22,r20
cpc r23,r21 // Neuer Wert betragsmäßig kleiner dem alten?
adc r24,r1 // Dann Nulldurchgang in „zweier Hälfte“
mov r22,r24
andi r22,1
sub r24,TBEFORE // Vom vorherigen Nulldurchgang Zeit fürs Ergebnis abziehen
mov TBEFORE,r22 // Jetzigen Bruchteil merken
#endif
ret
#if F_CPU >= 8000000
# define F_DIV (F_CPU/8)
#elif F_CPU >= 4000000
# define F_DIV (F_CPU/4)
#else
# define F_DIV (F_CPU/2)
#endif
#define FADC (F_DIV/4/13)
// Ermitteln der durchschnittlichen Abstände der Nulldurchgänge
// 256 gültige Flanken ~ 200 ms
// R24 = durchschnittlicher Pegelwechsel-Abstand in 26 µs
// 1300 Hz => 385 µs => 14,8
// 2100 Hz => 238 µs => 9,2
acMean:
1: clr TLEVEL
clr r0
clr r25
2: rcall acEdge
cpi r24,FADC/870 // 22: 520 µs => 1 kHz
brcc 1b // Zu groß: Neustart
cpi r24,FADC/4800 // 4: 104 µs => 4 kHz
brcs 1b // Zu klein: Neustart
add r0,r24
adc TLEVEL,r1
dec r25
brne 2b // 256 Flanken ausmitteln
;inc TLEVEL // runden (gemessen: +1)
mov r24,TLEVEL // Hier kommt 6 raus
ret
#ifdef __AVR_ATtiny85__
.global acHisto
acHisto:
// R25:R24 = Zeiger auf <r22> Byte
movw XL,r24
mov r25,r22
clr r0
1: rcall acEdge
cp r24,r25
brcs 2f
mov r24,r25
dec r24
2: add XL,r24
adc XH,r1
ld r1,X
inc r1
st X,r1
clr r1
sub XL,r24
sbc XH,r1
dec r0
brne 1b
ret
#endif
// Sucht eine lange Kette von Einsen (tiefe Frequenz)
acOnes:
1: ldi r25,100
2: rcall acEdge
cp r24,TLEVEL
brcs 1b
dec r25
brne 2b
ret
#define FBIT (1200)
#define NBIT ((FADC*2+FBIT/2)/FBIT) // 32 @ 4 MHz, *2 wegen Subsampling
#define NSTA (NBIT*38/32) // 38 @ 4 MHz, erprobt
acByte:
0: rcall acEdge // Warten auf lange Abstände (1-Bits)
cp r24,TLEVEL
brcs 0b
1: rcall acEdge // Warten auf kurzen Abstand (0-Bit = Startbit)
cp r24,TLEVEL
brcc 1b
// Startbit erkannt; jedes Bit ist 32 x 26 µs lang
ldi r25,8 // Bitzähler
ldi r18,-NSTA // Bitzeit (hier 1. Abtastzeitpunkt einstellen! Lange habe ich probiert.)
2: rcall acEdge
add r18,r24
brcc 2b // 32 × 26 µs = 832 µs (1 Bitzeit) abwarten
subi r18,NBIT
cp r24,TLEVEL // Länge des letzten Abstands
ror r19 // Bit einschieben (noch invertiert)
dec r25
brne 2b // 8 Runden
com r19
mov r24,r19
ret
// Gemeinsamer Anfang für PutNib und GetNib
27: movw ZL,r24 // Basiszeiger
mov r0,r22 // Index
lsr r0
add ZL,r0
adc ZH,r1
ld r24,Z
sbrs r22,0
swap r24
ret
.global PutNib,GetNib,x10
PutNib: rcall 27b
andi r24,0xF0
or r24,r20 // Nibble (muss 0..F sein)
sbrs r22,0
swap r24
st Z,r24
ret
GetNib: rcall 27b
andi r24,0x0F
ret
x10: lsl r24
mov r0,r24
lsl r24
lsl r24
add r24,r0
ret
.global clock_set
clock_set:
cli
ldi r25,0x80
out CLKPR,r25
out CLKPR,r24
sei
ret
Vorgefundene Kodierung: UTF-8 | 0
|