Forum: Mikrocontroller und Digitale Elektronik Impulsbreite messen mit mega48, timer1


von Rainer U. (r-u)


Lesenswert?

Hi Leute, ich möchte eine Impulsbreite von max. 10ms mit dem Timer1 vom 
Mega48 messen, mit möglichst wenig Prozessorbelastung (also z.B. "wie 
lange war die Leitung auf "H").

Vorüberlegung: Takt = 1MHz, also sollte der Timer erst nach gut 20ms 
überlaufen, wenn der CTC-Mode 12 verwendet wird und timer1 ohne 
prescaler läuft?

Ist es so richtig / am einfachsten, oder gibt es etwas Einfacheres, was 
ich übersehen habe?


1) ICES (edge detector) auf L->H einstellen, Interrupt abwarten 
(steigende Flanke)
2) in der ISR: Timer1 auf 0 stellen, ICES auf H->L umstellen
3) Interrupt abwarten (fallende Flanke)
4) in der ISR: Timer auslesen = Impulsbreite; ICES (edge detector) 
wieder auf auf L->H einstellen

(dann wieder weiter bei 2)

von Karl H. (kbuchegg)


Lesenswert?

Rainer Unsinn schrieb:
>
> Ist es so richtig / am einfachsten, oder gibt es etwas Einfacheres, was
> ich übersehen habe?

Hat der Mega48 am Timer 1 keinen Input Capture?

von Marcel V. (antis)


Lesenswert?

Grundsätzlich funktioniert das. Ich habe auf die Art und Weise mal ein 
PWM Signal ausgewertet. Das hatte, soweit ich mich erinnern kann, 10 
kHz. Problematisch wird es, wenn du nebenbei noch andere Interrupts 
laufen hast. Außerdem kann es bei kurzen Peaks, beispielsweise ein PWM 
von 0,1% oder 99,9% passieren, dass das Setzen der Register und das 
Umschalten der Flankenerkennung so lange dauert, dass du erst die 
nächste Flanke wieder erkennst, dann also statt 0,1%  100,1% gemessen 
werden.

Viel Erfolg.

von Lurchi (Gast)


Lesenswert?

Im Prinzip geht es so.

ICES dürft sich schon auf die Input capture Einheit beziehen.

Man sollte aber den Timer nicht zurücksetzen, sondern die Zeit nur 
Auslesen und die Differenz einfach berechnen. Den Überlauf kriegt man 
automatisch richtig hin, wenn man die Differenz mit word (16 Bit 
unsigned) berechnet.

von Ingo L. (corrtexx)


Lesenswert?

Rainer Unsinn schrieb:
> Hi Leute, ich möchte eine Impulsbreite von max. 10ms mit dem Timer1 vom
> Mega48 messen, mit möglichst wenig Prozessorbelastung (also z.B. "wie
> lange war die Leitung auf "H").
Wie genau muss es denn sein? Wenn du deinen Systemtimer (den du 
hoffentlich hast) auf 10KHz einstellst, kannst du dein Signal im 100us 
Raster abtasten.

Ansonsten, wie bereits erwähnt, den ICP des AVRs nehmen.

von Rainer U. (r-u)


Lesenswert?

Karl Heinz schrieb:
> Rainer Unsinn schrieb:
>>
>> Ist es so richtig / am einfachsten, oder gibt es etwas Einfacheres, was
>> ich übersehen habe?
>
> Hat der Mega48 am Timer 1 keinen Input Capture?

Doch, hat er (B0 istICP1) - da will ich ja das Signal auch anschließen - 
geht es damit einfacher, ggf. wie?

von Ingo L. (corrtexx)


Lesenswert?

Marcel V. schrieb:
> Außerdem kann es bei kurzen Peaks, beispielsweise ein PWM
> von 0,1% oder 99,9% passieren
Man sollte beachten, dass es doch eine merkliche Latenz von ~2us gibt, 
vom ICP bis zum betreten der dazughörigen ISR, sodass die 
Flankenumschaltung bei kleinen Pulsweiten nicht schnell genug erfolgt.

Also Pulse < 2us würde ich sein lassen.

von Rainer U. (r-u)


Lesenswert?

Lurchi schrieb:
> Im Prinzip geht es so.
>
> ICES dürft sich schon auf die Input capture Einheit beziehen.
>
> Man sollte aber den Timer nicht zurücksetzen, sondern die Zeit nur
> Auslesen und die Differenz einfach berechnen. Den Überlauf kriegt man
> automatisch richtig hin, wenn man die Differenz mit word (16 Bit
> unsigned) berechnet.

stimmt, ich lass das 0-stellen weg. Aber ich seh schon, ich habe eine 
bessere Möglichkeit übersehen - schon 2 Hinweise auf den ICP.. ?

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?


von Rainer U. (r-u)


Lesenswert?

Ach ja und an Genauigkeit nehme ich gerne was da ist, also der Timer 
zählt ja dann bei mir mit Mikrosekundenschritten..

von Ingo L. (corrtexx)


Lesenswert?

Rainer Unsinn schrieb:
> Doch, hat er (B0 istICP1) - da will ich ja das Signal auch anschließen -
> geht es damit einfacher, ggf. wie?
1
ISR (INPUT_CAPTURE)
2
{
3
 static uint16_t NewTimerValue, OldValue, Difference;
4
 NewTimerValue = ICP1;
5
6
if (NewTimerValue < OldValue){
7
  Difference = 0xFFFF - OldValue + NewTimerValue;
8
}else{
9
  Difference = NewTimerValue - OldValue;
10
}
11
 // Differenz auswerten
12
 // ...
13
14
 OldValue = NewTimerValue;
15
}

von Karl H. (kbuchegg)


Lesenswert?

Rainer Unsinn schrieb:
> Karl Heinz schrieb:
>> Rainer Unsinn schrieb:
>>>
>>> Ist es so richtig / am einfachsten, oder gibt es etwas Einfacheres, was
>>> ich übersehen habe?
>>
>> Hat der Mega48 am Timer 1 keinen Input Capture?
>
> Doch, hat er (B0 istICP1) - da will ich ja das Signal auch anschließen


Und warum fummelst du dann am TCNT1 Register rum?
Das braucht kein Mensch. Das ist ja das geniale am Input Capture, dass 
einen der TCNT überhaupt nicht mehr interessieren braucht. D.h. solange 
die zu messenden Ticks den maximalen Zählumfang des Timers nicht 
überschreiten.

Der Timer 1 ist ein 16 Bit Timer. D.h. du kannst damit bis zu 65535 
Ticks ganz einfach so im Capture INterrupt 'ausmessen'
1
volatile uint16_t Differenz;
2
3
ISR( ... )
4
{
5
  static uint16_t Start;
6
  uint16_t Now = Capture_Register;
7
8
  Differenz = Now - Start;
9
  Start = Now;
10
}

bei dir kommt dann noch die Flankenumschaltung dazu, aber vom Prinzip 
her wars das. Die Pulsbreite kann bis zu 65535 Timerticks lang sein und 
du wirst immer das richtige Ergebnis erhalten. Und zwar auf den 
Timertakt genau.

von Rainer U. (r-u)


Lesenswert?

Ingo Less schrieb:
...
>   Difference = 0xFFFF - OldValue + NewTimerValue;
> }else{
>   Difference = NewTimerValue - OldValue;
> }
>  // Differenz auswerten
>  // ...
...

Damit bekomme ich aber - meiner Meinung nach - NUR den Abstand zwischen 
2 steigenden Flanken, oder?

von Karl H. (kbuchegg)


Lesenswert?

Ingo Less schrieb:

> if (NewTimerValue < OldValue){
>   Difference = 0xFFFF - OldValue + NewTimerValue;
> }else{
>   Difference = NewTimerValue - OldValue;
> }

Braucht kein Mensch.
Solange unsigned gerechnet wird, kommt da immer das richtige Ergebnis 
raus, wenn man einfach nur Ende - Anfang rechnet.

von Karl H. (kbuchegg)


Lesenswert?

Rainer Unsinn schrieb:
> Ingo Less schrieb:
> ...
>>   Difference = 0xFFFF - OldValue + NewTimerValue;
>> }else{
>>   Difference = NewTimerValue - OldValue;
>> }
>>  // Differenz auswerten
>>  // ...
> ...
>
> Damit bekomme ich aber - meiner Meinung nach - NUR den Abstand zwischen
> 2 steigenden Flanken, oder?

Das kann man so nicht sagen. Er hat ja nicht gezeigt, wie die 
Einstellung der Flankendetektion ist :-)

von Ingo L. (corrtexx)


Lesenswert?

Rainer Unsinn schrieb:
> Damit bekomme ich aber - meiner Meinung nach - NUR den Abstand zwischen
> 2 steigenden Flanken, oder?
Ja, das musst du noch per Hand umschalten

Karl Heinz schrieb:
> Solange unsigned gerechnet wird, kommt da immer das richtige Ergebnis
> raus, wenn man einfach nur Ende - Anfang rechnet.
Sicher?

von Karl H. (kbuchegg)


Lesenswert?

Ingo Less schrieb:

> Karl Heinz schrieb:
>> Solange unsigned gerechnet wird, kommt da immer das richtige Ergebnis
>> raus, wenn man einfach nur Ende - Anfang rechnet.
> Sicher?

Ja, sicher.
Geht nicht anders. Es gibt ja bei unsigned kein negatives Ergebnis. 
Probiers aus, wenn du mir nicht traust.
Was ergibt 5 - 65530?

von Rainer U. (r-u)


Lesenswert?

Karl Heinz schrieb:
> bei dir kommt dann noch die Flankenumschaltung dazu, aber vom Prinzip
> her wars das.

Na gut, so wird's gehen (Flankenumschaltung direkt nach dem Auslesen). 
Ein paar Zeilen kommen wohl noch dazu, damit ich mit der richtigen 
Flanke anfange, aber so ist es schön einfach.

Danke an Alle!

von Ingo L. (corrtexx)


Lesenswert?

Karl Heinz schrieb:
> Ja, sicher.
> Geht nicht anders. Es gibt ja bei unsigned kein negatives Ergebnis.
> Probiers aus, wenn du mir nicht traust.
Läuft ;)

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.