Forum: Mikrocontroller und Digitale Elektronik PPM von RC-Empfänger einlesen in Mega8


von Christian S. (snoopy88)


Lesenswert?

Hallo zusammen,

Ich habe jetzt bereits einen Tag damit verbracht und komme nicht weiter. 
Leider hat mich auch die Suche nicht wirklich weiter gebracht.

Mein Ziel:
Ich habe vor das Summensignal (PPM) von einem standard-Empfänger 
einzulesen. IM moment teste ich das ganze an einem "Multiplex Pico 5/6". 
Leider ist meine Familie elektronisch nicht sonderlich vorbelastet, und 
so habe ich zwar einiges an RC-Equipment und fliege seit Jahren 
Modellflugzeuge, aber an Ausstattung für Elektrobasteleien mangelt es. 
Das Ansehen von Signalem mit einem Oszi o.ä. ist also nicht möglich und 
die meisten Bauteile muss ich auch jedes mal erst kaufen.

Ich arbeite daher momentan mit einem MyAVR-Board mit einem Mega8-16PU 
(wenn mir einer das 16PU in wenigen Worten erklären kann wäre das auch 
nett :)). Das PPM-Signal hängt an PIND2, um es über INT0 einzulesen. 
Dieser soll auf jede Taktflanke reagieren. Der nebenher laufende Timer0 
wird bei einer Taktfalnke 0->1 auf 0 gesetzt. Bei einer Taktfalnke 1->0 
wird er ausgelesen, sein Wert in einen array geschrieben, ein dirty-Bit 
gesetzt und der Index inkrementiert. Außerdem wird geprüft, ob es sich 
um einen langen Abstand gehandelt hat. Wenn das so ist, dann wird nur 
der Index auf 0 gesetzt.

Soweit zu meinem Vorhaben. Nur funktionieren tut es leider nicht. Da ich 
zu den Flanken im INternet unterschiedliche Angaben gefunden habe, habe 
ich auch schon die Reaktion auf die versch. Takflanken vertauscht, was 
aber auch keinen Erfolg brachte.


Mein Code sieht so aus:

ppm.c
1
//************************************************************************
2
// Note: This code was written for Mega8 at 4MHz
3
//       It reads in the Signal from standard RC-Transmitters with 8 Channels
4
//       The Signal from the reciever must be connected to PD2 (INT0)
5
//
6
// Current Counts per ms: 57.6
7
//
8
// TODO:
9
// * Currently there are no checks on array-borders
10
// * Automatic computeation of the prescaler would be nice
11
12
//************************************************************************
13
14
#include "ppm.h"
15
16
#include <avr/io.h>
17
18
#include <avr/interrupt.h>
19
20
21
22
extern void ppm_init()
23
{ 
24
25
//PD2 (INT0) as input with internal Pull-Up
26
  DDRD &= ~(1 << DDD2);
27
  DDRD |= (1 << PD2);
28
29
// enable Interupt INT0
30
  GIMSK |= (1 << INT0);
31
32
// Every change at INT0 triggers the Interupt
33
  MCUCR |= (1 << ISC00);
34
  MCUCR &= ~(1 << ISC01);
35
36
// Prescaler 64
37
  TCCR0 |= ((1 << CS00) | (1 << CS01));
38
  TCCR0 &= ~(1<<CS02);
39
40
// enable Timer-Interupt
41
//  TIMSK |= (1 << TOIE0);
42
43
  channels.dirty = 0;
44
45
  sei();
46
}
47
48
//ISR(TIMER0_OVF_vect)
49
//{
50
//  channels.overflow++;
51
//}
52
53
ISR(INT0_vect)
54
{
55
  if(PIND & (1 << PINC2)) { // High
56
    TCNT0 = 0;
57
  } else { // Low
58
    if (TCNT0 > LOW_MAX) { // all channels complete
59
      channels.counter = 0;
60
      channels.dirty   = 0;
61
    } else if (channels.counter < CHANNELS) { // write position after checking arraybounds
62
      channels.position[channels.counter] = TCNT0 - LOW_MIN;
63
      channels.dirty |= (1 << channels.counter);
64
      channels.counter++;
65
    }
66
  }
67
}
68
69
// Returns the position of the channel with a range between zero and 50.
70
// If the given channel doesn't exist, zero is returned.
71
uint8_t get_0_50 (uint8_t channel)
72
{
73
  if(channel => CHANNELS) {
74
    return 0;
75
  } else {
76
    return channels.position[channel] * (50/COUNTS_PER_MS);
77
  }
78
}

ppm.h
1
/*#######################################################################################
2
3
Reading the sum-Signal of normal RC-Recievers
4
5
6
7
Copyright (C) 2009 Christian Sachers
8
9
#######################################################################################*/
10
11
12
13
#include <avr/io.h>
14
15
#include <avr/interrupt.h>
16
17
18
19
#define CHANNELS  8
20
21
#define LOW_MIN    58  // = 1ms
22
23
#define LOW_MAX    130  // ~2.25ms
24
25
#define COUNTS_PER_MS  58
26
27
28
volatile struct {
29
  uint8_t position[CHANNELS];
30
  uint8_t counter;
31
  uint8_t dirty;  // every Bit represents one Channel
32
} channels;
33
34
35
36
extern void ppm_init(void);
37
extern uint8_t get_0_50 (uint8_t channel);

test.c
1
#include "ppm.h"
2
#include <avr/io.h> 
3
4
int main() {
5
  DDRC = 0xff;  // Port C ist Ausgang
6
7
  ppm_init();
8
9
  uint8_t position;
10
  while (1) {
11
    if (1 & channels.dirty) {
12
      position = get_0_50 (0);
13
      if (position < 17) {
14
        PORTC = 1;
15
      } else if (position < 33) {
16
        PORTC = 2;
17
      } else {
18
        PORTC = 4;
19
      }
20
    } else {
21
      PORTC = 7;
22
    }
23
  }
24
  return 1;
25
}


Ich habe im Internet auch eine Variante mit dem Timer1 und ICP gesehen. 
Aber den Timer1 würde ich mir gerne für PWM-Ausgabe freihalten.


Falls mir jemand von den Erfahrenen (oder gern auch Unerfahrene :)) 
einen Tip geben kann, was da der Fehler sein könnte, würde ich mich 
freuen.

Danke im Vorraus,
Christian

PS: Falls es nötig sein sollte, kann ich auch ein Photo des Aufbaus 
online stellen.

von Christian S. (snoopy88)


Lesenswert?

hochschiebt

von STK500-Besitzer (Gast)


Lesenswert?

>Ich habe im Internet auch eine Variante mit dem Timer1 und ICP gesehen.
>Aber den Timer1 würde ich mir gerne für PWM-Ausgabe freihalten.

Man kann ihn für beides benutzen.
Man muß nur erkennen, ob es einen Überlauf gab, wenn man den TOP-Wert 
des Timers verändert. Dann muss man die Differenz zu 65535 noch 
irgendwie dazupacken.

von Michael K. (mmike)


Lesenswert?

Schau doch mal bei den Mikrocopter - Sourcen ...

http://svn.mikrokopter.de/mikrowebsvn/listing.php?repname=FlightCtrl&path=%2Ftags%2F#_tags_

da ist mit Sicherheit was dabei, wo man sich die Technik "anlernen" kann 
um dann das Ganze SELBST zu implementieren ! Einfach nur copy - paste 
hat keinen pädagogischen Nutzen ;-)

Grüße,
Michael

Edit: Bei V0.70d die Dateien rc.h und rc.c

von Christian S. (snoopy88)


Lesenswert?

Danke für eure Antworten.

Dass man beides (PPM einlesen und PWM ausgeben) mit einem Timer 
hinbekommen kann klingt schon logisch, aber wenn ich drei Timer zur 
Verfügung habe, kann ich diese ja auch verwenden. Besonders als Anfänger 
scheint mir das geeigneter, sonst werde ich nachher garantiert Probleme 
mit nicht bedachten Wechselwirkungen bekommen :).

Ich habe mir auch die Sourcen vom Mikrokopter gerade mal angesehen. Die 
verwenden ja leider auch den Timer1 mit Input-Capture.


Ich würde außerdem gerne verstehen, was ich bisher falsch gemacht habe. 
Meine Theorie sagt mir, dass es eigentlich funktionieren sollte, aber 
leider sieht die realität anders aus.

Einen meiner vermutlichen Fehler habe ich bereits gefunden: Ich habe die 
Overflows des Counters nicht mitgezählt, weswegen die Pausen zwischen 
den "Blöcken" nicht sicher erkannt werden. Leider funktioniert das ganze 
trotzdem noch nicht.


Christian

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.