Forum: Mikrocontroller und Digitale Elektronik Input Capture mit STM32


von Philipp (Gast)


Lesenswert?

Hallo,
ich verwnede ein STM32VL Discovery Board.
Ich versuche gerade die Frequenz eines Eingangssingnales zu messen.
Signal liegt auf Port PA2 an und hat eine Frequenz zwischen 0Hz und 500 
Hz.
Ich verwende zum messen der Zeit zwischen Rising Edge und Falling Edge 
den Timer15 CH1.
Das Funktioniert auch soweit. Sobald eine Flanke auf dem Signal erkannt 
wird, wird das Capture Event ausgelöst und die ISR ausgeführt.
Mein Problem: Die Werte haben überhaupt nichts mit der gemessenen 
Frequenz zu tun. Gemessene Frequenzen leigen zwischen 366Hz und 
280KHz!!!
Meine Vermutung ist, dass es sich um nicht abgefangene Timer Überläufe 
des Registers handelt. Wenn ich das in der Initialisierung richtig 
verstanden habe, dann läuft der Timer mit dem vollen 24Mhz.
Register geht bis 65535 => 2,73062ms bis zum Überlauf => 366Hz, woher 
vermutlich auch die Untergrenze der gemessenen Frequenz herkommt.

Meine Frage:
Wie kann ich Timerüberläufe Abfangen?
Kann ich den Timer auch auf eine andere Frequenz einstellen, mit der er 
den Register wert hochzählt, dass es gar nicht zu einem Timer überlauf 
kommt?

Anbei mein Code:
Initialisierung:
1
        // Timer 15 Channel_1 PA2
2
        // TIM15 clock enable
3
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM15, ENABLE);
4
5
        // GPIOA clock enable
6
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
7
8
        // TIM15 channel 1 pin (PA.02) configuration
9
        GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_2;
10
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
11
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
12
        GPIO_Init(GPIOA, &GPIO_InitStructure);
13
14
        // Enable the TIM15 global Interrupt
15
        NVIC_InitStructure.NVIC_IRQChannel = TIM1_BRK_TIM15_IRQn;
16
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
17
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
18
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
19
        NVIC_Init(&NVIC_InitStructure);
20
21
        TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;
22
        TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_BothEdge;
23
        TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
24
        TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
25
        TIM_ICInitStructure.TIM_ICFilter = 0x0;
26
27
        TIM_ICInit(TIM15, &TIM_ICInitStructure);
28
29
        // TIM enable counter
30
        TIM_Cmd(TIM15, ENABLE);
31
32
        // Enable the CC2 Interrupt Request
33
        TIM_ITConfig(TIM15, TIM_IT_CC1, ENABLE);

ISR:
1
void TIM1_BRK_TIM15_IRQHandler(void)
2
{
3
  if(TIM_GetITStatus(TIM15, TIM_IT_CC1) == SET)
4
  {
5
    /* Clear TIM15 Capture compare interrupt pending bit */
6
    TIM_ClearITPendingBit(TIM15, TIM_IT_CC1);
7
    if(CaptureNumber == 0)
8
    {
9
      /* Get the Input Capture value */
10
      IC3ReadValue1 = TIM_GetCapture1(TIM15);
11
      CaptureNumber = 1;
12
    }
13
    else if(CaptureNumber == 1)
14
    {
15
      /* Get the Input Capture value */
16
      IC3ReadValue2 = TIM_GetCapture1(TIM15);
17
18
      /* Capture computation */
19
      if (IC3ReadValue2 > IC3ReadValue1)
20
      {
21
        Capture = (IC3ReadValue2 - IC3ReadValue1);
22
      }
23
      else
24
      {
25
        Capture = ((0xFFFF - IC3ReadValue1) + IC3ReadValue2);
26
27
      }
28
      /* Frequency computation */
29
      TIM3Freq = (uint32_t) SystemCoreClock / Capture;
30
      CaptureNumber = 0;
31
    }
32
  }

Danke für eure Tipps und Anregungen

von Nerd (Gast)


Lesenswert?

hm..

ich vermute mal, du hast die Variablen zur Auslesung der Timerwerte als 
unsigned Integer deklariert ?

Eine Überlaufdifferenz kannst du aber nur in einem (signed) int 
berechnen.

... Ich weiß nicht welchen Compiler du verwendest aber die Bedingung 
nach dem ersten "else" kannst du normalerweise weglassen.  Außerdem seh 
ich gerade das du in der If Anweisung die Bedingung "CaptureNumber = 1" 
dahingehend änderst das sie auch im Else-Zweig ausgeführt wird...

von Uwe B. (derexponent)


Lesenswert?

Hi Philipp,

Philipp schrieb:
> Ich verwende zum messen der Zeit zwischen Rising Edge und Falling Edge
> den Timer15 CH1.

das ergibt aber nicht die Frequenz...sondern die Impulszeit
von dem Signal

wenn du die Frequenz messen willst, solltest du nur auf die Hi-Flanke 
triggern (oder nur auf LO-Flanke)

Philipp schrieb:
> Kann ich den Timer auch auf eine andere Frequenz einstellen, mit der er
> den Register wert hochzählt, dass es gar nicht zu einem Timer überlauf
> kommt?

beim STM32F4 gibt es den Befehl
1
TIM_PrescalerConfig(TIM2, 83, TIM_PSCReloadMode_Immediate);

damit wird der Vorteiler auf den Wert "83" eingestellt

und "Nerd" hat recht, in der ISR kannst du schreiben
1
if(CaptureNumber == 0)
2
{
3
  ....
4
  CaptureNumber = 1;
5
}
6
else {
7
  ....
8
  CaptureNumber = 0;
9
}

es gibt ja nur zwei möglichkeiten

und noch was (mit TIM15) hab ich noch nichts gemacht
aber bei TIM2 bis TIM5 muss der GPIO auf AF gestellt werden
und per
1
GPIO_PinAFConfig(GPIOB, GPIO_PinSource11, GPIO_AF_TIM2);

mit dem Timer verbunden werden....
...braucht man das bei TIM15 nicht ?

Gruss Uwe

von Philipp (Gast)


Lesenswert?

Hallo Uwe und Nerd,

danke für eure Hilfe,

Uwe B. schrieb:
> beim STM32F4 gibt es den Befehl
> TIM_PrescalerConfig(TIM2, 83, TIM_PSCReloadMode_Immediate);

Das sieht doch mal Vernünftig aus. Genau so einen Befehl habe ich 
verzweifelt gesucht.
Werde ich gleich mal ausprobieren sobald ich dazu komme und berichten, 
ob ich zum gewünschten Ergebnis gekommen bin.

Uwe B. schrieb:
> und noch was (mit TIM15) hab ich noch nichts gemacht
> aber bei TIM2 bis TIM5 muss der GPIO auf AF gestellt werden
> und perGPIO_PinAFConfig(GPIOB, GPIO_PinSource11, GPIO_AF_TIM2);
>
> mit dem Timer verbunden werden....
> ...braucht man das bei TIM15 nicht ?

Das habe ich nicht gebraucht. Wie gesagt, wird die ISR aufgerufen, 
sobald eine Flanke auf dem Signal ist. Obwohl laut Datenblatt CH2 von 
TIM15 auf PA2 mit Alternate Function declariert ist.
Werde ich auch mal ausprobieren, wie sich dieser Befehl auswirkt.

Grus Philipp

von Philipp (Gast)


Lesenswert?

Hallo Uwe,

also der Befehl

Uwe B. schrieb:
> TIM_PrescalerConfig(TIM2, 83, TIM_PSCReloadMode_Immediate);

hat den gewünschten erfolg gebracht. Ich kann jetzt auch deutlich 
langsamere Frequenzen bestimmen.

Das mit dem GPIO_PinAFConfig ist mir ein Rätsel, da es kein Unterschied 
macht, ob ich diesen Befehl verwende oder nicht.

Weiß jemand genaueres darüber, was es damit aufsich hat.

Gruß Philipp

von M. N. (Gast)


Lesenswert?

Ist zwar für den F4xx und Timer9, aber vielleicht kannst Du den Code für 
Dich anpassen. Beitrag "reziproker Frequenzzähler mit STM32F4Discovery"

Die Variablen zur Berechnung sind vom Typ unsigned (uint16_t, uin32_t) 
damit die Überläufe richtig berechnet werden.

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.