Forum: Mikrocontroller und Digitale Elektronik Zeitmessung mit XMEGA


von Dominik G. (grosdode)


Lesenswert?

Hallo zusammen,
ich würde gerne eine Zeitmessung mit meinen XMEGA32E5 realisieren, um 
eine Distanzmessung auszuwerten. Die Distanzmessung soll mit einem 
Ultraschall Modul realisiert werden. Ich arbeite bei dem XMEGA mit 32MHz 
und möchte Zeiten von 10µs bis 200ms messen
http://www.mikrocontroller.net/attachment/218122/HC-SR04_ultraschallmodul_beschreibung_3.pdf
Leider ist mir nicht ganz klar wie ich diese Messung am genausten 
realisiere.

1.Möglichkeit:
Steigende Flanke bzw logisches high mit Interrupt detektieren und Timer 
starten
Fallende Flanke bzw logisches low mit Interrupt detektieren und 
Timerwert auslesen

2.Möglichkeit:
Nutzen der Capture channes des XMEGA's hierzu wird in Datenblatt unter 
anderen eine Pulsweitenmessung erwähnt, die ich jedoch noch nicht ganz 
verstanden habe.

Hat noch jemand eine andere Idee bzw. schon mal etwas ähnliches 
realisiert?

(Ich weiß das diese Module für den Arduino gedacht sind, möchte aber 
keinen Arduino nutzen)

von Knut B. (Firma: TravelRec.) (travelrec) Benutzerseite


Lesenswert?

2. Möglichkeit. Das kann der XMEGA besonders komfortabel.

Hier mal ein Beispielsetup. Parallel dazu muss der betreffende Interrupt 
behandelt werden, um die Messwerte abzuholen. Jede steigende Flanke 
startet die Messung, die fallende stoppt und trägt das Messergebnis in 
das Capture-Register ein.
1
;--------------------------
2
;TimerC5
3
;Debug pulse capturing
4
 ldi  Temp, 0xFF           
5
 ldi  TempH, 0xFF
6
 sts  TCC5_PER, Temp
7
 sts  TCC5_PER+1, TempH
8
 
9
 ldi  Temp, TC45_CCBMODE_CAPT_gc | TC45_CCAMODE_CAPT_gc    ;capture B and capture A enabled
10
 sts  TCC5_CTRLE, Temp
11
 ldi  Temp, TC45_EVACT_PWF_gc | TC45_EVSEL_CH0_gc    ;Pulse-width / Frequency Capture, Event Channel 0
12
 sts  TCC5_CTRLD, Temp
13
14
 ldi  Temp, 0b00000110                ;Prescaler 256
15
 sts  TCC5_CTRLA, Temp
16
 ldi  Temp, TC45_CCBINTLVL_LO_gc            ;Low Level compare interrupt enabled
17
 sts  TCC5_INTCTRLB, Temp
18
19
20
;setup EventSystem
21
 ldi  Temp, 0b01010110                ;PortA6 as EventCh0 input
22
 sts  EVSYS_CH0MUX, Temp

von Dominik G. (grosdode)


Lesenswert?

Ich hab mal versucht die Sache in C zu übersetzen

1
void initTimer5AsCapture();
2
{
3
  TCC5.PER = 0xFFFF;
4
  
5
  TCC5.CTRLE = TC45_CCBMODE_CAPT_gc
6
             | TC45_CCAMODE_CAPT_gc;
7
         
8
  TCC5.CTRLD = TC45_EVACT_PWF_gc
9
             | TC45_EVSEL_CH0_gc;
10
         
11
  TCC5.CTRLA = TC45_CLKSEL_DIV256_gc;
12
  
13
  TCC5.INTCTRLB = TC45_CCBINTLVL_LO_gc;
14
  
15
  EVSYS.CH0MUX = EVSYS_CHMUX_PORTA_PIN6_gc;
16
}


oder für Timer 4 etwas abgewandelt:

1
void initTimer4AsCapture();
2
{
3
  TCC5.PER = 0xFFFF;
4
  
5
  TCC4.CTRLA = TC4_SYNCHEN_bm 
6
             | TC4_EVSTART_bm 
7
             | TC45_CLKSEL_DIV1_gc;
8
  
9
  TCC4.CTRLD = TC45_EVACT_PWF_gc
10
             | TC45_EVSEL_CH0_gc;
11
         
12
  TCC4.CTRLE = TC45_CCAMODE_CAPT_gc;
13
  
14
  TCC4.INTCTRLB = TC45_CCAINTLVL_LO_gc;
15
  
16
  EVSYS.CH0MUX = EVSYS_CHMUX_PORTA_PIN0_gc;
17
}



Im Interrupt muss ich dann nur noch das richtige Register auslesen und 
in dem steht dann der Wert für die Zeit?

von Dominik G. (grosdode)


Lesenswert?

Der Code oben hat noch ein oder zwei kleine Probleme. Falls jemand ein 
ähnliches Problem hat könnte ihm mein fertiger Code vielleicht helfen.
(Das Programm ist für das XMEGA-E5 Xplained Board geschrieben)
1
#define F_CPU 32000000
2
#include <avr/io.h>
3
#include "clksys_driver.h"
4
#include <asf.h>
5
6
#include <stdlib.h>
7
8
void clock32M(void);  
9
void initTimer4AsCapture(void);
10
void initTimer5AsCapture(void);
11
12
13
14
volatile uint16_t timer4_value = 0;
15
volatile uint8_t timer4_Flag = 0;
16
volatile uint16_t timer5_value = 0;
17
volatile uint8_t timer5_Flag = 0;
18
19
20
/*! Channel B Compare or Capture Interrupt
21
 *
22
 *  This function handles the Channel B Compare or Capture Interrupt
23
 *
24
 */
25
ISR (TCC4_CCB_vect)
26
{
27
  timer4_Flag = 1;
28
  timer4_value = TCC4.CCB;
29
}
30
31
32
/*! Channel B Compare or Capture Interrupt
33
 *
34
 *  This function handles the Channel B Compare or Capture Interrupt
35
 *
36
 */
37
ISR (TCC5_CCB_vect)
38
{
39
  timer5_Flag = 1;
40
  timer5_value = TCC5.CCB;
41
}
42
43
void initTimer4AsCapture()
44
{
45
  TCC4.PER = 0xFFFF;
46
  
47
  TCC4.CTRLA = TC4_SYNCHEN_bm
48
  | TC4_EVSTART_bm
49
  | TC45_CLKSEL_DIV64_gc;
50
  
51
  TCC4.CTRLD = TC45_EVACT_PWF_gc
52
  | TC45_EVSEL_CH0_gc;
53
  
54
  TCC4.CTRLE = TC45_CCAMODE_CAPT_gc
55
  | TC45_CCBMODE_CAPT_gc;
56
  
57
  TCC4.INTCTRLB = TC45_CCBINTLVL_MED_gc;
58
  
59
  PMIC.CTRL |= PMIC_MEDLVLEN_bm;
60
  
61
  EVSYS.CH0MUX = EVSYS_CHMUX_PORTA_PIN0_gc;
62
}
63
64
65
void initTimer5AsCapture()
66
{
67
  TCC5.PER = 0xFFFF;
68
  
69
  TCC5.CTRLE = TC45_CCBMODE_CAPT_gc
70
  | TC45_CCAMODE_CAPT_gc;
71
  
72
  TCC5.CTRLD = TC45_EVACT_PWF_gc
73
  | TC45_EVSEL_CH0_gc;
74
  
75
  TCC5.CTRLA = TC5_SYNCHEN_bm
76
  | TC5_EVSTART_bm
77
  | TC45_CLKSEL_DIV256_gc;
78
  
79
  TCC5.INTCTRLB = TC45_CCBINTLVL_LO_gc;
80
  
81
  PMIC.CTRL |= PMIC_LOLVLEN_bm;
82
  
83
  EVSYS.CH0MUX = EVSYS_CHMUX_PORTA_PIN0_gc;
84
}
85
86
87
/*! Clock initial
88
 *
89
 *  This function initial the 32MHz Clock for the µC
90
 *
91
 */
92
void clock32M(void)
93
{
94
  /*  Enable internal 32 MHz ring oscillator and wait until it's
95
  *  stable. Set the 32 MHz ring oscillator as the main clock source.
96
  *  Then disable the other oscillators.
97
  */
98
  CLKSYS_Enable( OSC_RC32MEN_bm );
99
  do {} while ( CLKSYS_IsReady( OSC_RC32MRDY_bm ) == 0 );
100
  CLKSYS_Main_ClockSource_Select( CLK_SCLKSEL_RC32M_gc );
101
  CLKSYS_Disable( OSC_RC2MEN_bm | OSC_RC32KEN_bm );
102
}
103
104
int main(void)
105
{
106
  long double distance4 = 0;
107
  long double distance5 = 0;
108
  uint32_t d4 = 0;
109
  uint32_t d5 = 0;
110
  uint8_t count = 0;
111
  char buf4[5];
112
  char buf5[5];
113
  
114
  cli();
115
  
116
  clock32M();
117
  initTimer4AsCapture();
118
  initTimer5AsCapture();
119
  
120
  sei();
121
  
122
  PORTA.DIRSET = PIN1_bm;  // Ausgang
123
  PORTA.DIRCLR = PIN0_bm;  // Eingang
124
  
125
  PORTA.OUTSET = PIN1_bm;
126
  
127
  board_init();
128
  gfx_mono_init();
129
  
130
  _delay_ms(500);
131
  
132
  while (true)
133
  {
134
    
135
    PORTA.OUTCLR = PIN1_bm;
136
    _delay_us(20);
137
    PORTA.OUTSET = PIN1_bm;
138
    
139
    while(!timer4_Flag || !timer5_Flag){}
140
    timer4_Flag = 0;
141
    timer5_Flag = 0;
142
    
143
    distance4 = ((64*(long double)timer4_value)/64000)*343;
144
    distance5 = ((256*(long double)timer5_value)/64000)*343;
145
    
146
    count ++;
147
    
148
    d4 += distance4;
149
    d5 += distance5;
150
    
151
    if (count > 2)
152
    {
153
      count = 0;
154
      
155
      d4 = d4/3;
156
      d5 = d5/3;
157
      
158
      itoa(d4,buf4,10);
159
      itoa(d5,buf5,10);
160
      
161
      gfx_mono_draw_string("    mm", 0, 0, &sysfont);
162
      gfx_mono_draw_string("    mm", 0, 10, &sysfont);
163
      gfx_mono_draw_string(buf4, 0, 0, &sysfont);
164
      gfx_mono_draw_string(buf5, 0, 10, &sysfont);
165
    }
166
        
167
    _delay_ms(200);
168
    }
169
}

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.