SRF05 mit Interrupt nutzen

OP Persönliche Seite #3103262
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
Moderator (Firma: Titel) Persönliche Seite #3103375
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;
Moderator (Firma: Titel) Persönliche Seite #3103416
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...
OP Persönliche Seite #3103584
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.
Gast #3520862
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 ;)

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