Forum: Mikrocontroller und Digitale Elektronik Servomessung ungenau ( toggelt)


von M. H. (dbzwerg)


Lesenswert?

Hallo,

mit folgendem code versuche ich zwei Servosignale vom meinem RC 
Empfänger mit meinem atmega8 zu messen
1
// Aktion bei Interrupt INT0
2
 ISR(INT0_vect) 
3
  {
4
  
5
    if ((PIND & (1<<PD2))) // Abfrage ob Servo1 Signal high
6
       
7
       {
8
       
9
       buffer1_start = (servo1_overflow_count * 100)+TCNT0; // Berechnung des Startzählers
10
       
11
       
12
             }
13
    else
14
              {
15
        
16
      
17
      
18
      buffer1_end = ((servo1_overflow_count +1) * 100)+TCNT0;  //Berechnung des Endzählers
19
        servo1_in = buffer1_end - buffer1_start;           // Berechnung der Servo ti Zeit
20
        servo1_overflow_count = 0;                   // Reset Overflow Counter
21
      timestamp |= ((1 << 6));                  // Setzen des Bits in Timestamp Byte bei fallende Flanke an Int0
22
      GICR &= (~(1<<INT0));                 // INT0 DEaktivieren
23
      GICR |= (1<<INT1);                       // INT1 aktivieren
24
      
25
              }
26
    
27
  }
28
  
29
// Aktion bei Interrupt INT1
30
 ISR(INT1_vect) 
31
  {
32
    
33
    if ((PIND & (1<<PD3))) // Abfrage ob Servo2 Signal high
34
       
35
       {
36
PORTC |= (1 << PC3 ); // Schaltet das Abblendlicht ein         
37
         buffer2_start = (servo2_overflow_count * 100)+TCNT0; // Berechnung des Startzählers
38
PORTC &= ~((1 << PC3 )); //Abblendlicht ausschalten
39
           }
40
    else
41
             {
42
          buffer2_end = ((servo2_overflow_count +1) * 100)+TCNT0;//Berechnung des Endzählers
43
          servo2_in = buffer2_end - buffer2_start; // Berechnung der Servo ti Zeit
44
          servo2_overflow_count = 0; // Reset Overflow Counter
45
          timestamp |= ((1 << 7)); // Setzen des BIts in Tiemstamp Byte bei fallende Flanke an Int1
46
              GICR &= (~(1<<INT1)); // INT1 deaktivieren
47
    GICR |= (1<<INT0); // INT0 aktivieren
48
      
49
      }
50
    
51
  }

Diese ermittelten werte gebe ich dann an meine hardware pwm weiter.

Leider merke ich das der an dem PWM ausgang angeschlossene Servo 
"zittert".
Eine Messung mit nem oscar hat ergeben, dass das erzeugte PWM Signal um 
ca. +/- 250µs toggelt.

Wenn ich nun der HArdware PWM einen festen wert vorgebe ist dies nicht 
der fall und der servo bleibt ruhig.

Daraus schließe ich das es an der oben geposteten signalerfassung liegen 
muss.

Habe auch die benötigte ZEit für die Befehle bei steigender bzw. 
fallender flanke gemessen, sie liegen bei ca. 3,5µs , d.h. daran kann es 
nicht liegen.

Hoffe auf eure Hilfe!

MFG

von Rolf M. (rmagnus)


Lesenswert?

M. H. schrieb:
> Eine Messung mit nem oscar hat ergeben, dass das erzeugte PWM Signal um
> ca. +/- 250µs toggelt.

Passiert das nur ab und zu mal ganz kurz oder dauernd?
Was mir auffallen würde:
1
 buffer1_start = (servo1_overflow_count * 100)+TCNT0; // Berechnung des Startzählers
da hast du nicht bedacht, was passiert, wenn dein Timer überläuft, 
während du gerade in einer der Pin-ISRs bist. Dann ist dein 
overflow_count nämlich noch nicht inkrementiert, aber TCNT0 hat wieder 
bei 0 angefangen. Und wenn du dann noch deinen overflow_count auf 0 
setzt, nachdem ein noch nicht behandelter Overflow aufgetreten ist, wird 
dieser danach sofort von der Timer-ISR inkrementiert, und du rechnest 
dann mit einem Overflow zuviel weiter.

von M. H. (dbzwerg)


Lesenswert?

Stimmt daran hab ich garnicht gedacht....aber wie könnte ich das lösen?

Das würde auch die ca.220-270 µs erklären (timer ist auf 100µs 
konfiguriert)

von Stefan (Gast)


Lesenswert?

Hallo,
schau dir mal den Capture Compare Mode im DB an. Du triggerst auf die 
Positive Flanke, schaltest auf die Erkennung der negativen Flanke um und 
list anschließend den Registerwert aus.
Somit kannst du exakt deine Impulslänge bestimmen, ohne dir Gedanken 
darüber machen zu müssen, ob dir irgendein Timer überläuft.

Gruß
Stefan

von Stefan (Gast)


Lesenswert?

Sorry, ist natürlich der "input compare" Mode. Signal gehört an den 
"ICP"-Pin!

Gruß
Stefan

von M. H. (dbzwerg)


Lesenswert?

Erstmal danke für die Antworten...leider aknn ich den ICP pin nicht 
benutzen, da der Timer1 schon für andere Sachen( HArdware PWM) 
verwendung findet.
Allerdings hab ich das mit dem noch freinen Timer2 realisiert der 
einfach gestartet bzw. gestoppt wird.

Hier mein COde falls es jemand mal brauchen sollte.
Der Code funktioniert bestens( mit Oscar überprüft).
Es ergibt sich natürlich durch den 8-bit timer eine Ungenauigkeit von 
16µs, die aber nicht auffallen( meiner Hardware PWM werden durch eine 
separate  if abfrage nur werte übergeben, die größer als die 
ungenauigkeit sind).

So nun hier der Code
1
// Aktion bei Interrupt INT0
2
 ISR(INT0_vect) 
3
  {
4
  
5
    if ((PIND & (1<<PD2))) // Abfrage ob Servo1 Signal high
6
       
7
       {
8
      TCNT2 = 0;        // Zähler zurück setzen
9
         TCCR2 |=(1<<CS20);    // Timer 2 starten (Prescaler 128)
10
      TCCR2&=(~(1<<CS21));  //
11
      TCCR2 |=(1<<CS22);    //
12
       
13
       
14
             }
15
    else
16
              {
17
        
18
      TCCR2&=(~(1<<CS20));    // Timer 2 stoppen
19
      TCCR2&=(~(1<<CS21));    //
20
      TCCR2&=(~(1<<CS22));    //
21
      
22
      
23
      servo1_in =  (TCNT2 * 16);  // Berechnung der TI Zeit 
24
      
25
      
26
       
27
      timestamp |= ((1 << 6));                  // Setzen des Bits in Timestamp Byte bei fallende Flanke an Int0
28
      GICR &= (~(1<<INT0));                 // INT0 DEaktivieren
29
      GICR |= (1<<INT1);                       // INT1 aktivieren
30
      
31
              }
32
    
33
  }
34
  
35
// Aktion bei Interrupt INT1
36
 ISR(INT1_vect) 
37
  {
38
    if ((PIND & (1<<PD3))) // Abfrage ob Servo1 Signal high
39
       
40
       {
41
      TCNT2 = 0;        // Zähler zurück setzen
42
         TCCR2 |=(1<<CS20);    // Timer 2 starten (Prescaler 128)
43
      TCCR2&=(~(1<<CS21));  //
44
      TCCR2 |=(1<<CS22);    //
45
       
46
       
47
             }
48
    else
49
              {
50
        
51
      servo2_in =  (TCNT2 * 16);  // Berechnung der TI Zeit 
52
      
53
      TCCR2&=(~(1<<CS20));    // Timer 2 stoppen
54
      TCCR2&=(~(1<<CS21));    //
55
      TCCR2&=(~(1<<CS22));    //
56
          timestamp |= ((1 << 7)); // Setzen des BIts in Tiemstamp Byte bei fallende Flanke an Int1
57
              GICR &= (~(1<<INT1)); // INT1 deaktivieren
58
    GICR |= (1<<INT0); // INT0 aktivieren
59
60
      
61
      }
62
    
63
  }


Nochamls danke ans Forum für die immer freundliche Hilfe

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.