Forum: Mikrocontroller und Digitale Elektronik Ultraschallentfernungsmesser in AVR GCC


von Fabian H. (heisenberg_px)


Lesenswert?

Hallo Leute,

ich habe eine Frage bezüglich den Timern des ATmega 328p (16MHz).

Wie kann man die Zeit zwischen einer steigenden Flanke und einer 
fallenden Flanke messen. Die gemessene Zeit wird zwischen 8us und 5ms zu 
erwarten sein.

Meine Anwendung besteht darin, dass ich die HIGH-Zeit des ECHO Pins am 
Ultraschallentfernungsmessers HCSR04 messen will.

Ich habe es schon geschafft einen Timer zu programmieren der jede 
Microsekunde einen Interrupt auslöst.
1
float T = 0.0000001; // Periodendauer 1µs
2
3
uint16_t overflow = F_CPU/(T*2*256)-1; //Berechnung des Timeroverflows für eine 1µs
4
5
TCCR1B |= (1<<CS12) | (1<<WGM12);  //Prescaler 256 und CTC-Mode
6
TIMSK1 |= (1<<OCIE1A);  //Interrupt nach übersteigen des Werts im OCR1A Registers
7
OCR1A = overflow;

Leider weiß ich jetzt nicht mehr weiter, wie ich den Interrupt der durch 
den ECHO-Pin ausgelöst mit dem Timer-Interrupt verbinde, damit ich die 
Zeit auswerten kann.

Vielen Dank für die Unterstützung.

MFG Fabian

von Carl D. (jcw2)


Lesenswert?

Das Zauberwort ist "Input Capture".

Timer1 durchlaufen lassen, Flanke "capture"n, im CaptureInt den PINB0 
lesen und daraus Richtung erkennen. Auf der ersten Flanke ICR1 merken, 
auf der zweiten die Differenz ICR1 zu ICR_alt bilden. Bei 16MHz und 
Prescaler 8 ergibt das 1/2μs Auflösung und bis zu 32ms max. ermittelbare 
Pulslänge.

BTW, Int alle 1μs bedeutet 16Takte max. und dann macht der 328er sonst 
nichts mehr. Mit Prescaler 256 zählt der Timer aber nicht mal so 
schnell, wie er unterbrechen soll.

von ... (Gast)


Lesenswert?

Schau dir im Datenblatt das AVR das Kapitel "Input Capture" an.

von Wolfgang (Gast)


Lesenswert?

Fabian H. schrieb:
> Ich habe es schon geschafft einen Timer zu programmieren der jede
> Microsekunde einen Interrupt auslöst.

Bist du sicher?
Da bleibt nicht viel Zeit, für ernsthafte Dinge. Guck dir mal die Anzahl 
der zwischen den Interrupts verbleibenden Taktzyklen an ;-)

Float in Zusammenhang von einer diskreten Anzahl von Taktzyklen ist 
auch nicht das richtige Konzept. Alles was abzählbar ist, basiert auf 
grundsätzlich auf dem Datentyp int

von Fabian H. (heisenberg_px)


Lesenswert?

Wolfgang schrieb:
> Bist du sicher?

Danke Wolfgang für deine Antwort!

Ich hab den Timer zwar nicht mit einem Oszi überprüft aber wenn ich ihn 
so verändere, dass er jede Sekunde einen Interrupt auslöst und damit die 
onboard LED toggeln lasse, dann sieht das eigentlich ziemlich brauchbar 
aus.

Meinst Du, dass das Konzept des Timers für meine Anwendung unbrauchbar 
ist?

... schrieb:
> Schau dir im Datenblatt das AVR das Kapitel "Input Capture" an.

Danke! Werd ich machen.

von Rudolph R. (rudolph)


Lesenswert?

Fabian H. schrieb:
> Die gemessene Zeit wird zwischen 8us und 5ms zu
> erwarten sein.

Sicher?
Im Datenblatt vom Sensor findet man eine Tabelle mit Laufzeiten,
für 2cm sind das 117µs bei 20°C.

Mit 343,5 m/s komme ich bei 8µs auf 1,374 mm (Hin- und Rückweg).
Das ist gar nicht messbar mit dem Sensor.

von Mark S. (voltwide)


Lesenswert?

Bei vergleichbaren Experimenten an den üblichen 40khz Piezo-Wandlern 
zeigte sich ein deutliches "Klingeln" beim Ein- und Ausschalten, sowohl 
auf der Sender- als auch auf der Empfängerseite. Damit ist die 
Zeitauflösung schon mal begrenzt auf mehrere 40kHz-Schwingungen - also 
eher in der Größenordnung von 100us.

Angesichts dieser "langsamen" Sensoren bringt es nichts, im 1usec-Takt 
etwas ein zu lesen.

: Bearbeitet durch User
von Wolfgang (Gast)


Lesenswert?

Fabian H. schrieb:
> Ich hab den Timer zwar nicht mit einem Oszi überprüft aber wenn ich ihn
> so verändere, dass er jede Sekunde einen Interrupt auslöst und damit die
> onboard LED toggeln lasse, dann sieht das eigentlich ziemlich brauchbar
> aus.

Der Timer ist nicht das Problem, aber jede μs ein Interrupt wird dem μC 
etwas zu hektisch sein. Lass ihn mal in der ISR einen Pin tooglen und 
guck dir das mit dem Oszi an.

von Chrys (Gast)


Lesenswert?

Mark S. schrieb:
> Bei vergleichbaren Experimenten an den üblichen 40khz Piezo-Wandlern
> zeigte sich ein deutliches "Klingeln" beim Ein- und Ausschalten, sowohl
> auf der Sender- als auch auf der Empfängerseite. Damit ist die
> Zeitauflösung schon mal begrenzt auf mehrere 40kHz-Schwingungen - also
> eher in der Größenordnung von 100us.
>
> Angesichts dieser "langsamen" Sensoren bringt es nichts, im 1usec-Takt
> etwas ein zu lesen.

Hmm, soweit ich mich erinnern mag, ändert der Output des Sensors seinen 
Zustand beim Aussenden des Pulses und resetet den Output wieder beim 
Eintreffen der ersten, erkannten Flanke. Jetzt kann es sein, dass nicht 
die erste Flanke erkannt wird und dann liegt man gleich eine halbe 
(4.28mm) oder ganze Wellenlänge (8.58mm) daneben. Aber ansonsten ist der 
Sensor überhaupt nicht "langsam" bzw. eine hochauflösende Zeitmessung 
bringt durchaus Genauigkeit. Dazu gehört dann aber auch mindestens eine 
Temperaturmessung, würde ich behaupten :)

Gruss Chrys

von Eric B. (beric)


Lesenswert?

Fabian H. schrieb:
> float T = 0.0000001; // Periodendauer 1µs

Das sieht eher nach 0,1µs aus....

von Mark S. (voltwide)


Lesenswert?

Chrys schrieb:
> Aber ansonsten ist der
> Sensor überhaupt nicht "langsam" bzw. eine hochauflösende Zeitmessung
> bringt durchaus Genauigkeit. Dazu gehört dann aber auch mindestens eine
> Temperaturmessung, würde ich behaupten :)

Der Sensor ist ein Piezo Kristall mit einer Resonanzfrequenz von 40khz 
und einem deutlichen Ein- und Ausschwingverhalten von mehreren Perioden.
Und das sind nicht nur Mutmaßungen, sondern so etwas habe ich mal aus 
gemessen.
Das  bezeichne ich hier als langsam.

: Bearbeitet durch User
von Chrys (Gast)


Lesenswert?

Mark S. schrieb:
> Der Sensor ist ein Piezo Kristall mit einer Resonanzfrequenz von 40khz
> und einem deutliche Ein- und Ausschwingverhalten von mehreren Perioden.
> Das  bezeichne ich hier als langsam.


Mark S. schrieb:
> Angesichts dieser "langsamen" Sensoren bringt es nichts, im 1usec-Takt
> etwas ein zu lesen.

Ich verstehe nach wie vor nicht, was du mit langsam meinst und wieso man 
nicht im usec Bereich versuchen sollte die "Lauf"-Zeit zu messen?
So lange der "Burst" von der Schaltung immer in etwa gleich erkannt 
wird, kann man den Sensor kalibrieren und das Einschwingverhalten wird 
korrigiert. Wenn du mit langsam meinst, dass man nach einer Messung kurz 
warten sollte bis die reflektierten Wellen genügend gedämpft wurden um 
eine neue Messung zu starten, dann hast du evtl. recht, was auch immer 
langsam dann heissen mag...

von Wolfgang (Gast)


Lesenswert?

Chrys schrieb:
> Jetzt kann es sein, dass nicht die erste Flanke erkannt wird und
> dann liegt man gleich eine halbe (4.28mm) oder ganze Wellenlänge
> (8.58mm) daneben.

Diese Differenz würde man dann wohl als Messunsicherheit ansprechen. Bei 
einer US-Frequenz von 40kHz geht es hierbei um 25μs. Die ganze 
Diskussion um einzelne μs bei der Auflösung für die Zeitmessung ist 
damit "akademisch".

von Chrys (Gast)


Lesenswert?

Wolfgang schrieb:
>> Jetzt kann es sein, dass nicht die erste Flanke erkannt wird und
>> dann liegt man gleich eine halbe (4.28mm) oder ganze Wellenlänge
>> (8.58mm) daneben.
>
> Diese Differenz würde man dann wohl als Messunsicherheit ansprechen. Bei
> einer US-Frequenz von 40kHz geht es hierbei um 25μs. Die ganze
> Diskussion um einzelne μs bei der Auflösung für die Zeitmessung ist
> damit "akademisch".

Nein überhaupt nicht, es kommt darauf an wie schnell sich die Distanz 
ändert. Wenn du mit 10Hz etwas misst, was sich langsam bewegt z.b. 
1mm/s, kannst du auf Grund dieses Wissens korrigieren bzw. auf 
plausibilität Prüfen...

von Chrys (Gast)


Lesenswert?

Und wenn du eine "schnellere" Messung machen möchtest, weil sich etwas 
schneller ändert, dann brauchst du einfach etwas mehr Rechenpower :)

https://www.youtube.com/watch?v=Al1azJePN4A

von Chrys (Gast)


Lesenswert?

Fabian H. schrieb:
> Meine Anwendung besteht darin, dass ich die HIGH-Zeit des ECHO Pins am
> Ultraschallentfernungsmessers HCSR04 messen will.

Ich würde es ungefähr so probieren, habe es für einen atmega64 gemacht:

Timer1 im normal mode mit overflow interrupt enable und den echo input 
an einen I/O mit externem interrupt z.b. INT4
1
TCCR1B |= ((1<<CS11)); //16 bit counter in normal mode with prescaler = 8 --> 2MHz --> 0.5us
2
TIMSK |= (1<<TOIE1); //timer overflow interrupt enabled
3
4
//Interrupt INT4 (US1)
5
EICRB |= (1<<ISC40); //logic change
6
EIMSK |= (1<<INT4); //enable interrupt

Dann die dazugehörigen ISRs
1
ISR(TIMER1_OVF_vect)
2
{
3
  static uint8_t kk = 3;
4
  kk--;
5
  if(kk == 0)
6
  {
7
    send_results = 1;
8
    kk = 3; //nur bei jedem 3. mal einen Messung auslösen
9
    tof_1_old = tof_1; //letzte Messung sichern
10
    tof_1 = 0;
11
    portUS1_trig |= (1<<US1_trig); //set trigger high
12
  }
13
}
14
15
ISR(INT4_vect)
16
{
17
  //detect logical change
18
  //save TCNT1 counter value as "time of flight"
19
  tof_1 = TCNT1-tof_1;
20
}

und dann in deiner while(1) irgend so etwas...
1
if(send_results == 1)
2
{
3
4
  utoa(tof_1_old, buffer, 10);   // convert integer into string (decimal format)   
5
  uart_puts(buffer);        // and transmit string to UART
6
  uart_putc('\n');
7
  send_results = 0;
8
  portUS1_trig &= ~(1<<US1_trig); //set trigger low
9
}

Gute Nacht
Chrys

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.