Hallo,
nach Monaten mitlesen, muss ich jetzt doch tatsächlich mal selbst eine
Frage stellen, weil ich nicht weiter komme.
Wie im Betreff schon erwähnt, geht es um das HC SR04.
Das Problem ist, dass ich bei 10cm Abstand auch 10cm angezeigt bekomme.
Ich habe mich an dem Datenblatt
http://kt-elektronic.de/wawi11/artikeldaten/sen-hr_sr4-e1/ultraschallmodul_beschreibung_3.pdf
entlang gehangelt,
Aber bei 20cm Abstand zeigt mein Display 25 cm an.
bei 30 sind es 45
bei 40 sind es 63
bei 50 sind es 83
vom Tisch zur Decke sind es 140 cm angezeigt werden 260 cm
Echo ist an PA0 als Interrupt Eingang
Trigger ist an PC0 angeschlossen.
Ich nutze einen Atmega 1284P und das AtmelStudio 6
Ich bin mir etwas unsicher mit den Umrechnungen aber ich denke, dass da
das Problem liegt allerdings erkenne ich es nicht.
Der Code schaut folgendermassen aus:
1
#define F_CPU 16000000
2
#include<avr/io.h>
3
#include<util/delay.h>
4
#include<stdlib.h>
5
#include<avr/interrupt.h>
6
#include"lcd-routines.h"
7
8
charlcd[4];
9
uint8_tcon=0;
10
11
inta1;
12
inta2;
13
inta3;
14
15
intmain(void)
16
{
17
DDRC=0b00011101;
18
PORTC=0b10000011;
19
20
PCMSK0|=(1<<PCINT0);//Interrupt control
21
PCICR|=(1<<PCIE0);//Interrupt control
22
sei();
23
24
TCNT1=0;
25
26
lcd_init();
27
28
while(1)
29
{
30
_delay_ms(100);
31
PORTC&=~(1<<PC0);//
32
_delay_us(15);// -> Löst die Messung des HCSR04 aus.
33
PORTC|=(1<<PC0);//
34
35
36
//Jetzt löst der Interrupt aus, weil das Modul den Echo auf high setzt.
37
38
39
if(con>1)// Da der Interrupt 2 mal ausgelöst wird bis
40
// die Messung beendet ist, nutze ich den Zähler um
41
// nur jedes 2te Mal umzurechnen und auszugeben.
42
43
{
44
a1=(TCNT1/0.0625);//Umrechnung auf µs
45
a2=((0.0341*a1)/2);// Umrechnung auf cm
46
47
itoa(a2,lcd,10);
48
49
lcd_setcursor(0,0);
50
lcd_string(" ");
51
lcd_setcursor(0,0);
52
lcd_string(lcd);
53
lcd_string(" cm");
54
55
con=0;
56
TCNT1=0;
57
}
58
}
59
}
60
61
ISR(PCINT0_vect)
62
{
63
TCCR1B^=(1<<CS12);// Teiler 256
64
con++;
65
}
Ich würde mich freuen, wenn mit jemand helfen könnte.
mfg mario
Du traust dich was...
Mario E. schrieb:> TCCR1B ^= (1<<CS12); // Teiler 256
Was soll denn das?
Welchn Sinn hat es, mitten im Zählablauf den Vorteiler umzuschalten?
Aber auch der Ablauf ist eher kurios. Ich würde es etwa so machen:
1
volatileintresponse;
2
:
3
:
4
while(1){
5
:
6
:
7
if(respone){
8
// Berechnung überarbeiten!
9
a1=(TCNT1/0.0625);// Umrechnung auf µs
10
a2=((0.0341*a1)/2);// Umrechnung auf cm
11
:
12
response=0;
13
}
14
:
15
:
16
ISR(PCINT0_vect)
17
{
18
ifPORTC&1// steigende Flanke --> Start
19
TCNT1=0;
20
else// fallende Flanke --> Ende
21
response=TCNT1;
22
}
Mario E. schrieb:> uint8_t con = 0;
con sollte volatile sein, denn sonst darfst du keine Optimierung
einschalten und deine Delay-Funktionen passen nicht...
Mario E. schrieb:> bei 10cm Abstand auch 10cm> Aber bei 20cm Abstand zeigt mein Display 25 cm an.> bei 30 sind es 45> bei 40 sind es 63> bei 50 sind es 83> vom Tisch zur Decke sind es 140 cm angezeigt werden 260 cm
Dir ist schon klar, dass der Schall den Weg 2x zurücklegen muss?
Und schwuppdiwupp hast du nur noch ein Problem ganz am Anfang:
10 --> 10 --> 5
20 --> 25 --> 12
30 --> 45 --> 22 (der kleine Rundungstrick hier und ...
40 --> 63 --> 32 hier sei erlaubt, dann passt es besser ;-)
50 --> 83 --> 42
140 -> 260 --> 130
Addiere jetzt einfach mal überall rechts 8cm drauf und was passiert?
10 --> 13
20 --> 20
30 --> 30
40 --> 40
50 --> 50
140 -> 138
Na?
Die 8cm kommen übrigens von dem seltsamen Starten des Timers in deiner
SW...
Mario E. schrieb:> a2 = ((0.0341*a1)/2); // Umrechnung auf cm
Im Datenblatt ist übrigens eine Näherungsformel angegeben, die deinen
Mikrocontroller wohl deutlich weniger fordert, weil sie sich auf
Ganzzahlen beschränkt.
> You can calculate the range through the time interval between sending> trigger signal and receiving echo signal. Formula: uS / 58 = centimeters> or uS / 148 =inch;
Mit freundlichen Grüßen,
Karol Babioch
Lothar Miller schrieb:> Ich würde es etwa so machen: ...
In diesem Code läuft der Timer immer weiter und wird einfach bei der
steigenden Flanke des Sensorsignals auf 0 gesetzt. Bei der fallenden
Flanke wird der Timerwert in die Variable response übernommen.
response ist normalerweise 0, und enthält nur im Fall einer Antwort
einen Wert. Das ist wichtig für die Abfrage mit
if (response) {
Diese Abfrage ist funktionell gleich mit
if (response!=0) {
Denn eine if-Abfrage in C ist immer eine Abfrage auf "ungleich Null".
Ergo steht da: wenn ein Wert ungleich 0 in response steht, dann werte
diese Variable aus und setze sie anschließend wieder auf 0 zurück.
Und jetzt noch ein wort zur Berechnung:
a1 = (TCNT1/0.0625); //Umrechnung auf µs
"geteilt durch 0,0625" ist das selbe wie "mal 16"
Und "mal integer" ist eine ungleich viel einfachere Rechenoperation für
einen uc als "geteilt durch float".
Aber es geht noch einfacher:
wenn du die "mal 16" und die "geteilt durch 58" zusammenfasst, dann
kommt nur noch ein
a2 = (response*16)/58;
heraus.
Bleibt die Frage: woher kommt eigentlich die 58?
Ganz einfach: du rechnest a2 = ((0.0341*a1)/2) und 0.0341/2 sind 58,651.
Da ist also ein spürbarer Rundungsfehler (fast 1%). Aber genauer wird
das wegen der variablen Schallgeschwindigkeit (Temperatur) eh' nicht...
Wobei mir auffällt: in der Formel ist die Halbierung der Strecke schon
drin. Ist evtl. noch dein Timer falsch eingestellt?
Hallo,
schönen Dank für die Hilfe, es funktioniert jetzt.
Auch wenn ich den ganzen Vormittag kämpfen musste, weil einige Dinge
immernoch nicht funktioniert hatten.
Ich habe Ihre ISR an meine gewohnte Struktur angepasst, da es
funktioniert schätze ich, dass es nur eine andere Schreibweise ist.
Ich hatte im ersten Versuch am Anfang des Programms ein Delay eingefügt,
damit das Display nicht so schnell aktualisiert. Dieses Delay hat aber
die Messung verfälscht.
Nun habe ich das Delay für das auslösen des Messvorgangs verlängert und
nun funktioniert es.
Warscheinlich gibts da auch elegantere Möglichkeiten aber beim Versuch
eine Variable per ISR hochzuzählen und mit IF abzufragen bekomme ich
wieder Messfehler.
Wenn ich das jetzt richtig Verstanden habe, rechnet con*16 die Takte die
der Timer zählt in ms um und /58 rechnet das Ergebnis in cm um.
Somit muss ich nur die 16 ändern, wenn ich einen anderen Timer oder uc
mit anderem Takt benutzten möchte.
Super, ich freu mich jedenfalls das es klappt. Danke nochmal.
Hier nochmal mein Code:
1
#define F_CPU 16000000
2
#include<avr/io.h>
3
#include<util/delay.h>
4
#include<stdlib.h>
5
#include<avr/interrupt.h>
6
#include"lcd-routines.h"
7
8
charlcd[4];
9
volatileintcon;
10
inta1;
11
12
13
intmain(void)
14
{
15
DDRC=0b00011101;
16
PORTC=0b10000011;
17
18
PCMSK0|=(1<<PCINT0);//Interrupt control
19
PCICR|=(1<<PCIE0);//Interrupt control
20
sei();
21
22
TCCR1B|=(1<<CS12);// Teiler 256
23
24
lcd_init();
25
26
while(1)
27
{
28
PORTC&=~(1<<PC0);//
29
_delay_ms(100);// -> Löst die Messung des HCSR04 aus.
30
PORTC|=(1<<PC0);//
31
32
//Jetzt löst der Interrupt aus, weil das Modul den Echo auf high setzt.
Mario Eckel schrieb:> Wenn ich das jetzt richtig Verstanden habe, rechnet con*16 die Takte die> der Timer zählt in ms um
Abgesehen vom Typo (ms statt us) stimmt das, wenn du eine Zählfrequenz
von 1/16us also 62,5kHz hast. Sowas bekonnst du z.B. wenn du einen 16MHz
hättest und den durch 256 teilst:
> #define F_CPU 16000000> TCCR1B |= (1<<CS12); // Teiler 256Mario Eckel schrieb:> Somit muss ich nur die 16 ändern, wenn ich einen anderen Timer oder uc> mit anderem Takt benutzten möchte.
Du musst den Wert 16 UND den Vorteiler vom Timer so anpassen, dass du
auf 1us kommst.
Bei 16MHz wäre ein toller Vorteiler z.B. 16. Denn dann müsstest du gar
nichts umrechnen.
Oder noch besser wäre bei 16MHz ein Vorteiler von 940, denn dann
müsstest du gar nichts mehr rechnen, sondern hättest im Zähler gleich
den Abstand in cm.
Hallo und nochmals danke für die Hilfe.
Inzwischen bin ich dabei, eine Wassersteuerung aufzubauen, die mehrere
Regenwassertonnenstände ausmisst und Ventile und Pumpen steuert, sodass
für die Toiletten im Haus kein Frischwasser mehr gebraucht wird.
Ich möchte allerdings noch eine Erfahrung teilen, die ich quasi eben
gerade gemacht habe und geschlagene 3 Tage brauchte um das Problem zu
lösen.
Ich habe dieses mal einen Atmega 1284P benutzt weil ich ein Grafisches
LCD ansteuern wollte.
Ich habe das Programm weitgehend wie oben benutzt, nur das ich anstatt
die INT eingänge die PCINT´s benutzt habe.
Das Problem war, dass ab ca. 60 cm nur noch misst gemessen wurde, es
sprang dann irgendwo von 50 - 70 hin und her.
Ich habe alles ausprobiert, mit den Timern und den Ext. Interrupts und
ich währ beinahe wahnsinnig geworden.
Und was war die Lösung des Problems? Genau, Kondensator direkt an den
HCSR04 und schwubbs war ruhe. Je größer der Kondensator, desto weiter
konnte ich messen.
Das Problem hatte ich mit meinem Atmega8 den ich anfangs benutzt hatte
nicht. Aber mit dem 168-20PU den ich zum testen raus gekramt habe auch.
Naja jetzt funktionierts wieder und es kann weiter gehen.
Ich habe irgendwo gelesen, das jemand auch das Problem hatte, dass er
nur begrenzt gemessen hat. Ich hoffe das hier hilft den einen oder
anderen noch.
mfg mario