Forum: Compiler & IDEs SRF05-Ultraschall Distanzmessung, Fehler bei Hard oder Software


von Andy S. (andy11)


Lesenswert?

Ich habe gestern einen SRF05 im Labor gefunden, er war ausgepackt in 
einer Kiste. Habe ihn jetzt in Betrieb genommen und komme drauf, dass 
die Distanz zum Objekt immer 0 ist.
Es kann leicht sein, dass der SRF05 nicht funktioniert, ich weiß aber 
nicht wie ich das überprüfen kann.

Mein C Programm arbeitet so, dass ich jeden Schleifendurchlauf eine neue 
Messung mache und nach einer Messung die Messung im nächsten 
Schleifendurchlauf ausgewertet wird und anschließend 250ms lang 
angezeigt wird, damit sich die 5 m ausgehen.
1
/** Distanz zum Obekt wird so ermittelt: s = (v*t)/2 = 346m/s (für Schall) * t(Die Zeit die gezählt wird) /2(Für hin und zurück)
2
 * Umgerechnet s = 173um/us * x*us
3
 */
4
5
#include <stdlib.h>
6
#include <avr/io.h>
7
#include <avr/interrupt.h>
8
#include <avr/pgmspace.h>
9
#include <util/delay.h>
10
#include <stdio.h>
11
#include <inttypes.h>
12
#include <stdbool.h>
13
14
#define UART_BAUD_RATE 9600  //UART Baudrate
15
#define BufferMAX 10
16
#define GetDistanceToObject_um(time_uSeconds) (173*(time_uSeconds))
17
18
//Headerfiles+Subroutines---------------------------------------------
19
#include "uart.h"
20
#include "lcd-routines.h"
21
//--------------------------------------------------------------------
22
23
//Global deklarierte Variablen----------------------------------------
24
char buffer[BufferMAX] = { 0 };
25
unsigned int i = 0; //Zählervariable
26
27
28
volatile unsigned int Distanz = 0, zaehler = 0;
29
int main(void)
30
{
31
  //lcd-init
32
  lcd_init();
33
  lcd_clear();
34
35
  //uart-init:
36
  uart_init(UART_BAUD_SELECT(UART_BAUD_RATE, F_CPU));
37
38
  //Timer/Counter2 Konfiguration:
39
  TCCR2 &=~ ((1<<WGM20) | (1<<WGM21)); //Normaler Modus
40
  TCCR2 |= (1<<CS21); //Prescaler = 8
41
  TIMSK &=~ (1<<TOIE2); //Interrupt disable --> Overflow
42
43
  //INT1 - External Interrupt Konfiguration:
44
  MCUCR |= (1<<ISC10); //Pinchange --> Jump to ISR
45
  GICR |= (1<<INT1); //INT1 enable
46
47
  //Ein-Ausgänge
48
  DDRD |= (1<<DDD6);   //PORTD.2 = output, für Ultraschallsensor TRIGGER Impuls
49
  DDRD &=~ (1<<DDD3);  //PORTD.3 = input, für US-S ECHO Impuls
50
  PORTD |= (1<<PD3); //Pullup aktivieren
51
52
  //Interrupt enable
53
  sei();
54
55
  //Main-Loop:*********************************************************************
56
  while(1)
57
  {
58
    lcd_setcursor(0,2);
59
60
    lcd_home();
61
    Distanz /= 10000; //Distanz in cm
62
    itoa(Distanz, buffer, 10);
63
    lcd_string("Distanz:"); lcd_string(buffer);
64
    //uart_puts(buffer); uart_puts("\n");
65
    _delay_ms(250);
66
67
    //Starte Messung:
68
    PORTA |= (1<<PD6); //Starte Messung
69
    _delay_us(10);
70
    PORTA &= (1<<PD6);
71
  }
72
  //back***************************************************************************
73
  return 0;
74
}
75
76
ISR(TIMER2_OVF_vect)
77
{
78
  zaehler += 255;
79
}
80
81
ISR(INT1_vect)
82
{
83
  if(zaehler == 0)
84
    TIMSK |= (1<<TOIE2); // Fange an zu zählen
85
86
  else //Ansosnten wenn schon gemessen und Messung beendet, dann schluss!
87
  {
88
    Distanz = GetDistanceToObject_um(zaehler);
89
    zaehler = 0;
90
    TIMSK &=~ (1<<TOIE2);
91
  }
92
}

Ich hoffe der Code selber ist selbsterklärend.

Takt: 8MHz.
--> Timer2 läuft alle 255us über.

lg andy

von STK500-Besitzer (Gast)


Lesenswert?

>anschließend 250ms lang angezeigt wird,
und wer soll das ablesen?
Aliens? Menschen sind dafür zu träge.

Für sowas benutzt man die InputCaptureUnit.

>Es kann leicht sein, dass der SRF05 nicht funktioniert, ich weiß aber
>nicht wie ich das überprüfen kann.
Oszilloskop?
Denjenigen fragen, dem das Ding gehört?

von Andy S. (andy11)


Lesenswert?

STK500-Besitzer schrieb:
> und wer soll das ablesen?
> Aliens? Menschen sind dafür zu träge.

Es wird ja immer wieder neu gemessen.

STK500-Besitzer schrieb:
> Oszilloskop?

Hier habe ich keines zur verfügung, leider, da müsste ich bis dienstag 
warten.

STK500-Besitzer schrieb:
> Denjenigen fragen, dem das Ding gehört?

Sol das ein Scherz sein?

Es ist aber auch eine SMD LED drauf, leider leuchtet die nicht.
Dh an der Software kann es einmal nicht liegen, weil mein Code stimmt 
oder irre ich mich da?

lg andy

von Andy S. (andy11)


Lesenswert?

STK500-Besitzer schrieb:
> Für sowas benutzt man die InputCaptureUnit.

Würde es sowie ich es jetzt habe nicht funktionieren?
Wenn ja warum?

lg andy

von Karl H. (kbuchegg)


Lesenswert?

Andy S. schrieb:
> STK500-Besitzer schrieb:
>> Für sowas benutzt man die InputCaptureUnit.
>
> Würde es sowie ich es jetzt habe nicht funktionieren?
> Wenn ja warum?

Punkt 1
Du hast keinerlei Synchronisierung zwischen dem Senden des Pulses und 
dem Starten des Zählers

Punkt 2
Was du da mit deinem INT1 machst, ist mir ehrlich gesagt rätselhaft.

Punkt 3
zaehler erhöht sich bei dir immer nur um 255

Punkt 4
Du hast keine Taktfrequenz angegeben. Daher kann man nicht nachrechnen, 
was du dir bei deinen magischen Konstanten wohl gedacht hast.

Punkt 5
Port A wird nicht von Eingang auf Ausgang umgeschaltet

Punkt 6
Distanz /= 10000;
Da wird nicht viel übrigbleiben, selbst wenn zähler tatsächlich 
hochgezählt hat

Punkt 7
Die komplette Steuerung kommt mir .... kompliziert vor
In einem ersten Versuch würde ich:
Zähler auf 0; Port auf Ausgang; Startpuls senden; Port auf Eingang; 
Eingang pollen bis Echo da ist; Zähler stoppen; Gesamtzählerstand (inkl 
Overflows) ausrechnen; den mal ausgeben; umrechnen in Zeit; ausgebe; 
umrechnen in Distanz; ausgeben

Je weniger du beim ersten Versuch künstelst, desto weniger Fehlerquellen 
hast du. Persönlich bevorzuge ich bei der ersten Inbetriebnahme ein 
Vorgehen welches so naheliegend und simpel wie nur möglich ist. Je 
weniger Fehlerquellen ich mir selbst einbaue, desto mehr kann ich mich 
auf die unbkannte Komponente konzentrieren.

von Andy S. (andy11)


Lesenswert?

Karl heinz Buchegger schrieb:
> Du hast keinerlei Synchronisierung zwischen dem Senden des Pulses und
> dem Starten des Zählers

Oja, :
1
ISR(INT1_vect)
2
{
3
  if(zaehler == 0)
4
    TIMSK |= (1<<TOIE2); // Fange an zu zählen
5
.
6
.
7
.

Karl heinz Buchegger schrieb:
> Was du da mit deinem INT1 machst, ist mir ehrlich gesagt rätselhaft.

Die Idee ist die: Damit nicht immer gewartet werden muss bis die Messung 
fertig ist, habe ich folgendes System überlegt:
zwischendurch im Hauptprogramm sendet er einen Startimpuls (TRIGGER). 
Nach einer Zeit kommt der Antwort-lange Impuls zurück auf den 
Interrupt1. Zwischendurch hat er gezählt, und wenn die Antwort kommt 
stoppt er im INT1
-->
1
else //Ansosnten wenn schon gemessen und Messung beendet, dann schluss!
2
  {
3
    Distanz = GetDistanceToObject_um(zaehler);
4
    zaehler = 0;
5
    TIMSK &=~ (1<<TOIE2);
6
  }
7
}

Karl heinz Buchegger schrieb:
> zaehler erhöht sich bei dir immer nur um 255

Nein, nur wenn gestartet wird, bis beendet wird. -->
1
else //Ansosnten wenn schon gemessen und Messung beendet, dann schluss!
2
  {
3
    .
4
                .
5
    TIMSK &=~ (1<<TOIE2);
6
  }
7
}

Karl heinz Buchegger schrieb:
> Du hast keine Taktfrequenz angegeben. Daher kann man nicht nachrechnen,
> was du dir bei deinen magischen Konstanten wohl gedacht hast.

Sry, mein Fehler, 8MHz intern.
also 1/(8MHz/8(Prescaler vom TImer)) * 255(da 8 Bit TImer) = 255

Karl heinz Buchegger schrieb:
> Port A wird nicht von Eingang auf Ausgang umgeschaltet

der SFR05 hat auch 2 Betriebsmodi.

Karl heinz Buchegger schrieb:
> Punkt 6
> Distanz /= 10000;
> Da wird nicht viel übrigbleiben, selbst wenn zähler tatsächlich
> hochgezählt hat

/** Distanz zum Obekt wird so ermittelt: s = (v*t)/2 = 346m/s (für 
Schall) * t(Die Zeit die gezählt wird) /2(Für hin und zurück)
 * Umgerechnet s = 173um/us * x*us
 */
... Erste Zeile

Karl heinz Buchegger schrieb:
> In einem ersten Versuch würde ich:
> Zähler auf 0; Port auf Ausgang; Startpuls senden; Port auf Eingang;
> Eingang pollen bis Echo da ist; Zähler stoppen; Gesamtzählerstand (inkl
> Overflows) ausrechnen; den mal ausgeben; umrechnen in Zeit; ausgebe;
> umrechnen in Distanz; ausgeben

Ja, klingt vielleicht einbischen logischer, hast schon recht. Müsst aber 
überlegen ob mich das nicht irgendwelche unnötige Zeit kostet.


lg andy

von Karl H. (kbuchegg)


Lesenswert?

Andy S. schrieb:
> Karl heinz Buchegger schrieb:
>> Du hast keinerlei Synchronisierung zwischen dem Senden des Pulses und
>> dem Starten des Zählers
>
> Oja, :

AHa.
Und wenn ich mir das Datenblatt zum Sensor ansehe, dann sehe ich, dass 
da als Antwort auf einen Sendepuls ein paar Empfangspulse daher kommen. 
Wie das dann bei einem Echo ist, wage ich gar nicht anzudenken.

Mit jedem Puls wird bei dir ein Interrupt ausgelöst. In welchem Zustand 
daher 'zähler' ist wenn du in der Hauptschleife den Sendepuls auslöst, 
wage ich mir ehrlich gesagt gar nicht vorzustellen.

Ich finde es nicht besonders schlau, 2 Mechanismen (Hauptschleife und 
die Steuerung in der ISR) nebeneinander herlaufen zu lassen und auf Gott 
zu vertrauen, dass das immer alles synchron bleiben wird.

>> zaehler erhöht sich bei dir immer nur um 255
>
> Nein, nur wenn gestartet wird, bis beendet wird. -->

So?
Wo wird denn zähler noch erhöht? Die einzige Erhöhung die ich sehe ist 
im Overflow Interrupt. Und dort um 255 (wieso eigentlich 255. 256 wäre 
irgendwie logischer)


>> Punkt 6
>> Distanz /= 10000;
>> Da wird nicht viel übrigbleiben, selbst wenn zähler tatsächlich
>> hochgezählt hat
>
> /** Distanz zum Obekt wird so ermittelt: s = (v*t)/2 = 346m/s (für
> Schall) * t(Die Zeit die gezählt wird) /2(Für hin und zurück)
>  * Umgerechnet s = 173um/us * x*us
>  */
> ... Erste Zeile

Das mag alles sein.
Aber ein uint16_t kann maximal 65535 gross werden. Durch 10000 macht 
dann 6.
Das ist dein maximales Ergebnis. ANdere Eregbnisse als 0, 1, 2, 3, 4, 5, 
6 kannst du nicht erhalten.

von Andy S. (andy11)


Lesenswert?

Karl heinz Buchegger schrieb:
> AHa.
> Und wenn ich mir das Datenblatt zum Sensor ansehe, dann sehe ich, dass
> da als Antwort auf einen Sendepuls ein paar Empfangspulse daher kommen.
> Wie das dann bei einem Echo ist, wage ich gar nicht anzudenken.
>
> Mit jedem Puls wird bei dir ein Interrupt ausgelöst. In welchem Zustand
> daher 'zähler' ist wenn du in der Hauptschleife den Sendepuls auslöst,
> wage ich mir ehrlich gesagt gar nicht vorzustellen.

Nein, da hast du einen kleinen Denkfehler, die ganzen Impulse stellen 
nur dar, dass der US gerade seine Messung durchführt. Alles was auf der 
Echoleitung dann vorbeikommt ist ein langer/kurzer/mittlerer Impuls der 
dann mit seiner Länge die Zeit bestimmt.

Karl heinz Buchegger schrieb:
> Das mag alles sein.
> Aber ein uint16_t kann maximal 65535 gross werden. Durch 10000 macht
> dann 6.
> Das ist dein maximales Ergebnis

Das habe ich wohl nicht bedacht, da hast du recht. Dann mache ich halt 
ein Uint32 draus.

lg andy

von Karl H. (kbuchegg)


Lesenswert?

Andy S. schrieb:


> Ja, klingt vielleicht einbischen logischer, hast schon recht. Müsst aber
> überlegen ob mich das nicht irgendwelche unnötige Zeit kostet.


Premature optimization is the root of all evil

Du hast eine Hardware von der du nicht weißt ob sie funktioniert.
Und du machst dir Sorgen darum, ob dein erstes Testprogramm 'unnötige 
Zeit verplempert?'

Jetzt geht es darum, das Ding in Betrieb zu nehmen!
Nicht darum, optimale Software zu schreiben. Wenn du das Teil in Betrieb 
hast und erste Messergebnisse hast und ein wenig gelernt hast, was da 
alles am Input passieren kann .... dann ist es Zeit sich über eine für 
die Aufgabenstellung bessere Softwarearchitektur Gedanken zu machen.
Aber jetzt lautet das Ziel: funktioniert das Teil überhaupt? Kriege ich 
Messwerte? Welche Zeiten bekomme ich?
Und nicht: wo kann ich 20 Nanosekunden einsparen.

von Andy S. (andy11)


Lesenswert?

Karl heinz Buchegger schrieb:
> Du hast eine Hardware von der du nicht weißt ob sie funktioniert.
> Und du machst dir Sorgen darum, ob dein erstes Testprogramm 'unnötige
> Zeit verplempert?'

Nein das mache ich mir nicht, ich wollte lediglich wissen ob es mit dem 
Prinzip funktionieren kann, was nebenbei auch zu meiner weiteren 
Fragestellung gehört.

Ok, dann werde ich bis morgen warten, also an der Software wird es 
vermutlich nicht liegen habe ich recht?

lg andy

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.