Forum: Mikrocontroller und Digitale Elektronik Probleme bei Zeitmessung zwischen Interrupts mit STM32f107


von Jakub (Gast)


Angehängte Dateien:

Lesenswert?

Hallo!
Nach langer und erfolgloser Fehlersuche muss ich mich an euch um Hilfe 
wenden.
Ich versuche mithilfe eines STM32-f107 uC, einer Zahnscheibe und eines 
Hall-Sensors die Drehzahl eines Rades zu bestimmen. Der Hallsensor geht 
auf High sobald ein Zahn vor ihm vorbeiläuft und löst einen Interrupt 
aus. Mithilfe eines Hardware-Timers soll dann die Zeit zwischen zwei 
solchen Interrupts gemessen und in eine Raddrehzahl umgerechnet werden.

Im jetzigen Versuchsaufbau wird dieses Signal mit einem sauberen PWM 
Signal mit konstaner Frequenz von 100 Hz (resultierend in einer 
soll-Raddrehzahl von 300) simuliert. Der Microcontroller zeigt jedoch 
das Verhalten wie auf dem beigefügten Bild: Ausreißer zum Wert 150 
deuten auf verpasste Signalflanken hin, die Ausreißer zur 0 kann ich mir 
nicht erklären, da diese sehr hohe werte im Timer-Register bedeuten. 
Weitere Anomalien mit Ausschlägen nach oben treten ebenfalls auf. Das 
ganze lässt mich Vermuten es handle sich um ein Problem mit der Abfolge 
der Interrupt Ausführung, mein Wissen reicht jedoch nicht bis zu einer 
Lösung. Ich hoffe jemand kann mir dabei behilflich sein. Als Referenz 
poste ich auch den benutzen Code. Vielen Dank!
1
#include "blink.h"
2
3
#include "stm32f10x_it.h"
4
#include "stm32f10x_conf.h"
5
#include "stm32f10x_adc.h"
6
#include "stm32f10x_can.h"
7
#include "stm32f10x_rcc.h"
8
#include "stm32f10x_dma.h"
9
#include "stm32f10x_can.h"
10
#include "misc.h"
11
#include "can_handling.h"
12
13
14
uint32_t sysTick_counter = 0;
15
uint32_t last_exti9 = 0;
16
uint32_t last_exti10 = 0;
17
uint32_t time_exti9 = 0;
18
uint32_t time_exti10 = 0;
19
20
void SysTick_Handler(void){
21
  sysTick_counter++;
22
}
23
24
void revolutionCounter_InitGPIO(void)
25
{
26
  GPIO_InitTypeDef GPIO_InitStructure;
27
28
  //RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);
29
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD | RCC_APB2Periph_AFIO, ENABLE);
30
31
  //GPIOC Initilization
32
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //GPIO_Mode_IN_FLOATING
33
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;
34
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
35
  GPIO_Init(GPIOD, &GPIO_InitStructure);
36
}
37
38
39
void revolutionCounter_InitEXTI(void)
40
{
41
  EXTI_InitTypeDef EXTI_InitStructure;
42
43
  //Init EXTI
44
  EXTI_InitStructure.EXTI_Line = EXTI_Line9;
45
  EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
46
  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
47
  EXTI_InitStructure.EXTI_LineCmd = ENABLE;
48
  EXTI_Init(&EXTI_InitStructure);
49
50
  //Second time for Line10?
51
  EXTI_InitStructure.EXTI_Line = EXTI_Line10; //The rest should stay the same?
52
  EXTI_Init(&EXTI_InitStructure);
53
54
  //Connect GPIO to EXTI
55
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOD, GPIO_PinSource9); //left
56
  GPIO_EXTILineConfig(GPIO_PortSourceGPIOD, GPIO_PinSource10); //right
57
}
58
59
void revolutionCounter_InitNVIC(void)
60
{
61
  NVIC_InitTypeDef NVIC_InitStructure;
62
63
  //Init NVIC
64
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
65
66
  NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;
67
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
68
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00;//0xBF;
69
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0F;
70
  NVIC_Init(&NVIC_InitStructure);
71
72
  //Second time for line10?
73
  NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;
74
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
75
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00; //0xBF;
76
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x0F;
77
  NVIC_Init(&NVIC_InitStructure);
78
}
79
80
void revolutionCounter_initTim() //TODO: TIM2 und 4
81
{
82
  //Setup hardware timer 2
83
  TIM_DeInit(TIM2);
84
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
85
  TIM_TimeBaseInitTypeDef timer_init_struct2;
86
  timer_init_struct2.TIM_Prescaler = 36000;
87
  timer_init_struct2.TIM_CounterMode = TIM_CounterMode_Up;
88
  timer_init_struct2.TIM_Period = 10000; //divide by 2?!
89
  timer_init_struct2.TIM_ClockDivision = TIM_CKD_DIV2;
90
  timer_init_struct2.TIM_RepetitionCounter = 0;
91
  //TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update);
92
  TIM_TimeBaseInit(TIM2, &timer_init_struct2);
93
94
  NVIC_InitTypeDef tim2_it_struct;
95
96
  TIM_Cmd(TIM2, ENABLE);
97
98
  //TIM 4
99
  TIM_DeInit(TIM4);
100
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
101
  TIM_TimeBaseInitTypeDef timer_init_struct4;
102
  timer_init_struct4.TIM_Prescaler = 36000;
103
  timer_init_struct4.TIM_CounterMode = TIM_CounterMode_Up;
104
  timer_init_struct4.TIM_Period = 10000;
105
  timer_init_struct4.TIM_ClockDivision = TIM_CKD_DIV2;
106
  timer_init_struct4.TIM_RepetitionCounter = 0;
107
  //TIM_SelectOutputTrigger(TIM4, TIM_TRGOSource_Update);
108
  TIM_TimeBaseInit(TIM4, &timer_init_struct4);
109
110
  NVIC_InitTypeDef tim4_it_struct;
111
112
  TIM_Cmd(TIM4, ENABLE);
113
114
  //TIM_SetCounter wenn zeit ausgelesen
115
  //TIM_GetCounter() to get it
116
117
}
118
119
void EXTI9_IRQHandler(void){
120
  uint32_t now = TIM_GetCounter(TIM2);
121
  if(GPIO_ReadInputDataBit(GPIOD, GPIO_PinSource10)){
122
    time_exti9 = now;
123
//    time_exti9 = now-last_exti9;
124
125
    //last_exti9 = now;
126
    TIM_SetCounter(TIM2, (uint16_t) 0);
127
  }
128
129
  EXTI_ClearITPendingBit(EXTI_Line9);
130
}
131
132
void EXTI10_IRQHandler(void){
133
134
  uint32_t now = sysTick_counter;
135
  if(GPIO_ReadInputDataBit(GPIOD, GPIO_PinSource10)){
136
    time_exti10 = now-last_exti10;
137
    last_exti10 = now;
138
  }
139
  EXTI_ClearITPendingBit(EXTI_Line10);
140
141
}
142
void usb_lp_can_rx0_isr(void){}
143
void can2_rx0_isr(void){}
144
145
int main(void)
146
{
147
148
  ///////*General Controller Initialization *///////
149
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
150
  SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);
151
  SysTick_Config(9000);
152
153
  volatile uint32_t now = sysTick_counter;
154
  while ((sysTick_counter - now) <= 10){
155
    __asm__ volatile ("nop");
156
  }
157
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN2, ENABLE);
158
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
159
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //GPIOB
160
  blink_setup();
161
  can_setup();
162
163
  revolutionCounter_InitGPIO();
164
  revolutionCounter_InitNVIC();
165
  revolutionCounter_InitEXTI();
166
  revolutionCounter_initTim();
167
168
  uint32_t last_sent = 0xFFFF;
169
170
  CanTxMsg revCounter_sensorData1;
171
  revCounter_sensorData1.StdId = 0x390;
172
  revCounter_sensorData1.ExtId = 0;
173
  revCounter_sensorData1.IDE = CAN_Id_Standard;
174
  revCounter_sensorData1.RTR = CAN_RTR_DATA;
175
  revCounter_sensorData1.DLC = 8;
176
177
  for(;;){
178
179
    if (sysTick_counter - last_sent > 10){
180
      int32_t revCounter_resultLeft = 60000 / (time_exti9 * 20);
181
      int32_t revCounter_resultRight = 60000 / (time_exti10 * 20);
182
183
      revCounter_sensorData1.Data[0] = (uint8_t) (revCounter_resultLeft);
184
      revCounter_sensorData1.Data[1] = (uint8_t) (revCounter_resultLeft >> 8);
185
      revCounter_sensorData1.Data[2] = (uint8_t) (revCounter_resultLeft >> 16);
186
      revCounter_sensorData1.Data[3] = (uint8_t) (revCounter_resultLeft >> 24);
187
      revCounter_sensorData1.Data[4] = (uint8_t) (revCounter_resultRight);
188
      revCounter_sensorData1.Data[5] = (uint8_t) (revCounter_resultRight >> 8);
189
      revCounter_sensorData1.Data[6] = (uint8_t) (revCounter_resultRight >> 16);
190
      revCounter_sensorData1.Data[7] = (uint8_t) (revCounter_resultRight >> 24);
191
192
      if (revCounter_resultLeft <= 150){
193
        uint32_t dummy = 0xBEEF;
194
      }
195
196
      CAN_Transmit(CAN2, &revCounter_sensorData1);
197
      last_sent = sysTick_counter;
198
    }
199
  }
200
}

von STK500-Besitzer (Gast)


Lesenswert?

Warum verwendest du nicht einfach die Input-Capture-Unit des Timers?

von Jakub (Gast)


Lesenswert?

Hatte ich um ehrlich zu sein nicht auf dem Schirm. Werde das als 
nächstes versuchen, allerdings würde ich auch gerne wissen wo der Fehler 
in meinem Code liegt, weil das etwas mittlerweile etwas frustrierend ist 
die Fehlerursache nicht zu kennen :D

von Thomas E. (picalic)


Lesenswert?

Servus,

sollte das if() im EXTI9_IRQHandler nicht PD9 auf high testen? Sieht 
nach einem typischen "Copy+Paste" Fehler aus...

Die Variablen, die in der ISR verändert werden und in main gelesen 
werden, solltest Du als volatile deklarieren. Sonst könnte der Compiler 
z.B. auf die Idee kommen, time_exti9 einmal vor der Endlosschleife in 
ein Register zu laden und dann nur mit diesem Register zu arbeiten. Die 
ISR schreibt aber in das für time_exti9 reservierte RAM.

von Jakub (Gast)


Lesenswert?

Ja das müsste es tatsächlich, praktisch macht es aber keinen 
unterschied, D10 war auf permament auf High und das Bild sieht genauso 
aus.

von Jakub (Gast)


Lesenswert?

Die Variablen auf volatile zu setzen macht ebenfalls keinen Unterschied

von Thomas F. (igel)


Lesenswert?

So aus eigener Erfahrung:
Auf einem Atmega16 habe ich sowas ähnliches in Assembler am laufen. Dort 
mit Input Capture Interrupt. Funktioniert gut...

Die Elektronik des Sensors muss natürlich erst mal passen. Wenn die 
schon zwischendrin zusätzliche kurze Spikes erzeugt und eben keine 
sauberen Flanken so hat man gleich mal eine unangenehme Störquelle. Also 
erst mal mit dem Oszi den Signalpfad ansehen ob dort alles passt.

Zur Auswertung des Timer-Counters in der Software: Die Drehzahl bzw. 
schon der Counterwert ändert sich zwischen zwei Impulsen einer 
Zahnscheibe nicht abrupt um den doppelten Wert. Ich vergleiche in meiner 
Software daher den neuen Wert mit dem letzten Wert des Counters. Ist der 
Unterschied größer als 25% so liegt ein Messfehler vor und der neue Wert 
kann gleich verworfen 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.