Forum: Mikrocontroller und Digitale Elektronik Problem Erweiterung 16 bit Timer beim STM32F3 für IC


von R. H. (breezer)


Lesenswert?

Ich möchte Flanken von zwei gleichen Sensoren messen. Dafür nutze ich 
den Timer2 (32 bit) und den Timer3 (16 bit), die Timer laufen mit 64Mhz 
(Systemtakt)
Beim 32 bit Timer klappt alles wie vorgesehen, nur beim 16 bit Timer 
treten Fehlmessungen aufgrund der Erweiterung auf 32 bit auf.

Das Problem liegt meines erachtens dran das ein Timerüberlauf statt 
findet währen der Interrupt Change aufgerufen wird.
Der IC Wert ist dann noch beim kleineren "High-int" gecaptured worden 
aber zwischenzeitlich ist nun der Timer übergelaufen.

Wie kann ich diese Situation sinnvoll abfangen?
1
/**
2
* @brief This function handles TIM2 global interrupt.
3
*/
4
void TIM2_IRQHandler(void)
5
{
6
  /* USER CODE BEGIN TIM2_IRQn 0 */
7
8
  if(__HAL_TIM_GET_FLAG(&htim2, TIM_FLAG_CC4) == SET )
9
      {
10
11
      __HAL_TIM_CLEAR_FLAG(&htim2, TIM_FLAG_CC4);
12
13
        if(HAL_COMP_GetOutputLevel(&hcomp2) == COMP_OUTPUTLEVEL_HIGH)
14
        {
15
          T_total_ch1 = (__HAL_TIM_GET_COMPARE(&htim2, TIM_CHANNEL_4) - T_rising_edge_ch1);
16
          T_rising_edge_ch1 = __HAL_TIM_GET_COMPARE(&htim2, TIM_CHANNEL_4);
17
          timeout_ch1 = 0;
18
        }
19
        else if(HAL_COMP_GetOutputLevel(&hcomp2) == COMP_OUTPUTLEVEL_LOW)
20
        {
21
          T_high_ch1 = (__HAL_TIM_GET_COMPARE(&htim2, TIM_CHANNEL_4) - T_rising_edge_ch1);
22
        }
23
24
25
        if(T_high_ch1 < T_high_55 )                        // under 55µs -> forward rotation
26
        {
27
          period_ch1 = T_total_ch1;
28
          direction_ch1 = 0;
29
          //low_value++;
30
        }
31
        else if( (T_high_ch1 > T_high_70) && (T_high_ch1 < T_high_110) )    // between 70µs and 110µs -> reverse rotation
32
        {
33
          period_ch1 = T_total_ch1;
34
          direction_ch1 = 1;
35
          //mid_value++;
36
        }
37
        else if(T_high_ch1 > T_high_145)                    //over 145µs -> unknown rotation
38
        {
39
          period_ch1 = 0;
40
          direction_ch1 = 0;
41
          //high_value++;
42
        }
43
44
      }
45
46
  /* USER CODE END TIM2_IRQn 0 */
47
  HAL_TIM_IRQHandler(&htim2);
48
  /* USER CODE BEGIN TIM2_IRQn 1 */
49
50
  /* USER CODE END TIM2_IRQn 1 */
51
}
52
53
/**
54
* @brief This function handles TIM3 global interrupt.
55
*/
56
void TIM3_IRQHandler(void)
57
{
58
  /* USER CODE BEGIN TIM3_IRQn 0 */
59
60
    if(__HAL_TIM_GET_FLAG(&htim3, TIM_FLAG_UPDATE) == SET )
61
    {
62
      timer32b.int16b[1]++ ;
63
      __HAL_TIM_CLEAR_FLAG(&htim3, TIM_FLAG_UPDATE);
64
    }
65
66
67
    if(__HAL_TIM_GET_FLAG(&htim3, TIM_FLAG_CC1) == SET )
68
        {
69
70
        __HAL_TIM_CLEAR_FLAG(&htim3, TIM_FLAG_CC1);
71
72
73
        timer32b.int16b[0] =  __HAL_TIM_GET_COMPARE(&htim3, TIM_CHANNEL_1);
74
75
76
          if(HAL_COMP_GetOutputLevel(&hcomp4) == COMP_OUTPUTLEVEL_HIGH)
77
          {
78
            T_total_ch2 = timer32b.int32b - T_rising_edge_ch2;
79
            T_rising_edge_ch2 = timer32b.int32b;
80
            timeout_ch2 = 0;
81
          }
82
          else
83
          {
84
            T_high_ch2 = timer32b.int32b - T_rising_edge_ch2;
85
          }
86
87
88
          if(T_high_ch2 < T_high_55 )                        // under 55µs -> forward rotation
89
          {
90
            period_ch2 = T_total_ch2;
91
            direction_ch2 = 0;
92
            low_value++;
93
          }
94
          else if( (T_high_ch2 > T_high_70) && (T_high_ch2 < T_high_110) )    // between 70µs and 110µs -> reverse rotation
95
          {
96
            period_ch2 = T_total_ch2;
97
            direction_ch2 = 1;
98
            mid_value++;
99
          }
100
          else if(T_high_ch2 > T_high_145)                    //over 145µs -> unknown rotation
101
          {
102
            period_ch2 = 0;
103
            direction_ch2 = 0;
104
            high_value++;
105
          }
106
107
       }
108
109
  /* USER CODE END TIM3_IRQn 0 */
110
  HAL_TIM_IRQHandler(&htim3);
111
  /* USER CODE BEGIN TIM3_IRQn 1 */
112
113
  /* USER CODE END TIM3_IRQn 1 */
114
}

: Bearbeitet durch User
von m.n. (Gast)


Lesenswert?

Ein Beispiel, wie man die Überläufe handhaben kann: 
Beitrag "reziproker Frequenzzähler mit STM32F4Discovery"
Es wird Timer9 verwendet und die Überläufe werden in der zugehörigen ISR 
bearbeitet.
Dein Programm habe ich nicht verstanden, aber grundsätzlich sollte man 
auch bei 32-Bit Timern die Überläufe korrekt behandeln.

von R. H. (breezer)


Lesenswert?

Danke für die Antwort.

Zum Verständnis halber:

es handelt sich um einen Code zur Auswertung zweier Hallgeber (ATS692). 
Die Sensoren geben pro Flanke einen Impuls ab, die Dauer des Impulses 
gibt die Drehrichtung an. Die Sensoren geben ein Stromsignal aus welches 
über einen 100 Ohm Widerstand an den zwei Komperatoren des STM32 
ausgewertet wird (low->0,7v high->1,3v)

Die Komperatoren leiten ihren Ausgang auf die Captureeingänge der beiden 
Timer.

Der Code wertet nun anhand der High-Zeit der Pulse die Drehrichtung und 
der Zeit zwischen den steigenden Flanken die Rotationsgeschwindigkeit 
aus.

Beim Timer2 (32bit) funktioniert alles fehlerfrei.

Ich habe deinen Code zur Überlauferkennung in meinen Code eingepflegt, 
leider ohne Erfolg.

Bei 64Mhz Timertakt treten noch immer recht häufig Zählfehler auf, setze 
ich den Timertakt auf 16Mhz runter treten nur noch gelegentlich Fehler 
auf (~1 Fehler pro Minute)

Zum Testen habe ich die Komperatorausgänge an den Timern mal getauscht 
mit dem Ergebnis das es nicht an den Sensoren oder Komperatoren liegt 
sondern an der Auswertung im Timer3.
1
extern volatile union {
2
  uint32_t int32b;
3
  uint16_t int16b[2];
4
} timer32b;
1
/**
2
* @brief This function handles TIM3 global interrupt.
3
*/
4
void TIM3_IRQHandler(void)
5
{
6
  /* USER CODE BEGIN TIM3_IRQn 0 */
7
8
    if(TIM3->SR & TIM_SR_CC1IF)
9
        {
10
11
        TIM3->SR = ~TIM_SR_CC1IF;
12
        timer32b.int16b[0] = TIM3->CCR1;;
13
        timer32b.int16b[1] = overflow;
14
15
        if((TIM3->SR & TIM_SR_UIF) && (timer32b.int16b[0] < 0x8000))                // evtl. Ueberlauf T3 noch offen?
16
        {
17
          timer32b.int16b[1]++;
18
19
        }
20
21
22
23
          if(HAL_COMP_GetOutputLevel(&hcomp4) == COMP_OUTPUTLEVEL_HIGH)
24
          {
25
            T_total_ch2 = timer32b.int32b - T_rising_edge_ch2;
26
            T_rising_edge_ch2 = timer32b.int32b;
27
            timeout_ch2 = 0;
28
          }
29
          else
30
          {
31
            T_high_ch2 = timer32b.int32b - T_rising_edge_ch2;
32
          }
33
34
35
36
          if(T_high_ch2 < T_high_55_ch2 )                              // under 55µs -> forward rotation
37
          {
38
            period_ch2 = T_total_ch2;
39
            direction_ch2 = 0;
40
            //low_value++;
41
          }
42
          else if( (T_high_ch2 > T_high_70_ch2) && (T_high_ch2 < T_high_110_ch2) )        // between 70µs and 110µs -> reverse rotation
43
          {
44
            period_ch2 = T_total_ch2;
45
            direction_ch2 = 1;
46
            //mid_value++;
47
          }
48
          else if (T_high_ch2 > T_high_145_ch2)        //over 145µs -> unknown rotation
49
          {
50
            period_ch2 = 0;
51
            direction_ch2 = 0;
52
            //high_value++;
53
            //test = timer32b.int16b[0];
54
          }
55
56
        }
57
58
59
      if(TIM3->SR & TIM_SR_UIF)
60
      {
61
            TIM3->SR = ~TIM_SR_UIF;
62
            overflow++;
63
      }
64
65
  /* USER CODE END TIM3_IRQn 0 */
66
  HAL_TIM_IRQHandler(&htim3);
67
  /* USER CODE BEGIN TIM3_IRQn 1 */
68
69
  /* USER CODE END TIM3_IRQn 1 */
70
}

: Bearbeitet durch User
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.