#define __SFR_OFFSET 0
#include "avr/io.h"
/* Dieses merkwürdig kurze Programm benötigt keinen Timer, keinen ADC,
keinen RAM, keinen Stack, keinen Interrupt und verschwenderische 4 Register.
Sowas wäre ein typischer Kandidat für PIC12F508,
wenn der nur genügend treiberstark wäre und einen Analogvergleicher hätte.
Oder ATtiny4, wenn der genügend Beinchen hätte.
Oder ATtiny11/12, habe ich gerade nicht zur Hand.
Oder ATtiny25, dessen OSCCAL ist etwas genauer.
TODO: Interrupt fürs Aufwecken bei Pin-Change und Analogvergleicher;
der externe OPV zieht aber ohnehin ständig Strom.
*/
//#define DEBUG
.section .fuse,"a",@progbits // --set-section-flags=.fuse="alloc,load" ersparen
#ifdef TCNT1 // ATtinyX5
.byte 0b01100011 // ATtiny15-Modus: 6,4 MHz
.byte 0b11011111 // unverändert
.byte 0b11111111 // unverändert
#else // ATtiny13
.byte 0b01101010 // unverändert, kein Brown-Out
.byte 0b11111111 // unverändert
#endif
.section .signature,"a",@progbits
.byte SIGNATURE_0,SIGNATURE_1,SIGNATURE_2
.text
// Initialisieren: Takt = 1,2 MHz, kein ADC/Timer/USI
#ifdef TCNT1
ldi r24,0b10000000
out CLKPR,r24
ldi r24,0b00000010 // Taktteiler /4 = 1,2 MHz
out CLKPR,r24
ldi r24,0b1111
#else
ldi r24,0b11
#endif
#ifdef PRR // Nicht bei ATtiny11/12
out PRR,r24 // Alles deaktivieren
// Initialisieren: Portpins, Analogvergleicher
ldi r24,0b000011
out DIDR0,r24
#endif
ldi r24,0b000100
out PORTB,r24
ldi r24,0b111001
out DDRB,r24 // PB5:0 = LLLhzL
ldi r24,0
0: rjmp 1f
1: dec r24
brne 0b // 1 ms warten: PB1 = Ucc/2 von außen
ldi r24,0b010000
out DDRB,r24 // PB5:0 = zLzhzz
ldi r24,0b00010011
out ACSR,r24 // Auslöser = steigende Flanke
out ACSR,r24 // Interrupt-Flag löschen
// Analogvergleicher: ACO = AIN0 - AIN1 = UPB0 - UPB1:
// Ohne Empfangssignal liefert die Schaltung an PB1 eine (ein klein wenig)
// höhere Spannung als an PB0 (Spannungsteiler aus R10 und R11).
// Negative Spitzen erscheinen als „positive Interrupts“
#ifdef DEBUG
4: ldi r24,0
out MCUSR,r24
in r24,WDTCR
sbr r24,1<<4
out WDTCR,r24
ldi r24,0b11000001 // Interrupt bei Watchdog alle 32 ms
out WDTCR,r24
wdr
#endif
// Hauptschleife:
// Wenn und solange Analogvergleicher H liefert, PB2 nach L ziehen
3: sbis ACSR,4 // Interrupt?
rjmp 2f
33: cbi PORTB,2
sbi DDRB,2 // PB2 = L
1: sbi ACSR,4 // Interrupt löschen
#ifdef DEBUG
sbic ACSR,5
rjmp 33b // wenn (erneut) H
sbi PORTB,2 // wenn L
cbi DDRB,2
#else
ldi r24,10
0: dec r24
brne 0b // 1 Periode (40 kHz = 25 µs) abwarten
sbic ACSR,4 // Erneute steigende Flanke?
rjmp 1b
cbi DDRB,2
sbi PORTB,2 // PB2 = h: Pullup reaktivieren
ldi r24,10
0: dec r24
brne 0b // warten bis PB2 H-Pegel annimmt (25 µs)
#endif
// Wenn PB2 L ist (von außen), Puls ausgeben, sonst weiter Analogvergleicher abfragen
#ifdef DEBUG
2: //sbis PINB,2
// rjmp 0f
in r24,WDTCR
sbrs r24,7 // Watchdog-Timeout da?
rjmp 3b // nein, weiter Analogverleicher-Output auslesen
#else
2: sbic PINB,2
rjmp 3b
#endif
// Burst (40 kHz @ 1,2 MHz) ausgeben: 15 Takte pro Halbwelle
0: ldi r25,0b000100 // Clamp aktivieren (Pullup belassen)
ldi r24,0b111001 // PB5:0 = LLLhzL
out PORTB,r25
out DDRB,r24 // Ausgänge aktivieren
ldi r22,16 // 8 Vollwellen
ldi r23,0b011000
ldi r25,0b010100 // [1] PB4:3 = HL
0: out PORTB,r25 // [1] Membran bewegen
eor r25,r23 // [1] dann HL
ldi r24,3 // [1]
1: dec r24
brne 1b // 3×[3]-[1] = [8]
dec r22
brne 0b // [3] beim Sprung, [2] beim Ende
// Wie im Oszillogramm des originalen SR04 zu sehen,
// den letzten Impuls doppelt lang machen.
ldi r24,4
1: dec r24
brne 1b // 4×[3]-[1] = [11]
ldi r25,0b000100 // PB5:0 = LLLhzL
ldi r24,0b111001
out PORTB,r25 // Clamp halten, Membran bedämpfen mit 1 kOhm
out DDRB,r24
ldi r24,50
1: dec r24 // Wandler ausschwingen lassen (braucht lange!)
brne 1b
ldi r24,0b011000 // PB5:0 = zLLhzz
out DDRB,r24 // Clamp lösen, C6 laden lassen
#ifdef DEBUG
rjmp 4b
#else
// Warten (= keine Meldemöglichkeit) solange PB2 L ist (von außen):
// Repetierender (Stör-)Ultraschall bei permanent Low (zum Testen)
ldi r25,hi8(3000)
ldi r24,lo8(3000) // ca. 20 ms (15 m Echodistanz)
0:
#ifdef ADCL
sbiw r24,1 // beeinflusst Z-Flag
#else
subi r24,1
sbci r25,1
#endif
sbi ACSR,4 // Möglichen Analogvergleicher-Interrupt löschen
sbis PINB,2
brne 0b // raus wenn Zähler Null
rjmp 3b // zur Hauptschleife
#endif
| Detected encoding: UTF-8 | 0
|