Forum: Mikrocontroller und Digitale Elektronik Frequenz Messung InputCapture STM32


von Palmolive (Gast)


Lesenswert?

Guten Morgen,
ich versuche mit einem Stm32F103 eine Frequenz zu messen.
Und das Ergebnis ist fast gut. Irgendwie ist die Messung immer um einen 
1% zu niedrig. (gegenüber Oszilloskop)

die Init des Timers sieht so aus
1
void MX_TIM3_Init(void)
2
{
3
  TIM_ClockConfigTypeDef sClockSourceConfig;
4
  TIM_MasterConfigTypeDef sMasterConfig;
5
  TIM_IC_InitTypeDef sConfigIC;
6
7
  htim3.Instance = TIM3;
8
  htim3.Init.Prescaler = 71;
9
  htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
10
  htim3.Init.Period = 99;
11
  htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
12
  htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
13
  if (HAL_TIM_Base_Init(&htim3) != HAL_OK)
14
  {
15
    _Error_Handler(__FILE__, __LINE__);
16
  }
17
18
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
19
  if (HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig) != HAL_OK)
20
  {
21
    _Error_Handler(__FILE__, __LINE__);
22
  }
23
24
  if (HAL_TIM_IC_Init(&htim3) != HAL_OK)
25
  {
26
    _Error_Handler(__FILE__, __LINE__);
27
  }
28
29
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
30
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
31
  if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
32
  {
33
    _Error_Handler(__FILE__, __LINE__);
34
  }
35
36
  sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_FALLING;
37
  sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
38
  sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
39
  sConfigIC.ICFilter = 15;
40
  if (HAL_TIM_IC_ConfigChannel(&htim3, &sConfigIC, TIM_CHANNEL_1) != HAL_OK)
41
  {
42
    _Error_Handler(__FILE__, __LINE__);
43
  }
44
45
}
Die ISR
1
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
2
{
3
  static uint16_t captureState=0;
4
  switch (captureState)
5
  {
6
    case 1:
7
      inputCapture_A = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1); //1)
8
      overflow_cnt = 0;
9
      update = 0;
10
      captureState = 0;
11
      break;
12
    case 0:
13
      inputCapture_B = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1); //1)
14
      update = 1; //2)
15
      captureState = 1;
16
      break;
17
    default:
18
      break;
19
  }
20
}

Die Auswertung in der main
1
#define MAX_CNT 100
2
if (update == 1)
3
    {
4
      zw_Erg = inputCapture_B - inputCapture_A;
5
6
      if (zw_Erg >= 0) // Überlauf erkennung
7
      {
8
        pw_us = zw_Erg; // erg = (B-A)
9
      }
10
      else
11
      {
12
        pw_us = zw_Erg + MAX_CNT; // erg=(max-A)+B = (B-A)+max
13
      }
14
      pw_us = pw_us + (overflow_cnt * MAX_CNT);
15
16
      pw_s = (double)pw_us / 1E6;
17
      frq_Hz = 1 / pw_s; // Frequenz in Hz
18
      printf("\n\rpw_us= %li, Frequenz = %04.2f Hz OV=%i\r\n", pw_us,frq_Hz,overflow_cnt );
19
      update = 0;
20
    }

Was mache ich falsch.
Wo habe ich den Denkfehler?

Danke  für die Hilfe

von m.n. (Gast)


Lesenswert?

Mit einem Programmfragment ohne Kommentare kann man nichts anfangen.
Ich gebe Dir ein Beispiel, wie man die Frequenz reziprok messen kann. 
Vielleicht ist das eine Anregung für Dich.
Beitrag "reziproker Frequenzzähler mit STM32F4Discovery"

von Palmolive (Gast)


Lesenswert?

Also meine Vermutung ist das ich die Zeit Basis nicht ganz Stimmt.
Ich Habe einen Hauptakt von 72MHz


Und Teile den mit htim3.Init.Prescaler = 71; das sollte eine division 
von72 sein also sollte ich einen Timer Takt von 1us haben.
Ist diese Annahme richtig? weiters habe ich htim3.Init.Period = 99; dies 
sollte bewirken das ich alle 100 100us einen überlauf meines Zählers 
habe.
Ist das so richtig interpretiert?

Danke für die Hilfe

m.n. schrieb:
> Mit einem Programmfragment ohne Kommentare kann man nichts anfangen.

Wie soll ich es aufarbeiten damit man was tun kann?
Lg

von pegel (Gast)


Lesenswert?

Teiler und Periode sollten stimmen.

Leite deinen internen Takt an den MCO und vergleiche was dein Oszi als 
Frequenz anzeigt.

von Palmolive (Gast)


Lesenswert?

pegel schrieb:
> Teiler und Periode sollten stimmen.
>
> Leite deinen internen Takt an den MCO und vergleiche was dein Oszi als
> Frequenz anzeigt.

Bei einer Frequenz von 100Hz messe ich 99 und bei 1Herz eben auch nur 
0.9 Herz
etwas muss ich falsch machen

von 123 Gast (Gast)


Lesenswert?

Wie genau ist das Oszi? Schon mal mit nem Frequenzzähler versucht?

von pegel (Gast)


Lesenswert?

Palmolive schrieb:
> Bei einer Frequenz von 100Hz messe ich 99

Ich meine den MCO, um erst einmal den internen Takt mit deinem Oszi 
abzugleichen.

von Palmolive (Gast)


Lesenswert?

123 Gast schrieb:
> Wie genau ist das Oszi? Schon mal mit nem Frequenzzähler versucht?

Habe ich leider nicht.
Es ist ein Fluke105B Scopemeter

pegel schrieb:
> Ich meine den MCO, um erst einmal den internen Takt mit deinem Oszi
> abzugleichen.

Was ist der MCO?

Danke

von pegel (Gast)


Lesenswert?

Palmolive schrieb:
> Was ist der MCO?

Master Clock Output.

Damit kannst du den internen Takt von verschiedenen Quellen über Teiler 
an ein Pin nach aussen leiten.

von pegel (Gast)


Lesenswert?

Du hast CubeMX verwendet, stimmts?

Dann findest du unter Clock Configuration unten links die Einstellung 
und in System Core -> RCC die Aktivierung des MCO.

von Hans (Gast)


Lesenswert?

Subtrahiere mal -1 vom Ergebnis des Timers. Sprich:

frq_Hz = 1 / (pw_s - 1); // Frequenz in Hz

von Jim M. (turboj)


Lesenswert?

Palmolive schrieb:
> Irgendwie ist die Messung immer um einen
> 1% zu niedrig.

Benutzt Du einen Quarz oder den internen RC Oszillator? Letzterer darf 
um 1% auch bei Laborbedingungen falsch gehen, siehe Datenblatt.

von Palmolive (Gast)


Lesenswert?

Jim M. schrieb:
> Benutzt Du einen Quarz oder den internen RC Oszillator? Letzterer darf
> um 1% auch bei Laborbedingungen falsch gehen, siehe Datenblatt.

Ja ich verwende ein Quarz!

Hans schrieb:
> Subtrahiere mal -1 vom Ergebnis des Timers. Sprich:
>
> frq_Hz = 1 / (pw_s - 1); // Frequenz in Hz

Kannst du mir den Grund dafür nennen?
werde es probieren
Danke

pegel schrieb:
> Du hast CubeMX verwendet, stimmts?
>
> Dann findest du unter Clock Configuration unten links die Einstellung
> und in System Core -> RCC die Aktivierung des MCO.

A ok wie dumm von Mir

Danke

von 123 Gast (Gast)


Lesenswert?

Wie genau ist das Oszi? Ich werde jetzt sich nicht das Manual deines 
Scopes lesen wenn du schon zu faul bist...

von Andreas S. (igel1)


Lesenswert?

Stelle bitte Deinen gesamten Code hier ein - Du kannst auch Anhänge hier 
hochladen. Alternativ kannst Du Deinen Code auch bei Github oder sonstwo 
einstellen, aber ohne Gesamtsicht ist das hier nur Raterei.

Insbesondere die Clocktree-Initialisierung wäre interessant.
Vielleicht liegt dort schon etwas im Argen.

Ein Bild vom Clocktree wäre ebenfalls nett - ich meine so etwas einmal 
in dem Programm, mit dem man HAL programmiert, gesehen zu haben.

Viele Grüße

Igel1

von m.n. (Gast)


Lesenswert?

Andreas S. schrieb:
> aber ohne Gesamtsicht ist das hier nur Raterei.

Sag ich doch. Nicht einmal das Meßverfahren und der benötigte 
Frequenzbereich sind klar.
Dennoch wundere ich mich über die vielen gut gemeinten Tipps.
100 Hz / 99 Hz sind 1%, 1,0 Hz / 0,9 Hz allerdings schon 10% Abweichung. 
Mit Quarz oder nicht hat das nichts zu tun.

von Palmolive (Gast)


Lesenswert?

m.n. schrieb:
> Sag ich doch. Nicht einmal das Meßverfahren und der benötigte
> Frequenzbereich sind klar.
> Dennoch wundere ich mich über die vielen gut gemeinten Tipps.
> 100 Hz / 99 Hz sind 1%, 1,0 Hz / 0,9 Hz allerdings schon 10% Abweichung.
> Mit Quarz oder nicht hat das nichts zu tun.

Ich werde jetzt ein Projekt anlegen das nur die Frequenzmessung hat.
Das Quarz funktioniert den der Canopen funktioniert.

Also bis gleich und danke für die Hilfe und Entschuldigung für meine 
Unklarheit

von Palmolive (Gast)


Angehängte Dateien:

Lesenswert?

So hier wie gewünscht das gesamte Projekt.

von Herr Bert (Gast)


Lesenswert?

Ohne jetzt am frühesten Morgen nachgedacht zu haben: Wie kann denn case 
1: möglich sein, wenn bei jedem Eintritt explizit auf 0 gesetzt wird?
1
static uint16_t captureState=0;
2
  switch (captureState)
3
  {
4
    case 1:
5
      inputCapture_A = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1); //1)
6
      overflow_cnt = 0;
7
      update = 0;
8
      captureState = 0;
9
      break;
10
    case 0:
11
      inputCapture_B = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1); //1)
12
      update = 1; //2)
13
      captureState = 1;
14
      break;
15
    default:
16
      break;
17
  }

von Beo Bachta (Gast)


Lesenswert?

Herr Bert schrieb:
> wenn bei jedem Eintritt explizit auf 0 gesetzt wird?

Wird es ja nicht da static deklariert.

von Andreas S. (igel1)


Angehängte Dateien:

Lesenswert?

Habe die ClockConfiguration aus Deinem *.zip-file entnommen.
Das sieht meiner Meinung nach korrekt aus.

Viele Grüße

Igel1

von Palmolive (Gast)


Lesenswert?

Andreas S. schrieb:
> Habe die ClockConfiguration aus Deinem *.zip-file entnommen.
> Das sieht meiner Meinung nach korrekt aus.

Ich finde der fehler muss im Programm sein aber ich finde ihn leider 
nicht.

von Andreas S. (igel1)


Lesenswert?

Palmolive schrieb:
> Andreas S. schrieb:
>> Habe die ClockConfiguration aus Deinem *.zip-file entnommen.
>> Das sieht meiner Meinung nach korrekt aus.
>
> Ich finde der fehler muss im Programm sein aber ich finde ihn leider
> nicht.

Habe mir Deinen Code nun mindestens eine halbe Stunde angesehen, werde 
aber nicht so recht schlau daraus.

Ich habe dabei 2 Probleme:

1.)  Leider kenne ich mich mit HAL so gar nicht aus und
2.)  Ich verspüre wenig Lust, gänzlich unkommentierten Code reverse
     zu engineeren

Wenn Du hier die Funktionsweise Deines Code zumindest etwas erklären 
könntest, so erhältst Du vielleicht von dem einen oder anderen noch 
etwas Hilfe oder zumindest Hinweise.

Fragen wären z.B.:

- Wie funktioniert Dein Programm?
- Wie funktioniert Dein "overflow"-Mechanismus?
- Wie und wo genau wird die overflow-Variable gefüllt?

Weitere Fragen sind z.B.:

- Welche Frequenzen willst Du mit dem Teil messen?
- Woher nimmst Du die Messfrequenz, die Du untersuchst?
- Bist Du Dir 100%ig sicher, dass diese Messfrequenz stimmt?
- Spendiere und mal den Output Deines Programmes bei verschiedenen
  Frequenzen:  1Hz, 10Hz, 100Hz, 1kHz, 10kHz, 10kHz, 1MHz, 10MHz

Viele Grüße

Igel1

von Beo Bachta (Gast)


Lesenswert?

Andreas S. schrieb:
> Ich habe dabei 2 Probleme:
>
> ............
> 2.)  Ich verspüre wenig Lust, gänzlich unkommentierten Code reverse
>      zu engineeren

Andreas S. schrieb:
> Wenn Du hier die Funktionsweise Deines Code zumindest etwas erklären
> könntest, so erhältst Du vielleicht von dem einen oder anderen noch
> etwas Hilfe oder zumindest Hinweise.

Zweimal Zustimmung zu dem schon geschriebenen.

Ich weiss warum ich HAL nicht mag obwohl man bei den neueren
Prozessoren fast nicht mehr drum herumkommt wenn man nicht
Bare Metal prgrammieren möchte. Für jedes Bit Setzen oder
Löschen eine HAL Call, auch die Interrupts werden schon mit
Callbacks "belastet", alles sehr unübersichtlich, jede HAL
Funktion wieder woanders suchen..... Und alles das bei einem
jetzt sehr kleinen Projekt ....

Ja ich habe mir das Zeugs heruntergeladen aber auch durch
HAL keine Lust das zu durchforsten ....

von R.F (Gast)


Lesenswert?

> Ich weiss warum ich HAL nicht mag obwohl man bei den neueren
> Prozessoren fast nicht mehr drum herumkommt wenn man nicht
> Bare Metal prgrammieren möchte. Für jedes Bit Setzen oder
> Löschen eine HAL Call, auch die Interrupts werden schon mit
> Callbacks "belastet", alles sehr unübersichtlich, jede HAL
> Funktion wieder woanders suchen..... Und alles das bei einem
> jetzt sehr kleinen Projekt ....

Was heißt nicht drumrum kommen. Es gibt auch die LL und die ist sogar 
kombinierbar mit HAL.

von Beo Bachta (Gast)


Lesenswert?

R.F schrieb:
> Es gibt auch die LL

Die hab ich allerdings noch nie gesehen. Zeigst du sie mir?

von pegel (Gast)


Lesenswert?

Da alles auf Pulsdauer Messung beruht, bleibt nur der Berechnungsteil 
als Fehlerquelle. Das hat nichts mit HAL zu tun.

inputCapture_A und inputCapture_B würde ich genauer unter die Lupe 
nehmen, um zu sehen ob die Grundlage für die weitere Berechnung auch 
stimmt.

von Andreas S. (igel1)


Lesenswert?

1
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
2
{
3
  static uint16_t captureState=0;
4
  switch (captureState)
5
  {
6
    case 1:
7
      inputCapture_A = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1); //1)
8
      overflow_cnt = 0;
9
      update = 0;
10
      captureState = 0;
11
      break;
12
    case 0:
13
      inputCapture_B = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1); //1)
14
      update = 1; //2)
15
      captureState = 1;
16
      break;
17
    default:
18
      break;
19
  }
20
}

Szenario:  zwischen zwei Aufrufen der obigen ISR (nach meiner Berechnung 
passiert das alle 100us) trudeln 80 Pulse rein.

Das entspricht einer Frequenz von 80/100us=800kHz und einer Pulsdauer 
von 1/800kHz=1,25us.

Beim ersten Aufruf sei der Counter=10, beim nächsten Aufruf steht der 
Counter auf 90, overflow gibt es keinen.

Dann ist nach meinen Überlegungen inputCapture_B=10 und 
inputCapture_A=90.

Dann passiert in der Hauptroutine nach meinen Überlegungen folgendes:
1
#define MAX_CNT 100
2
if (update == 1)
3
    {
4
      // Igel1: zw_Erg=10-90=-80
5
      zw_Erg = inputCapture_B - inputCapture_A;
6
7
      if (zw_Erg >= 0) // Überlauf erkennung
8
      {
9
        pw_us = zw_Erg; // erg = (B-A)
10
      }
11
      else
12
      {
13
        // Igel1: wir landen in else-Zweig und pw_us=-80+100=20
14
        pw_us = zw_Erg + MAX_CNT; // erg=(max-A)+B = (B-A)+max
15
      }
16
      // Igel1: wegen overflow_cnt=0 bleibt pw_us=20
17
      pw_us = pw_us + (overflow_cnt * MAX_CNT);
18
19
      // Igel1: pw_s=20/1000000=20*10e-6
20
      pw_s = (double)pw_us / 1E6;
21
      // Igel1: frq_Hz=1/20*10e-6=50000
22
      frq_Hz = 1 / pw_s; // Frequenz in Hz
23
      // Igel1: hier müsste rauskommen:
24
      //        "pw_us=20, Frequenz = 50000,00 Hz OV=0"
25
      printf("\n\rpw_us= %li, Frequenz = %04.2f Hz OV=%i\r\n", pw_us,frq_Hz,overflow_cnt );
26
      update = 0;
27
    }


Fazit: Nach meinen Überlegungen müsste eigentlich alles total 
danebengehen:
50.000Hz Anzeige statt 800KHz.

Trotzdem berichtet der TO nur vor einer Abweichung von 1%.
Das heisst: ich muss wohl irgendwo sein Programm falsch nachvollziehen 
...

Viele Grüße

Igel1

von Palmolive (Gast)


Lesenswert?

Andreas S. schrieb:
> Fragen wären z.B.:
>
> - Wie funktioniert Dein Programm?

also ich habe den im InputCapture  Interrupt auf fallender Flanke 
eingestellt und im Interrupt des selben führe ich diesen
1
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
2
{
3
  static uint16_t captureState=0;
4
  switch (captureState)
5
  {
6
    case 1:
7
      inputCapture_A = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1); //1)
8
      overflow_cnt = 0;
9
      update = 0;
10
      captureState = 0;
11
      break;
12
    case 0:
13
      inputCapture_B = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1); //1)
14
      update = 1; //2)
15
      captureState = 1;
16
      break;
17
    default:
18
      break;
19
  }
20
}

> - Wie funktioniert Dein "overflow"-Mechanismus?
wenn der zähler des selben Timer von 99 auf 100 geht zähle ich den 
Overflow
> - Wie und wo genau wird die overflow-Variable gefüllt?
>
> Weitere Fragen sind z.B.:
>
> - Welche Frequenzen willst Du mit dem Teil messen?
Frequenzen bis 200Hz
> - Woher nimmst Du die Messfrequenz, die Du untersuchst?
> - Bist Du Dir 100%ig sicher, dass diese Messfrequenz stimmt?
> - Spendiere und mal den Output Deines Programmes bei verschiedenen
>   Frequenzen:  1Hz, 10Hz, 100Hz, 1kHz, 10kHz, 10kHz, 1MHz, 10MHz
bei 100Hz = diese AUsgabe pw_us= 10100, Frequenz = 99.01 Hz OV=101

von R.F (Gast)


Lesenswert?

Beo Bachta schrieb:
> R.F schrieb:
>> Es gibt auch die LL
>
> Die hab ich allerdings noch nie gesehen. Zeigst du sie mir?

Gerne z.B. InputCapture in LL
1
void Configure_TIMInputCapture(void)
2
{
3
  /*************************/
4
  /* GPIO AF configuration */
5
  /*************************/
6
  /* Enable the peripheral clock of GPIOs */
7
  LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOA);
8
9
  /* GPIO TIM3_CH1 configuration */
10
  LL_GPIO_SetPinMode(GPIOA, LL_GPIO_PIN_6, LL_GPIO_MODE_INPUT);
11
  LL_GPIO_SetPinPull(GPIOA, LL_GPIO_PIN_6, LL_GPIO_PULL_DOWN);
12
13
  /***************************************************************/
14
  /* Configure the NVIC to handle TIM3 capture/compare interrupt */
15
  /***************************************************************/
16
  NVIC_SetPriority(TIM3_IRQn, 0);
17
  NVIC_EnableIRQ(TIM3_IRQn);
18
  
19
  /******************************/
20
  /* Peripheral clocks enabling */
21
  /******************************/
22
  /* Enable the timer peripheral clock */
23
  LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM3);
24
  
25
  /************************************/
26
  /* Input capture mode configuration */
27
  /************************************/
28
  /* Select the active input: IC1 = TI1FP1 */
29
  LL_TIM_IC_SetActiveInput(TIM3, LL_TIM_CHANNEL_CH1, LL_TIM_ACTIVEINPUT_DIRECTTI);
30
  
31
  /* Configure the input filter duration: no filter needed */
32
  LL_TIM_IC_SetFilter(TIM3, LL_TIM_CHANNEL_CH1, LL_TIM_IC_FILTER_FDIV1);
33
34
  /* Set input prescaler: prescaler is disabled */
35
  LL_TIM_IC_SetPrescaler(TIM3, LL_TIM_CHANNEL_CH1, LL_TIM_ICPSC_DIV1);
36
37
  /* Select the edge of the active transition on the TI1 channel: rising edge */
38
  LL_TIM_IC_SetPolarity(TIM3, LL_TIM_CHANNEL_CH1, LL_TIM_IC_POLARITY_RISING);
39
  
40
  /**************************/
41
  /* TIM3 interrupts set-up */
42
  /**************************/
43
  /* Enable the capture/compare interrupt for channel 1 */
44
  LL_TIM_EnableIT_CC1(TIM3);
45
  
46
  /***********************/
47
  /* Start input capture */
48
  /***********************/
49
  /* Enable output channel 1 */
50
  LL_TIM_CC_EnableChannel(TIM3, LL_TIM_CHANNEL_CH1);
51
    
52
  /* Enable counter */
53
  LL_TIM_EnableCounter(TIM3);
54
}

Die Funktionen sind alle inline und werden direkt auf die entsprechenden 
register aufgelöst (kein overhead).

Die LL ist direkt mit dabei lässt sich auch im STMCube einstellen. So 
wird nur LL verwendet und kein HAL.

von Andreas S. (igel1)


Lesenswert?

Tut mir leid, Palmolive, Deine Erklärung ist alles andere als 
verständlich - ich verstehe jedenfalls nach wie vor nur Bahnhof.

Du musst Dir schon etwas mehr Mühe mit der Erklärung der Funktionsweise 
Deines Programms geben, sonst wird das hier nichts.

Viele Grüße

Igel1

von 123 Gast (Gast)


Lesenswert?

Wie soll er dass den auch noch schaffen.... Er meint nach wie vor dass 
die Zeitbasis eines Oszis beliebig genau ist...

von Palmolive (Gast)


Lesenswert?

123 Gast schrieb:
> Wie soll er dass den auch noch schaffen.... Er meint nach wie vor dass
> die Zeitbasis eines Oszis beliebig genau ist...

Ich traue einem guten Oszi mehr als meinem Programm.

Andreas S. schrieb:
> Tut mir leid, Palmolive, Deine Erklärung ist alles andere als
> verständlich - ich verstehe jedenfalls nach wie vor nur Bahnhof.
>
> Du musst Dir schon etwas mehr Mühe mit der Erklärung der Funktionsweise
> Deines Programms geben, sonst wird das hier nichts.
>
> Viele Grüße
>
> Igel1

Habe den Fehler gefunden.habe den ersten Überlauf zu viel gzählt.
Jetzt geht es!

von pegel (Gast)


Lesenswert?

Schön das du den Fehler gefunden hast.


Palmolive schrieb:
> Ich traue einem guten Oszi mehr als meinem Programm.

Du hättest aber schon lange HSE auf den MCO Pin ausgeben können, wenn 
dann die 8MHz angezeigt werden, brauchst du nicht auf das Oszi 
vertrauen, sondern kannst einfach messen.

von m.n. (Gast)


Lesenswert?

Palmolive schrieb:
> Habe den Fehler gefunden.habe den ersten Überlauf zu viel gzählt.

Das war ja abzusehen, denn Palmolive schrieb:
> bei 100Hz = diese AUsgabe pw_us= 10100, Frequenz = 99.01 Hz OV=101

Nur, was Du da programmiert hast, ist mir nach wie vor nicht klar. 
Nicht, weil ich mich weigere diesen ganzen HAL-Klumpatsch durchzusehen, 
sondern weil kein einziger Kommentar, keine einzige Erläuterung zur 
gewünschten Funktion gegeben wurde.
Ebenfalls nicht zu verstehen ist, auf der einen Seite einen Zähler mit 
dekadischem Überlauf zu programmieren und auf der anderen Seite 
float-Berechnungen durchzuführen. Typischerweise läßt man einen 16 Bit 
Zähler bis 65535 zählen, bevor ein Überlauf stattfindet. Der µC hat 
keine zehn Finger, mit denen er ganz schnell zählen muß.

von FloMann (Gast)


Lesenswert?

Morgen,

Zur Config interpretation:
Timer 2 alle 1ms Overflow,in dessen
Overflow ISR Callback alle 5 durchläufe
ein Pin Toggle. Dies ergibt 100Hz,
ist das die Frequenz die du aktuell an deinen Timer 3
Capture Input zum Messen gibst?

Timer 3 alle 100µs Overflow und Input Capture auf
Negative Flanke?

Beide Timer die selbe Clk Quelle,mehr oder minder Synchron.

1.) In Main deine Auswertung:
ZwErg = CapB - CapA
deklariert als
int32 =  uInt16 - uInt16
wird nicht so funktionieren wie du dir das wünscht,
weil hier i.r. keine negativen Zahlen rauskommen werden.
uInt16 - uInt16 gibt dann zwar einen überlauf die Zahl
ist dann aber immer Positiv und wird dann in dein ZwErg geschrieben.
Sprich du landest immer in deinem ersten If Zweig der auswertung.
z.B. uInt16 zuvor casten auf int32

Annahme obige Berechnung Korrigiert
Bsp: CaptureA = 99, Capture B = 49, OVR = 1 folglich 50µs
zwErg = B - A = -50 /folgt nun im If der zweig else
pwus = zwErg + 100(Max Capture Timer OVR Count) = 50
pwus = pw_us + (1* 100) = 150 -> eine Timer3 Overflow Periode zuviel.

Den Else Zweig kannst du dir sparen.
pwus = zwErg(-50) + (1*100) = 50 reicht.

Das dir der erste berechnungsfehler momentan nicht auf die
Füße fällt liegt wahrscheinlich auch daran das deine beiden
Capture A und B Werte (fast)immer gleich sind und die differenz
bisher nicht negativ wurde.
10ms Periode deiner Messfrequenz(100Hz) erzeugt mit dem selben Takt
zu deinen 100µs im Timer3 ist hier ein vielfaches.
Variiere hier mal und ich denke der Fehler wird auffallen.

2.) Capture ISR
-Negative Flanke, State = 1, Speicher Capture A
Capture WertA = 99, also 1µs Tick vor dem Overflow.
Nun kommt der Overflow und der Counter wird um 1 erhöht,
jetzt geht es mit etwas verzug in deine Capture ISR und
du nullst nun den Overflow Count, im grunde Race condition.

BSP:
A = 99 -> B = 49 ergibt 50µs Periodenzeit mit normal einem Overflow,
der aber hier aufgrund zeitlichen abläufen von deinem Programm
genullt wurde.

Auswertung: mit Korrigierten Berechnungen.
49 - 99 = -50 + (OVRCnt(0) * 100µs(CatureTimerOVR) = -50 -> falsch

-Negative Flanke, State = 0, Speicher Capture B
Capture WertB = 99, bis du in deiner Hauptschleife
die Auswertung beginnst ist der OVRCount hochgezählt worden

BSP.
Capture A= 49, CaptureB = 99, 50µs kein Overflow, aufgrund von verzug
bis in die Auswertung Overflow nun = 1
99-49 = 50 + (1*100) = 150 -> Falsch!

Um es abzukürzen:
Mino hat dir ein Link gepostet,schaue ihn dir an ich denke da kann
man vom prinzip her viel lernen.
Imho zeigt deine vorgehensweise lücken und tücken im Programm bin es 
aber
nur kurz überflogen, vor missintepretation bin ich auch nicht gefeit.

von Palmolive (Gast)


Lesenswert?

FloMann schrieb:
> Morgen,
>
> Zur Config interpretation:
> Timer 2 alle 1ms Overflow,in dessen
> Overflow ISR Callback alle 5 durchläufe
> ein Pin Toggle. Dies ergibt 100Hz,
> ist das die Frequenz die du aktuell an deinen Timer 3
> Capture Input zum Messen gibst?

Genau war zu Hause ohne Funktionsgenerator eine einfache Möglichkeit zum 
testen.
  Ich habe den Code so umgebaut am Sonntag
1
if (update == 1)
2
    {
3
      count++;
4
      printf("\n\r INA= %i INB= %i\n\r",inputCapture_A,inputCapture_B);
5
      zw_Erg = inputCapture_B - inputCapture_A;
6
      printf("\n\r zw= %li \n\r",zw_Erg);
7
      if (zw_Erg >= 0) // Überlauf erkennung
8
      {
9
        pw_us = zw_Erg; // erg = (B-A)
10
      }
11
      else
12
      {
13
        pw_us = zw_Erg + MAX_CNT; // erg=(max-A)+B = (B-A)+max
14
        overflow_cnt--;
15
        printf("\n\r else");
16
      }
17
      pw_us = pw_us + (overflow_cnt * MAX_CNT);
18
19
      pw_s = (double)pw_us / 1E6;
20
      frq_Hz = 1 / pw_s; // Frequenz in Hz
21
      printf("\n\rpw_us= %li, Frequenz = %04.2f Hz OV=%i count=%i\r\n", pw_us,frq_Hz,overflow_cnt,count );
22
      update = 0;
23
    }

Und auch mit dem Funktionsgenerator bis über 1KHZ keine Fehler und auch 
hinter dem Komma genau.
War das Zufall?

FloMann schrieb:
> 1.) In Main deine Auswertung:
> ZwErg = CapB - CapA
> deklariert als
> int32 =  uInt16 - uInt16
> wird nicht so funktionieren wie du dir das wünscht,
> weil hier i.r. keine negativen Zahlen rauskommen werden.
> uInt16 - uInt16 gibt dann zwar einen überlauf die Zahl
> ist dann aber immer Positiv und wird dann in dein ZwErg geschrieben.
> Sprich du landest immer in deinem ersten If Zweig der auswertung.
> z.B. uInt16 zuvor casten auf int32

Ist das dann wircklich so?

Danke für die Hilfe

von Palmolive (Gast)


Lesenswert?


von FloMann (Gast)


Angehängte Dateien:

Lesenswert?

Palmolive schrieb:
> FloMann schrieb:
>> 1.) In Main deine Auswertung:
>> ZwErg = CapB - CapA
>> deklariert als
>> int32 =  uInt16 - uInt16
>> wird nicht so funktionieren wie du dir das wünscht,
>> weil hier i.r. keine negativen Zahlen rauskommen werden.
>> uInt16 - uInt16 gibt dann zwar einen überlauf die Zahl
>> ist dann aber immer Positiv und wird dann in dein ZwErg geschrieben.
>> Sprich du landest immer in deinem ersten If Zweig der auswertung.
>> z.B. uInt16 zuvor casten auf int32
>
> Ist das dann wircklich so?
>
> Danke für die Hilfe

Ich kenne es so bei den von mir verwendeten Compiler.
C kümmert sich erstmal um die rechte seite von innen nach ausen.
Bsp siehe Bild, SDCC für 8051 Target.
Prüf es bei dir kostet keine Minute.

von FloMann (Gast)


Lesenswert?

Das mit dem Video hätte man auch so lösen können das
man die gesammte Ausgabe sehen kann.

Auffällig:
OV ist 0
Capture Werte sind über 2^16 verteilt.

Wenn dein Timer3 alle 100µs überläuft kann das bei einer
Frequenz mit 1280,554Hz(T~781µs) nur schwer hinkommen.

Mir fehlt dazu das wissen der genauen STM32 Timer funktionen.
Deine Capture Werte liegen auch nicht wie ich erst dachte nur
zwischen 0-99, Timer Up Count auf == Top Wert dann Autoreload und
von vorne(0).

Warum:
Bei Capture Events wird oft der Zählerstand in das Snapshot register
gespeichert, da Timer Config auf 100µs OVR Zyklus dachte ich es werden
auch nur Werte in dem Bereich gezählt und gecaptured, entweder 0-99 oder
von startwert 2^16-100 zum überlauf hin.

Da mir genaueres wissen zum STM32 Timer hier fehlt kann
ich nicht weiterhelfen.
Nur irgendwas ist da inkonsistent, entweder weißt du es
selbst nicht was du genau machst und/oder müsstest mal mit
einer genauen erklärung rausrücken.

Bei z.B. den Timern im EFM8 den ich vor mir hab, der zählt im Capture
Mode immer kommplett rundum durch, was eh sinn macht da der Overflow
dann das increment des lsb der oberen 2Byte sind(32Bit betrachtet).

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.