Forum: Mikrocontroller und Digitale Elektronik SRF05 mit Interrupt nutzen


von N. G. (newgeneration) Benutzerseite


Lesenswert?

Guten Tag,

ich habe ein Problem mit dem SRF05 Ultraschallsensor. Wenn ich diesen an 
meinem ATmega2560 anschliesse, braucht eine Messung etwa 20ms (min. 10 / 
max. 30). Den Prozessor programmiere ich mit AVR-Studio 4 in c++.
Hier mal der der Code fuer einen Auslesevorgang
1
uint16_t readDistanceSensor(uint8_t num)
2
     {
3
     DDRB|=(1<<(num+4)); // set pin as output
4
     TCNT3=0;
5
     PORTB|=(1<<(num+4)); // set pin to high
6
     while(TCNT3<=100); //wait 50 us
7
     PORTB&=((1<<(num+4)) xor 0xFF); // set pin low
8
     DDRB&=((1<<(num+4)) xor 0xFF);// set pin as input
9
     while((PINB bitand (1<<(num+4))) != 0);  // wait until pin goes to 0
10
     TCNT3=0; // reset timer
11
12
     while(((PINB bitand (1<<(num+4))) == 0) &&(TCNT3<10000));//wait for signal but not longer than 5ms
13
     uint16_t impuls =TCNT3; 
14
     TCNT3=0;
15
     if(impuls<=10000)
16
     {
17
      while(((PINB&(1<<(num+4)))==(1<<(num+4))) and (TCNT3<60000U)); // wait up to 30ms for pin becoming low
18
      impuls=TCNT3; //1ms = 2000CT, 1us=2CT
19
      if(impuls>=60000U)//more than 30ms: no object in range
20
      {
21
      return 1;
22
      impuls=0;}
23
     }
24
     else
25
     {
26
           impuls=0;
27
    }
28
    return 1.44*impuls;  //????????????? so gehts; so nicht:((impuls/2)/58); //distance in cm =time in us/58
29
}

Nun habe ich mir gedacht, dass das Hauptprogramm mittels einer Interrupt 
weiterlaeuft, waehrend der Sensor noch auf das Echo wartet.
Ich bin mir allerdings nicht sicher ob das ueberhaupt funktioniert.
Dazu kommt, dass der Sensor bei jedem Programmdurchlauf ausgelesen 
werden soll, also sehr schnell.

Wer auf nur eine Anregung hat, soll diese bitte schreiben.

Danke fue eure Hilfe

:
von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

atmega2560 und  N. G. (Firma: KdS) (newgeneration) schrieben:
> Ich möchte nun, da der Auslesevorgang sehr lange dauern kann, erreichen,
> dass das Hauptprogramm weiterläuft und nicht wartet.
Dann muss also sowas loswerden:
> while(TCNT3<=100); //wait 50 us
Und dann solltest du den Ablfu so umstellen, dass du eine Schleife hast,
die dauernd schnellstmöglich durchlaufen wird und die Pins abfragt. Wenn
sich ein Pin geändert hat, sieht die Funktion auf die Uhr und rechnet
sich aus, was da zwischenzeitlich passiert ist, merkt sich dann diese
Uhrzeit und läuft wieder so lange durch die Schleife, bis die nächste
Flanke auftritt...

Es wird also nicht gewartet, sondern auf Änderungen reagiert.

atmega2560 schrieb:
> return 1.44*impuls;  //????????????? so gehts;
Für eine so kleine Rechenaufgabe die float-Lib einbinden?
Weißt du eigentlich, was du da gerade machst?
Probiers doch mal ganz ohne Float so:   return (144*(short)impuls)/100;

von N. G. (newgeneration) Benutzerseite


Lesenswert?

erstmal danke für die schnelle Hilfe.
Hast du dir das Datenblatt angeschaut? Ich versteh zwar, was du mir 
sagen willst, aber nicht wie ich das umsetzen soll.
Wärst du so freundlich mir ein Stück code zu schreiben.
das return habe ich schon umgewandelt. Leider keine große 
Veränderung(war ja auch klar) xD
Danke

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

N. G. schrieb:
> Hast du dir das Datenblatt angeschaut?
Jetzt, ja.
Das ist ja noch einfacher: du gibst einen Impuls aus und lässt dir dann 
2 Pinchange-Interrupts geben. Einen, wenn du die steigende Start-Flanke 
am Echo-Pin bekommst. Und einen zweiten, wenn du eine fallende 
Ende-Flanke am Echo-Pin bekommst. Beim ersten der beiden Interrupts 
merkst du dir den Zählerstand eines Timers, der im Idealfall pro 58us 
(oder pro 5,8us) um eins hochzählt. Und beim zweiten Interrupt liest du 
wieder den Zählerstand aus, subtrahierst den Anfang vom Ende und hat die 
Entfernung in cm oder mm (je nachdem, ob der Timer pro 58us oder 5,8us 
um 1 hochzählt).

N. G. schrieb:
> Nun habe ich mir gedacht, dass das Hauptprogramm mittels einer Interrupt
> weiterlaeuft, waehrend der Sensor noch auf das Echo wartet.
Als Regel sollte gelten: KEIN Hauptprogramm läuft im Interrupt. 
Hauptprogramme laufen in der Hauptschleife. Interrupts werde so schnell 
wie möglich abgearbeitet und mit der Hautpschleife weitergemacht.

> Wärst du so freundlich mir ein Stück code zu schreiben.
Nein. Die Reihenfolge ist anders: du machst dir Gedanken und probierst 
selber mal was aus. Und dabei gibt es evtl. Probleme. Und die können 
wir dann gern hier diskutieren...

> Leider keine große Veränderung(war ja auch klar) xD
Logisch, weil du garantiert irgendwo anders nochmal so einen unnötige 
float-Operation drin hast...

von N. G. (newgeneration) Benutzerseite


Lesenswert?

nochmals Danke.
wollte nicht unhöflich sein, bin ja noch neu hier.
ich poste den Code dann wenn ich ihn habe.

P.S.: ich nutze den mode mit nur 3 Pins

von N. G. (newgeneration) Benutzerseite


Lesenswert?

nun mein verkürtzter code, allerdings noch ohne Interrupts.
1
uint16_t readDistanceSensor(uint8_t num)
2
{
3
  TCNT3=0;
4
  DDRB|=(1<<(num+4));   //set pin as output
5
  PORTB|=(1<<(num+4));  //set pin to high
6
  while(TCNT3 <= 100);  //wait 50us
7
  TCNT3=0;        //reset timer
8
  PORTB&=((1<<(num+4)) xor 0xFF);//set pin low
9
  DDRB&=((1<<(num+4)) xor 0xFF); // set pin as input
10
  TCNT3=0;        //reset timer
11
  while((PINB bitand (1<<(num+4))) == 0 && (TCNT3 < 10000));    // wait until pin goes to 1
12
  TCNT3=0;        //reset timer
13
  while(((PINB&(1<<(num+4)))==(1<<(num+4))) && (TCNT3<=60000U));  //wait for signal but not longer than 30ms
14
  uint16_t impuls=TCNT3;
15
  return (144*impuls)/100;
16
}
immer wenn ich irgendwelche interrupts probiere, geben die Sensoren 
nichts mehr zurück.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

N. G. schrieb:
> nun mein verkürtzter code, allerdings noch ohne Interrupts.
> ... // wait until pin goes to 1
Du musst da nicht irgendwie irgendwelche Interrupts einfügen, du musst 
das komplette Softwarekonzept ändern, da hilft eine Makulatur wie 
"Code verkürzen" nichts...

von N. G. (newgeneration) Benutzerseite


Lesenswert?

also generell schwachsinn?
das ganze Konzept bezieht sich auf diese Methode oder auf mein 
komplettes Programm?

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

N. G. schrieb:
> auf diese Methode
Ja.

> auf mein komplettes Programm?
Das kenne ich nicht, deshalb kann ich es nicht beurteilen...

von N. G. (newgeneration) Benutzerseite


Lesenswert?

wie müsste ich  die methode denn umschreiben(ich habe von Interrupts 
noch nicht so viel Ahnung)
eig. möchte ich mein Programm nicht online stellen, da es konkurrenten 
hrunterladen könnten

von N.G. (Gast)


Lesenswert?

Also, ich grab diesen Thread noch mal aus;
ich habe mich jz wieder hingesetzt und an dem Problem weitergearbeitet; 
nun habe ich auch einen besseren Ansatz:
Der Timer, sowie, die PC-Interrupts werden so konfiguriert:
(16 MHz)
1
TCCR5B = (1<<WGM02)|(1<<CS51);//eneble Timer5(16bit) - CTC; prescaler 8 => every 0,5us 
2
OCR5A = 116;//every 58us
3
TIMSK5 = (1<<OCIE5A);//enable timer 5 overflow
4
TCNT5 = 0;
5
PCICR=(1<<PCIE0); // enable PCINT7:0
6
PCMSK0=(1<<PCINT1); // enable PCINT 1
Der Rest, der die Ultraschallsensoren betrifft:
1
ISR(PCINT0_vect)
2
{
3
  if(PINB & (1<<PB1))//pin changed to high
4
  {
5
    usVal = TCNT5;
6
  }
7
  else if(!(PINB & (1<<PB1)))//pin changed to low
8
  {
9
    us = TCNT5;
10
  }
11
}
12
ISR(TIMER5_COMPA_vect)
13
{
14
  TCNT5++;
15
}
Die Variablen usVal(also der Startwert, uint16_t) und us(Endwert, auch 
uint16_t) sind volatile.

Eigentlich wurden auch die Interrupts während dem Auslösen des 
Messvorgangs(Pin für 50us auf High) gesperrt:
1
PCMSK0 &= ~(1<<PCINT1);
2
DDRB |= (1<<PB1);
3
PORTB |= (1<<PB1);
4
_delay_us(50);
5
PORTB &= ~(1<<PB1);
6
DDRB &= ~(1<<PB1);
7
PCMSK0 |= (1<<PCINT1);

Aber die Sensoren liefern keine sinnvollen Ergebnisse. Leider habe ich 
kein Oszi, nur ein LCD, also keine sehr genauen Zeitangaben.

Hat jemand eine Idee, was ich falsch mache?
Weiter Infos gebe ich natürlich gerne ;)

von N. G. (newgeneration) Benutzerseite


Lesenswert?

ach ja, nur zur info:
der srf05 wird immer noch im mode 2 betrieben, also mit nur einem Pin. 
Dieser liegt auf PB1
MCU ist ein mega2560

: Bearbeitet durch User
von N. G. (newgeneration) Benutzerseite


Lesenswert?

weiß keiner Rat?

von N. G. (newgeneration) Benutzerseite


Lesenswert?

Okay, hat sich erledigt.
Die Lösung war:
Den Dragon bzw. AVR ISP mkII abstecken. So verrückt es klingt. Die 
Clock-Leitung liegt genau auf dem Pin Für den Ultraschall. Leider wurde 
dadurch der Wert bis zur unkenntlichkeit verfälscht..

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.