Ultraschallsensor HC-SR04 auswerten

Gast #3626547
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.
Gast #3626548
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?
Gast #3626831
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
}
#3627171
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?
Gast #3628151
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?
#3628290
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
Gast #3628360
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?
#3628381
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
Gast #3628389
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?
Gast #3917291
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...
Angehängte Dateien:
#3917298
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.
#3917303
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.
#3917332
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.
#3917345
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.
Gast #3917369
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?

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren