Mega16 Timer-Start/Stop für Geschwindigkeitsmessung

Gast #1613247
Lesenswert?

Hallo zusammen,
ich versuch mich schon seit Tagen an einer Geschwindigkeitsmessung mit 
einem mega16.
Es soll die Geschwindigkeit auf 5m berechnet und per rs232 aufn PC 
gegeben werden, allerdings wird hier nur 0.0000000 oder 65536.000 
gesendet...
Timer-Start mit PD2, Stopp mit PD3.
Auch nach einschlägigen Tipps hab ich nen Gerhirnknoten.
Kann mir jemand die betreffende Stelle coden?
Danke schonmal für die Hilfe,
Felix
1
  
2

3
volatile unsigned int  millisekunden;
4
volatile unsigned int sekunden;
5
volatile float geschw;
6
volatile unsigned int i;
7

8

9

10
int uart_putc (volatile char c)        
11
{
12
      while (!(UCSRA & (1<<UDRE)))  //warten 
13
    {
14
    }
15
 
16
    
17
 
18
    UDR = c;                      //senden
19
    return 0;
20
}
21

22

23
void uart_puts (char *s)   //string senden
24
{     
25
while (*s)     
26
  {   
27
   uart_putc(*s);         
28
   s++;     
29
  } 
30
}
31

32

33

34

35
int main(void)
36
{
37

38
 UCSRB |= (1<<TXEN);                // UART einschalten
39
    UCSRC |= (1<<URSEL)|(3<<UCSZ0);   
40
 
41
    UBRRH = UBRR_VAL >> 8;
42
    UBRRL = UBRR_VAL & 0xFF;
43
 DDRD &= ~(1 << PD3);
44
 DDRD |= (1<<PD5);
45
 int i;
46
 
47

48
  while(1)
49
  {
50
     
51
  
52

53
if (PIND & (1<<PD2))
54
{
55
// Global Interrupts aktivieren
56
  sei();
57
  // Timer 0 konfigurieren
58
  
59
  TCCR0 |= (1<<CS00)|(1<<CS01)|(1<<WGM01); // Prescaler 64 
60
  
61
  OCR0 = 250-1; 
62
 
63
 
64
TIMSK |= (1<<OCIE0);
65
}
66

67

68
if (PIND & (1<<PD3))
69
{
70
   
71
  
72
  geschw = 5 / ((millisekunden + sekunden*1000) * 3600) ;   //Ber.
73
  TIMSK &= ~(1<<OCIE0);
74
  cli ();
75
  
76
   char s[8]; 
77
   dtostrf( geschw , 6, 3, s ); 
78
   uart_puts( s );
79

80

81

82

83
  for (i=0;i<5;i++)
84
   {
85
   PORTD |= (1<<PD5);
86
   _delay_ms(100);                    //StatusLed
87
   PORTD &= ~(1<<PD5);
88
   _delay_ms(100);
89
   }
90
  }
91
  }
92
          }
93
   
94

95
// Compare Interrupt Handler 
96

97
ISR (TIMER0_COMP_vect)
98
{
99
  millisekunden++;
100
  if(millisekunden == 2000)
101
  {
102
    sekunden++;
103
    millisekunden = 0;
104
   
105
  }
106
}
Persönliche Seite #1613301
Lesenswert?

> volatile unsigned int millisekunden;
> volatile unsigned int sekunden;
> volatile float geschw;

Ändere diese Berechnung damit es keinen Integer-Überlauf gibt:

>   geschw = 5 / ((millisekunden + sekunden*1000) * 3600) ;   //Ber.

Z.B. Float Ergebnis = Float Zähler / Unsigned long Nenner

>   geschw = 5.0 / ((millisekunden + sekunden*1000UL) * 3600) ;   //Ber.
                                                  ^^

Die Berechnung kannst du mit gutem Gewissen nach dem Abschalten des 
Timers machen, dann brauchst du dich auch nicht um atomaren Zugriff auf 
millisekunden und sekunden zu kümmern (s. AVR-GCC-Tutorial Variablen 
> 1 Byte). geschw braucht nicht volatile zu sein.

Die Berechnung könntest du bei diesem Verfahren geringfühig genauer 
machen, wenn du den angebrochenen Zählerstand im TCNT0 Register 
berücksichtigst.

Vor dem Start des Timers würde ich noch millisekunden und sekunden 
nullen, wenn mehrere Messungen gemacht werden sollen.

Und ich würde dann auch Umordnen:
1
  // Timer 0 konfigurieren
2
  TCCR0 |= (1<<CS00)|(1<<CS01)|(1<<WGM01); // Prescaler 64 
3
  OCR0 = 250-1; 
4

5
  while(1)
6
  {
7
    if (PIND & (1<<PD2)) // *** Start ***
8
    {
9
      millisekunden = 0;
10
      sekunden = 0;
11
      TCNT0 = 0;
12
      TIMSK |= (1<<OCIE0);
13
      sei();
14
    }
15

16
    if (PIND & (1<<PD3)) // *** STOPP ***
17
    {
18
      cli ();
19
      TIMSK &= ~(1<<OCIE0);
20

21
      // Berechnen...
22
      geschw = 5.0 / ((millisekunden + sekunden*1000UL) * 3600) ;
23

24
      // Ausgabe...
25
      // ...
26
    }    
27
  }
28
}

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