PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Pulsweite messen



Chypsylon
04.04.2011, 17:10
Hallo

Ich möchte gerne die Länge der rot markierten Stellen (also der low-pegel) von folgendem Signal messen: http://teamandroid.bplaced.net/upload/signal.PNG

Ich habe das ganze auf einem atmega128@16mhz mit der input capture funktion probiert doch irgendwie funktioniert es nicht so recht. So wie der code jetzt ist funktioniert nicht einmal die displayausgabe im while-loop. Habt ihr einen Tipp was ich anders machen sollte und/oder wo der/die Fehler sind? :confused:

Das ist das erste Mal das ich timer/interrupts benutze also seid bitte gnädig mit mir falls ich einen echt dummen anfängerfehler gemacht habe ;)

Schon im Vorraus danke für eure Hilfe!



#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdio.h>
#include "lib.h"

uint16_t duration_low=0;
ISR(TIMER3_CAPT_vect)
{
//was rising edge
if((TCCR3B & (1<<ICES3))==0) duration_low=ICR3;
//switch edge detection mode
TCCR3B ^=(1<<ICES3);
//deactivate interrupts
cli();
//set timer to 0
TCNT3=0;
//activate Interrupts
sei();
}


int main(void)
{
char Zahl[4];

// Initialization
INIT();

//set ICP3/PE7 as input
DDRE &= ~(1<<PE7);

//deactivate pwm output
TCCR3A = 0;
//Enable Input Capture Interrupt + Overflow Interrupt
ETIMSK = (1<<TICIE3)|(1<<TOIE3);
//Set Prescaler to cpu clock + Edge detection to falling edge + Input capture noise canceler
TCCR3B |=(0<<CS32)|(0<<CS31)|(1<<CS30)|(0<<ICES3)|(1<<ICNC3);
// Clear Input Capture Flag + clear pending interrupts
ETIFR = (1<<ICF3)|(1<<TOV3);
//activate global interrupts
sei();


while(1)
{

//Displayausgabe
sprintf(Zahl,"%3d",duration_low);
for (uint8_t i=0; i<=10; i++) LINE_2[i]=Zahl[i];
SHOW_LINES();
}

return 0;
}

BMS
04.04.2011, 18:12
Hallo,
ich würde das einfacher lösen. Ohne Interrupts und Timer/Counter.
Vom Prinzip:


void messung()
{
while(PIN_AUF_HIGH)
{
//do nothing
}
unsigned int counter=0;
while(PIN_AUF_LOW)
{
counter++;
warte_wenige_mikrosekunden();
}
return counter;
}


Da müsste man halt noch einen Sicherheitszähler o.ä. rein machen, damit das Programm bei zeitlich konstantem High oder Low-Pegel das Programm nicht hängen bleibt!

Grüße, Bernhard

PS: Die Zeiten kommen mir bekannt vor ;) Robocupjunior neuer Ball (RCJ-05) - Auswertung mit einem TSOP?

Besserwessi
04.04.2011, 19:21
Für eine genaue Messung der Zeiten sollte man den Timer durch laufen lassen, und die Differenzen zwischen den Zeiten für die fallende und steigende Flanke bilden.

Das CLI und SEI in der ISR ist überflüssig, bzw, sogar fehlerträchtig. Das Interrupt-Bit ist in der ISR ohnehin schon gelöscht - CLI macht also nicht. Und am Ende wird das Bit wieder gesetzt - das SEI ist überflüssig und in aller Regel eher schädlich.

Chypsylon
04.04.2011, 19:56
@BMS: Sowas habe ich mir auch schon überlegt aber dabei wird das Programm ziemlich verlangsamt da er in der zähler-whileschleife "hängen bleibt". Außerdem sind einige delays von ein paar ms im Hauptloop eingebaut (z.b. displayausgabe, Tasterentprellung usw..)

PS: Die Zeiten kommen mir bekannt vor ;) Robocupjunior neuer Ball (RCJ-05) - Auswertung mit einem TSOP?
Exakt :) Bist du eigentlich noch dabei?


Für eine genaue Messung der Zeiten sollte man den Timer durch laufen lassen, und die Differenzen zwischen den Zeiten für die fallende und steigende Flanke bilden.
Aber was ist wenn der Timer während der Messung überlauft und wieder bei 0 beginnt? Dann habe ich ja ein falsches negatives Ergebnis?
EDIT: Bin selber draufgekommen - if(erste_messung>zweite messung) zeit= 65536-erste_messung + zweite_messung;

Werde ich dann mal probieren...



Das CLI und SEI in der ISR ist überflüssig, bzw., sogar fehlerträchtig. Das Interrupt-Bit ist in der ISR ohnehin schon gelöscht - CLI macht also nicht. Und am Ende wird das Bit wieder gesetzt - das SEI ist überflüssig und in aller Regel eher schädlich.
Danke für den Hinweis, ich habe irgendwo gelesen das vor Zugriff auf dieses Register alle Interrupts deaktiviert sein sollen - hab wohl im "Eifer des Gefechts" vergessen das diese in der ISR sowieso in die "Warteschlange" gereiht werden :oops:

sternst
04.04.2011, 20:32
Aber was ist wenn der Timer während der Messung überlauft und wieder bei 0 beginnt? Dann habe ich ja ein falsches negatives Ergebnis?Du nimmst die passenden Datentypen (uint16_t) und schon regelt sich das von alleine.


EDIT: Bin selber draufgekommen - if(erste_messung>zweite messung) zeit= 65536-erste_messung + zweite_messung;Einfaches Abziehen reicht, wenn erste_messung und zweite_messung uint16_t sind.

wkrug
04.04.2011, 22:36
Ich würde es schon mit dem Input Capture Interrupt machen, weil das praktisch im Hintergrund läuft.

Der Trick dabei ist, das Sensing, also ob der Interrupt auf steigende oder fallende Flanke reagiert in der Interruptroutine umgeschaltet wird.

Das Sensing wird also zunächst auf fallende Flanke eingestellt.
Tritt dieser Interrupt dann auf wird das Input Capture Register ausgelesen und in einer Variable zwischengespeichert.
Zusätzlich wird das Interrupt Sensing auf steigende Flanke umgestellt.

Wird nun irgendwann durch die steigende Flanke der ICP Interrupt ausgelöst, wird das Input Capture Register ausgelesen und der vorher abgespeicherte Wert abgezogen.
Der Unterschied ist das Mass für die gemessene Pausenlänge, also Dein gewünschtes Ergebnis.
Sogleich wird das Interrupt Sensing wieder auf fallende Flanke für die nächste Messung eingestellt.

Ob es dabei zu Überläufen bzw. Fehlberechnungen bei der Subtraktion, kommt wird vom Compiler abhängig sein.
Üblicherweise kommt es bei der reinen Subtraktion von 2 16Bit Unsigned Int Variablen zu keinen Rechenfehlern.
Ich nehm da immer gerne einen 8MHz Quarz und einen Vorteiler von 8, weil dann das errechnete Ergebnis direkt in µs rauskommt.
Die maximal mögliche Messlänge ist dabei 65535µs. Sonst ist ja der Timer ( 16Bit ) bereits einmal komplett durchgelaufen.

Günstig ist es auch, wenn in der Interruptroutine ein Flag ( Bit Variable ) nach einer neuen Berechnung gesetzt wird, damit das Hauptprogramm weiß, das es wieder was zu tun hat.
Wenn das Hauptprogramm den gemessenen Wert verarbeitet hat, wird dieses Flag einfach wieder gelöscht.

sternst
05.04.2011, 08:43
Ob es dabei zu Überläufen bzw. Fehlberechnungen bei der Subtraktion, kommt wird vom Compiler abhängig sein.Nein, es sei denn der Compiler ist fehlerhaft. Über-/Unterläufe bei Unsigned-Integer-Arithmetik sind im C Standard eindeutig definiert.

BMS
05.04.2011, 09:43
PS: Die Zeiten kommen mir bekannt vor :wink: Robocupjunior neuer Ball (RCJ-05) - Auswertung mit einem TSOP?
Exakt :) Bist du eigentlich noch dabei?
Bin nicht mehr dabei, studiere jetzt Elektrotechnik, 2.Semester ;)

Wie viele TSOP wertest du denn aus? Weil es gibt nur relativ wenige Pins, an denen du mit Input Capture arbeiten kannst.

Grüße, Bernhard

wkrug
05.04.2011, 19:16
Wie viele TSOP wertest du denn aus? Weil es gibt nur relativ wenige Pins, an denen du mit Input Capture arbeiten kannst.
Man kann auch noch die Interrupt Quellen INTx verwenden, da sich da auch das Sensing einstellen lässt.
Allerdings produziert man da einen kleinen Fehler, weil man dabei ja nur das TCNT Register auslesen kann, das ja immer weiter hochzählt.

Chypsylon
06.04.2011, 20:06
Danke für die Tipps ich werde sie wenn ich wieder mal zeit habe umsetzen und mich bei event. Problemen wieder an euch wenden :)


Nein, es sei denn der Compiler ist fehlerhaft. Über-/Unterläufe bei Unsigned-Integer-Arithmetik sind im C Standard eindeutig definiert.
Zumindest in dieser Hinsicht funktioniert avr-gcc einwandfrei


Bin nicht mehr dabei, studiere jetzt Elektrotechnik, 2.Semester ;)

Wie viele TSOP wertest du denn aus? Weil es gibt nur relativ wenige Pins, an denen du mit Input Capture arbeiten kannst.

Grüße, Bernhard
Eigentlich habe ich vorgehabt 16 sensoren auszuwerten, pro 16bit timer gibt es nur einen icp-pin was aber kein weiteres problem sein sollte wenn ich die sensoren mit einem 5041 (oder ähnlichem) abwechselnd auf den icp-pin durchschalte

wkrug
06.04.2011, 21:45
Eigentlich habe ich vorgehabt 16 sensoren auszuwerten, pro 16bit timer gibt es nur einen icp-pin was aber kein weiteres problem sein sollte wenn ich die sensoren mit einem 5041 (oder ähnlichem) abwechselnd auf den icp-pin durchschalte
Du kannst INT0, INT1, INT2, und den ICP verwenden.
Eventuell wäre auch ein Controller mit Pin Change Interrups eine Lösung.
Dann sind noch mehr Interrupteingänge möglich.
Welcher Pin sich aber da geändert hat musst Du per Software rausfinden.
16 Sensoren pro Controller dürfte eine harte Nummer werden.
Die Messungen sollen ja auch einigermassen stimmige Werte ergeben und keine Schätzungen sein.