Forum: Mikrocontroller und Digitale Elektronik Ultraschallsensor HC-SR04 auswerten


von Robotico (Gast)


Lesenswert?

Hallo,

ich möchte mit dem AtMega8 den Ultraschallsensor HC-SR04 auswerten 
(http://kt-elektronic.de/wawi11/artikeldaten/sen-hr_sr4-e1/ultraschallmodul_beschreibung_3.pdf).
Dabei muss man laut Datenblatt mindestens 10µs lang einen H-Pegel auf 
den Trigger geben und dann wartet man bis der Echo Pin auf H-Pegel geht 
und zählt wie lange der H-Pegel bestehen bleibt. Dieser Wert ist dann 
proportional zum Abstand.


Mein Programm sieht folgendermaßen bisher aus:
1
#include <avr/io.h>
2
#include "lcd-routines.h"
3
#include <stdint.h>
4
#include <stdlib.h>
5
#include <util/delay.h>
6
#include <avr/interrupt.h>
7
#include <stdbool.h>
8
9
#define F_CPU 12000000;
10
11
12
volatile uint16_t zeitwert;
13
14
15
ISR (TIMER0_OVF_vect)
16
{
17
  zeitwert += 1;
18
}
19
20
21
int main(void)
22
{
23
  lcd_init();
24
  lcd_setcursor(0,1);
25
  lcd_string("Zeit:");
26
  
27
  DDRB = (1 << DDB2) | (0 << DDB1);
28
  
29
  bool flanke_pos;
30
  bool flanke_neg;
31
  flanke_pos = 0;
32
  flanke_neg = 0;
33
  
34
  zeitwert = 0;
35
  char Buffer[20];
36
  
37
  // 16-Bit-Timer
38
  //TCCR1B = (1<<CS11);            // CTC-Mode; Prescaler 8
39
  //TCCR1A = (0<<COM1A1) | (0<<COM1A0);    // OC1 wird nicht angesteuert
40
  //TCCR1A |= (0<<WGM11) | (0<<WGM10);    // Der Timer arbeitet als normaler Timer
41
  
42
  // 8-Bit-Timer
43
  TCCR0 = (1<<CS00);              // Timer aktivieren (kein Prescaler)
44
  TIMSK = (1<<TOIE0);              // Overflow-Interupt erlauben
45
  
46
  sei();                    // Interrupts global an
47
  
48
  
49
    while(1)
50
    {
51
        PORTB = (1 << PB2);
52
    _delay_us(15);
53
    PORTB = (0 << PB2);
54
    
55
    while ((PINB & 0x01) == 0) {}
56
    TCNT0 = 0;
57
                zeitwert = 0;
58
    while ((PINB & 0x01) == 1) {}
59
    
60
    itoa(zeitwert,Buffer,10);
61
    lcd_setcursor(6,1);
62
    lcd_string(Buffer);
63
    lcd_data('    ');
64
    }
65
}


Wollte das zuerst mit dem 16-Bit Timer machen, aber ich hab gedacht, den 
habe ich nicht zum laufen bekommen. Jedoch scheint mir mittlerweile das 
Problem am Sensor, bzw. an der Erkennung des Echo-Signals zu liegen.

Ich warte eben, bis der Echo auf H-Pegel ansteigt, setze dann den Timer 
zurück und warte bis das Echosignal wieder auf L-Pegel fällt. Und 
schreibe das dann auf das Display.
Er scheint aber gar nicht über die zwei Schleifen hinauszukommen, da auf 
dem Display bisher nur "Zeit:" steht.

von Robotico (Gast)


Lesenswert?

Hm okay, ich kanns mir glaub schon fast selber denken.

Die Eingangspins werden wahrscheinlich nur immer nach einem Zyklus neu 
abgefragt, oder?
Dann kann PB1 ja nie auf H-Pegel kommen, zumindest nicht im Programm.

Hat jemand einen besseren Lösungsvorschlag?

von Robotico (Gast)


Lesenswert?

Hat keiner einen Ansatz?


Hab es jetzt nochmal etwas anders probiert und zwar mit 
Flankenauswertung, bringt aber auch keine Verbesserung, das LCD zeigt 
wie vorher nur "Zeit:" an.

1
/*
2
 * Ultraschallsensor.c
3
 *
4
 * Created: 20.04.2014 14:36:27
5
 *  Author: Stefan
6
 */ 
7
8
#include <avr/io.h>
9
#include "lcd-routines.h"
10
#include <stdint.h>
11
#include <stdlib.h>
12
#include <util/delay.h>
13
#include <avr/interrupt.h>
14
#include <stdbool.h>
15
16
#define F_CPU 12000000;
17
18
19
volatile uint16_t zeitwert;
20
21
22
ISR (TIMER0_OVF_vect)
23
{
24
  zeitwert += 1;
25
}
26
27
28
int main(void)
29
{
30
  lcd_init();
31
  lcd_setcursor(0,1);
32
  lcd_string("Zeit:");
33
  
34
  DDRB = (1 << DDB2) | (0 << DDB1);
35
  
36
  bool flanke_pos;
37
  bool flanke_neg;
38
  flanke_pos = 0;
39
  flanke_neg = 0;
40
  
41
  zeitwert = 0;
42
  char Buffer[20];
43
  
44
  // 16-Bit-Timer
45
  //TCCR1B = (1<<CS11);            // CTC-Mode; Prescaler 8
46
  //TCCR1A = (0<<COM1A1) | (0<<COM1A0);    // OC1 wird nicht angesteuert
47
  //TCCR1A |= (0<<WGM11) | (0<<WGM10);    // Der Timer arbeitet als normaler Timer
48
  
49
  // 8-Bit-Timer
50
  TCCR0 = (1<<CS00);              // Timer aktivieren (kein Prescaler)
51
  TIMSK = (1<<TOIE0);              // Overflow-Interupt erlauben
52
  
53
  sei();                    // Interrupts global an
54
  
55
  
56
  PORTB = (1 << PB2);
57
  _delay_us(15);
58
  PORTB = (0 << PB2);
59
  
60
    while(1)
61
    {
62
    if((PINB & 0x01) == 1 && !flanke_pos)
63
      {
64
      TCNT0 = 0;
65
      zeitwert = 0;
66
      }
67
    flanke_pos = PINB & 0x01;
68
69
    if((PINB & 0x01) == 0 && flanke_neg)
70
      {
71
      itoa(zeitwert,Buffer,10);
72
      lcd_setcursor(6,1);
73
      lcd_string(Buffer);
74
      lcd_data('    ');
75
      
76
      PORTB = (1 << PB2);
77
      _delay_us(15);
78
      PORTB = (0 << PB2);
79
      }
80
    flanke_neg = PINB & 0x01;
81
    }
82
}

von Rainer V. (rudi994)


Lesenswert?

Bei Darisus GmbH gibt es ein engl.-sprach. Datenblatt im Menü 'Aktionen' 
oder 'Arduino\Boards' unter Artikel HC-SR04. Einiges steht da etwas 
anders drin, als unter o.g. Link. Z.B. soll die Laufzeit eines 
Messzyklus 50ms, besser 60ms betragen. Findet der Sensor kein Objekt, 
dann liegt am Echo-Pin ein 38ms langer High-Pegel an (sonst kürzer).

Dein Code ist für mich schwierig, da ich keine AVRs in C programmiere. 
Ich versuche es in Assembler. Das HC-SR04 werde ich mir für meinen 
ATmega8 mal besorgen. Wie ist die Hierachie bei der Auswertung der 
logischen Ausdrücke in den if-Anweisungen? Fehlen noch Klammern?

: Bearbeitet durch User
von Robotico (Gast)


Lesenswert?

Danke für den Einwand, hätte da gar nicht dran gedacht.
Weiß leider nicht genau wie die Priorisierung bei C ist, also habe ich 
es mal getestet:
1
...
2
if(((PINB & 0x01) == 1) && !flanke_pos)
3
...
4
5
if(((PINB & 0x01) == 0) && flanke_neg)
6
...

Leider bringt das auch keine Änderung.

Die Laufzeit des Messzyklus dürfte bei mir ja keine Rolle spielen, da er 
sowieso erst wieder eine Messung ausführt, wenn ein Messwert ermittelt 
wurde.


Hat denn sonst keiner einen Ansatz?

von Sebastian W. (wangnick)


Lesenswert?

Hallo Robotico,

1. Der Echo-Ausgang des HC-SR04 kann beim Senden des Trigger-Impulses 
u.U. immer noch auf H-Pegel sein. In diesem Fall dauert es von der 
H-L-Flanke auf dem Trigger-Eingang bis zum L-Pegel des Echo-Ausgangs so 
4.5us. Du solltest an dieser Stelle also ein kleine Verzögerung 
einbauen.

2. Wenn der HC-SR04 kein Ultraschallecho empfängt, so bleibt bei manchen 
Varianten des HC-SR04 der Echo-Ausgang einfach bis auf weiteres auf 
H-Pegel. Für diesen Fall (und für den Fall, dass Echo gar nicht auf 
H-Pegel geht) solltest du Timeouts vorsehen.

3. Zwei Messungen sollten einen Abstand von so 60ms nicht 
unterschreiten, damit die erste Schallwelle sicher verebbt ist und die 
zweite Messung nicht verfälscht.

LG, Sebastian

von Robotico (Gast)


Lesenswert?

Hallo Sebastian,

danke für deine Antwort!


1. Aber am Echo-Ausgang ist doch im normalen Zustand immer L-Pegel, nur 
zwischen Aussenden und Detektieren des Ultraschalls geht das Echo-Signal 
auf H-Pegel. Somit kann bei einer HL-Flanke am Trigger-Eingang ja 
eigentlich das Echo-Signal nicht auf H sein, oder?

2. Von Timeouts habe ich noch nichts gehört, da muss ich mich mal schlau 
machen. Danke!

3. Dadurch dass ich ja aber eine Messung erst nach Detektieren des 
Signals wieder starte, also bei HL-Flanke des Echos, sollte das ja 
eigentlich kein Problem machen, oder?

von Sebastian W. (wangnick)


Lesenswert?

Robotico schrieb:
> 1. Aber am Echo-Ausgang ist doch im normalen Zustand immer L-Pegel, nur
> zwischen Aussenden und Detektieren des Ultraschalls geht das Echo-Signal
> auf H-Pegel. Somit kann bei einer HL-Flanke am Trigger-Eingang ja
> eigentlich das Echo-Signal nicht auf H sein, oder?

Eigentlich ja, aber uneigentlich passiert es doch. Bei mir zumindest 
manchmal (ich messe jede Minute den Pegel im Öltank per HC-SR04).

> 2. Von Timeouts habe ich noch nichts gehört, da muss ich mich mal schlau
> machen. Danke!

Bitte nicht falsch verstehen. Du solltest einfach mögliche Fehlerfälle 
abfangen, bei denen an den pins gar nichts passiert, und nach einer 
gewissen Zeit abbrechen und neu anfangen.

Robotico schrieb:
> 3. Dadurch dass ich ja aber eine Messung erst nach Detektieren des
> Signals wieder starte, also bei HL-Flanke des Echos, sollte das ja
> eigentlich kein Problem machen, oder?

Nein, es macht ein Problem. Das Ultraschallecho kann ja von mehreren 
Zielen in verschiedenen Distanzen reflektiert werden, und dann sind beim 
Eintreffen des ersten Echos immer noch andere Echos auf dem Weg zurück 
zum HC-SR04. Diese würden dann nach dem Senden des nächsten Impulses 
empfangen und fälschlich als Reflektion dessen interpretiert werden.

LG, Sebastian

von Robotico (Gast)


Lesenswert?

Okay vielen Dank für deine Hilfe, dann versuche ich das mal umzusetzen.

Aber noch etwas:
Habe gerade zum ersten Mal wirklich den AVR Simulator getestet und 
irgendwie scheint der bei mir auch in das erste IF zu springen, wenn PB1 
gar nicht 1 ist, was ja eigentlich überhaupt nicht sein kann. Außerdem 
interpretiert der die IF-Verzweigung irgendwie als Schleife und macht 
das immer und immer wieder, alles was nach dem ersten IF steht wird 
weder ausgeführt noch geprüft. Das Problem wird bestimmt bei mir liegen, 
aber ist das Problem und die zugehörige Lösung bekannt?

von Peter (Gast)


Angehängte Dateien:

Lesenswert?

Moin....habe auch ein ähnliches Problem beim auswerten des Sensors!
Versuche mir den Abstand auf einem LCD anzeigen zu lassen...funktioniert 
aber nicht, da TCNT0 mir fast immer konstant das selbe raus gibt, obwohl 
ich den Abstand verändere. Der Wert ändert sich nur minimal.
Stimmt da vielleicht was in der Funktion nicht?

Da das Programm um einiges größer ist, hab ich nur den Teil für die 
Abstandsmessung ausgeschnitten...

von Karl H. (kbuchegg)


Lesenswert?

Peter schrieb:
> Moin....habe auch ein ähnliches Problem beim auswerten des Sensors!
> Versuche mir den Abstand auf einem LCD anzeigen zu lassen...funktioniert
> aber nicht, da TCNT0 mir fast immer konstant das selbe raus gibt, obwohl
> ich den Abstand verändere. Der Wert ändert sich nur minimal.
> Stimmt da vielleicht was in der Funktion nicht?

Das Datenblatt spricht von einem 10 Mykro-Sekunden langen Trigger Puls. 
Nicht Millisekunden.

> Da das Programm um einiges größer ist, hab ich nur den Teil für die
> Abstandsmessung ausgeschnitten...

Ganz starke Idee, den Ausschnitt als Bild anzuhängen. Da kann man sich 
so wunderbar auf Codestellen beziehen.

von Karl H. (kbuchegg)


Lesenswert?

Karl Heinz schrieb:
> Peter schrieb:
>> Moin....habe auch ein ähnliches Problem beim auswerten des Sensors!
>> Versuche mir den Abstand auf einem LCD anzeigen zu lassen...funktioniert
>> aber nicht, da TCNT0 mir fast immer konstant das selbe raus gibt, obwohl
>> ich den Abstand verändere. Der Wert ändert sich nur minimal.
>> Stimmt da vielleicht was in der Funktion nicht?
>
> Das Datenblatt spricht von einem 10 Mykro-Sekunden langen Trigger Puls.
> Nicht Millisekunden.

Und auch den Teil beachten
1
You can calculate the range through the time interval between
2
sending trigger signal and receiving echo signal.

d.h. was dich interessiert ist die Zeit die vergeht, gemessen von deinem 
Puls, bis du am Empfänger das Echo siehst. Die Länge des Echo-Pulses 
hingegen ist NICHT die gewünschte Information.

von Peter (Gast)


Angehängte Dateien:

Lesenswert?

hier der komplette Code.

von Peter (Gast)


Lesenswert?

Mit der Formel (TCNT0*ps*ss*100)/(F_CPU*2); wollte ich mir den Abstand 
in cm ausgeben lassen.

von Karl H. (kbuchegg)


Lesenswert?

Peter schrieb:
> Mit der Formel (TCNT0*ps*ss*100)/(F_CPU*2); wollte ich mir den Abstand
> in cm ausgeben lassen.


Das ändert aber immer noch nichts daran, dass nicht die LÄnge des 
Echopulses die Entfernungsinformation enthält, sondern die Zeit die 
vergeht, von der Auslösung des US-Pulses bis das Echo eintrifft!

Also
* _delay_us(10) anstatt _delay_ms(10)
* die Zeit beginnt zu laufen nachdem du den Puls rausgeblasen hast und 
endet damit, dass der Eingangspin von 0 auf 1 wechselt. WIe lange der 
Pin dann auf 1 bleibt interessiert keinen.

Es kann höchstens jetzt noch sein, dass du nach dem Aussenden des Pulses 
eine kleine Zeit warten musst, bis du den Eingang das erst mal abfrägst, 
weil der Empfänger ja logischerweise nicht nur das Echo empfängt, 
sondern ganz schwach auch auf den eigentlichen Sendepuls regieren 
könnte, Inwiefern der Hersteller da vorgesorgt hat, weiss ich aber 
nicht. Im Datenblatt ist dazu nichts erwähnt.

von Peter (Gast)


Lesenswert?

Die Zeit hab ich umgestellt.
Naja ich möchte den Abstand raus bekommen. Daher muss ich ja die Zeit 
des Echo-Impulses messen. Denn umso größer der Abstand desto länger ist 
Echo auf eins oder?

von Karl H. (kbuchegg)


Lesenswert?

Karl Heinz schrieb:

> * die Zeit beginnt zu laufen nachdem du den Puls rausgeblasen hast und
> endet damit, dass der Eingangspin von 0 auf 1 wechselt. WIe lange der
> Pin dann auf 1 bleibt interessiert keinen.

Den nehme ich zurück.
Da scheinen mehrere Beschreibungen im Umlauf zu sein und ich bin da 
einer Zweit-Quelle aufgesessen.

In einer anderen Beschreibung
https://docs.google.com/document/d/1Y-yZnNhMYy7rwhAgyL_pfa39RsB-x2qR4vP8saG73rE/edit
ist es so beschrieben, wie du es implementiert hast. Die Pulslänge ist 
proportional der Distanz.

Hier
http://www.micropik.com/PDF/HCSR04.pdf
ist es anders rum beschrieben: Die zeitliche LÄnge vom Puls bis zum 
Einsetzen des Echos ist die Distanz.

: Bearbeitet durch User
von Peter (Gast)


Lesenswert?

Aber Danke für die schnelle Antwort, ich werde es gleich mal 
ausprobieren.

von Karl H. (kbuchegg)


Lesenswert?

Geh mal mit den Millisekunden runter auf µs.
Leider gibt es keine eindeutige Aussage darüber, ob die steigende oder 
die fallende Flanke zählt.

: Bearbeitet durch User
von W.A. (Gast)


Lesenswert?

Peter schrieb:
> Aber Danke für die schnelle Antwort, ich werde es gleich mal
> ausprobieren.

Wie wäre es, wenn du statt rumzuprobieren mal zu einem Oszi, DSO, LA 
oder was es sonst noch für angemessene Werkzeuge gibt, greifst, um 
überhaupt erstmal zu klären, was der Sensor so von sich gibt?

von Karl H. (kbuchegg)


Lesenswert?

Apropos.
In welchem Bereich bewegen sich denn die ermittelten Werte?

von Peter (Gast)


Lesenswert?

Funktioniert jetzt!
Teiler war falsch eingestellt....von 1024 auf 64.

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.