Probleme bei Zeitmessung zwischen Interrupts mit STM32f107

Gast #5446872
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
}
Angehängte Dateien:
Gast #5446902
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
#5446997
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.
#5447943
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren