Forum: Mikrocontroller und Digitale Elektronik RC Empfänger auswerten


von GEA (Gast)


Lesenswert?

Hallo Leute,

ich möchte mehrere Signale von einem Graupner Empfänger mit AVR einlesen
auswerten und mischen.
Die Suche habe ich bemüht aber leider nichts brauchbares gefunden, es 
existieren zwar zig Themen zum Thema "Servo ansteuern" aber nichts zu 
der Auswertung von Signalen.

Möchte mit einem Atmega 32 die Signale auswerten, versuche in C zu 
programmieren.
Also meine Idee war folgende:

Ich wollte die externen Interrupts benutzen, es wären die Pins INT0, 
INT1, INT2.
1) Am Anfang den Interrupt Initialisieren für die Positive Flanke
2) Positive Flanke aufgetreten--->Initialisieren für die Negative Flanke
3) Zeit zählen die vergeht bis wieder ein Interrupt auftritt(jetzt für 
die Negative Flanke)
4) Negative Flanke aufgetreten--->Initialisieren für die Positive Flanke
usw

Das ganze funz aber nicht, es geht zwar wenn ich mit einem Draht die 
Flanken simuliere aber nicht wenn der Empfänger am µC hängt.

Hat einer vielleicht eine andere Idee? wo liegt mein Fehler?
Welche Möglichkeiten gibt es noch?

von STK500-Besitzer (Gast)


Lesenswert?

>wo liegt mein Fehler?

Entweder in der Hardware, der Software oder in beiden...
Zeig dein Programm, und man kann dir (besser) helfen.

von Hannes L. (hannes)


Lesenswert?

http://www.hanneslux.de/avr/mobau/index.html

Nicht der letzte Schrei, aber brauchbar und ausbaufähig...

...

von Tobias T. (tobytetzi)


Lesenswert?

Hallo,

ich habe es so gemacht.
ATmega8, 16mHz,ein Kanal wird mit einem Ext.Int ausgewertet.

#include <avr/io.h>
#include <avr/interrupt.h>

volatile uint8_t Pulsdauer = 0;

void (steigende_Flanke)(void);
void (fallende_Flanke)(void);

SIGNAL(SIG_INTERRUPT0)
{
  if( MCUCR == 0x03) // Testen auf steigende Flanke
  {
  steigende_Flanke();
  return;
  }

  if( MCUCR == 0x02 ) // Testen auf fallende Flanke
  {
  fallende_Flanke();
  return;
  }
}
void (steigende_Flanke)(void)
{
  TCNT0 = 0; // Timer Reset
  TCCR0 = _BV (CS02);  // Timer2 1/256 MCU start
  MCUCR = 0x02; // INT0 fallende Flanke
}
void (fallende_Flanke)(void)
{
  TCCR0 = 0x00; // Timer2 Stoppen
  Pulsdauer = TCNT0; // Timer Wert = Pulsdauer
  MCUCR = 0x03; // INT0 auf steigende Flanke
}

int main(void) {

//PD2 Int0 für RC Signal
  PORTD = 0x04;       // Pull up on PD2
  DDRD = 0xFB;        // PD2 in Rest out

//Int0 steigende Flanke / INT0 enable
  MCUCR = _BV (ISC01) | _BV (ISC00);
  GICR = _BV (INT0);

  sei();

for(;;)
{

if (Pulsdauer < 68){"mach was"}

else if (Pulsdauer >= 68 && Pulsdauer < 85){"mach was anderes"}

else if (Pulsdauer >= 85 && Pulsdauer < 110){"mach was anderes"}

else if (Pulsdauer >= 110 && Pulsdauer < 150){"mach was anderes"}
}
}

Gruß Toby

von Tobias T. (tobytetzi)


Angehängte Dateien:

Lesenswert?

Hallo nochmal,

du kannst natürlich auch mit dem RC Summensignal mehrere Kanäle 
auswerten.

Das habe ich mal hier gemacht, siehe Anhang.
Die LCD Routine habe ich nicht mit angehangen, es geht ja ums Auswerten 
des Signals.

Gruß Toby

von GEA (Gast)


Lesenswert?

Danke erstmal für die Antworten und Beispiele.
Hier ist mein Code, etwas primitiv aber na ja:

#include <avr/interrupt.h>
#include <avr/io.h>
#include "usart.h"
#include "lcd.h"


volatile int eins=1 ; // Wenn die Variable eins 1 ist, wird für negative
                      // Flanke initialisiert

volatile int zeit_ein; //Wenn die Variable zeit_ein 1 ist läuft die Zeit

volatile int wert;     //Pulsbreite



//---------------------------------------------------------------------- 
------
//INT1 Interrupt
ISR (INT1_vect)
{

if(eins==1)
{
wert=0;
zeit_ein=1;
MCUCR|= (1<<ISC11);
GICR |= (1<<INT1);
eins=0;
}

else
{
zeit_ein=0;
MCUCR|= (1<<ISC10 | 1<<ISC11);
GICR |= (1<<INT1);
eins=1;
}
}
//---------------------------------------------------------------------- 
--------

int main (void)
{



//-----Allgemeine Initialisierung-----------------------
  //Initialisierung externe Interrupt
  MCUCR|= (1<<ISC10 | 1<<ISC11);
  GICR |= (1<<INT1);

  LCD_Init();

  LCD_Clear();

  sei();

//------Allgemeine Initialisierung ende --------------------

  while(1)
  {

    if(zeit_ein == 1)
    {
    wert=wert+1;
    }


LCD_Print(0,0,"    %i   %i        ",wert,zeit_ein);
LCD_Print(1,0,"                    ");
LCD_Print(2,0,"                    ");
LCD_Print(3,0,"                    ");

  }


}

@Tobias
du benutzt da den Timer, wie ist es aber wenn ich mehrere Kanäle 
auswerten
will?

von STK500-Besitzer (Gast)


Lesenswert?

1
if(eins==1)
2
{
3
wert=0;
4
zeit_ein=1;
5
MCUCR|= (1<<ISC11);
6
GICR |= (1<<INT1);
7
eins=0;
8
}
9
10
else
11
{
12
zeit_ein=0;
13
MCUCR|= (1<<ISC10 | 1<<ISC11);
14
GICR |= (1<<INT1);
15
eins=1;
16
}
17
}

Soll wohl deine Flankendetektierungsumschaltung sein.
Allerdings wird die immer auf die gleiche Flanke reagieren. Du mußt das 
entsprechende Bit löschen "... &= ~ ...". Dann schaltest du auch die 
Flanken um.

von Tobias T. (tobytetzi)


Lesenswert?

Hallo,

eigentlich müssten die Empfängerausgänge nacheinander angesteuert 
werden,
da der Empfänger nur das PPM Signal in die Entsprechenden Kanäle 
umwandelt.

Also müsste eine Auswertung von 2 Kanälen mit 2 Ext.Ints gehen.

Siehe hier:
http://www.mftech.de/ppm.htm

Alle 22,5 ms bekommt der dementsprechende Kanal seine Pulslänge.

Gruß Toby

von GEA (Gast)


Lesenswert?

Ja hast eigentlich recht, die Signale kommen ja nach einander.
Ich probiere was aus vielleicht klappt es ja

von GEA (Gast)


Lesenswert?

Kann mir einer sagen was das für ein Fehler ist?

Compiling: main.c
avr-gcc -c -mmcu=atmega32 -I. -g -Os -funsigned-char 
-funsigned-bitfields -fpack-struct -fshort-enums -Wall 
-Wstrict-prototypes -Wa,-adhlns=main.lst  -std=gnu99 main.c -o main.o
main.c: In function '__vector_1':
main.c:84: warning: 'main' is normally a non-static function
main.c:180: error: expected declaration or statement at end of input
make.exe: *** [main.o] Error 1

Der zeigt auf die Geschweiften Klammern von "main"
Ich weis aber nicht was da falsch sein soll.

von GEA (Gast)


Lesenswert?

Ich habs, es fehlte nur eine Klammer.

Und die Auswertung läuft auch, Super.

Ich danke euch.

von Marco D. (pendler)


Lesenswert?

Hi,

ich habe lange gewartet mit dem Posten hier, aber scheinbar komme ich 
nicht drum herum (leider).

Zu meinem Problemchen:
Ich versuche ähnliches (Empfänger Signal von nem Servo auslesen) mit 
einem Attiny2313 aber komme nun schon seit 5 Tagen und etlichen Stunden 
testerei nicht mehr weiter.
Ich habe viel selbst rumprobiert, mir auch mal nen Source, der 
eigentlich für den Atmega8 waren angeguckt und meinen danach 
umgeschrieben, aber leider klappt alles nicht!
Vielleicht könnte mir jemand mit mehr Erfahrung (stehe noch relativ am 
Anfang) einen Tip geben.

Als Info:
Den Interrupt habe ich getestet, reagiert auf steigende und sinkende 
Flanken. Der Overflow von INT0 geht auch.

Der Timer wird mit nem Prescale von 64 gestartet (was eigentlich nicht 
sein muss) und wenn meine Berechnungen stimmen sollte bei einem Maximal 
Ausschlag (~2ms) knappe 250 rauskommen. Stimmt das so?

Den Divider habe habe ich weggefused. Und sonst die Standardfuses 
gelassen (Int. RC Osc. 4 MHz; Start-up time: 14 CK + 65 ms)

Um den Code (solange er noch nicht funktioniert) möglichst schmal zu 
halten schalte ich nur Komplett den PORTB an, mehr nicht.

Ich habe den Code mal ein bisschen dokumentiert.
1
#define F_CPU 4000000;
2
#include <inttypes.h>
3
#include <avr/io.h>
4
#include <avr/interrupt.h>
5
6
uint16_t value;
7
8
int main (void)
9
{
10
11
  DDRB = 255;  // portb as output
12
  PORTB = 0;   // portb to 0  
13
14
  DDRD = 0;  // portd as input
15
  PORTD = 0;   // portd to 0  
16
17
  PCMSK |= (1<<PIND2);             // Pin 6 (PD2) als Interrupt setzen
18
  MCUCR = 1;            // External Interrupt on PinChange
19
  GIMSK  |= (1<<INT0);
20
21
  TCNT1 = 0;
22
23
  TIMSK |= (1<<TOIE1);                        // 16-Bit Timer Overflow-Interrupt an
24
  TCCR1A = 0;                        // 16-Bit Normal Mode
25
  TCCR1B = 0;                        // stop 16-Bit Timer 
26
27
  sei();   // Interrupts an.
28
29
  
30
31
  while(1)
32
  {
33
    if (value > 200)
34
    {
35
      PORTB = 255;
36
    }
37
    else
38
    {
39
      PORTB = 0;
40
    }
41
  }
42
}
43
44
ISR(TIMER1_OVF_vect)
45
{
46
47
}
48
49
ISR (INT0_vect)
50
{
51
  if ((PIND & 4)==4) // HIGH!
52
  {
53
    TCCR1B = 0;
54
    TCNT1 = 0;
55
    TCCR1B = 3; // Starten mit Prescaler: 4mhz / 64 > 2ms = 125 Takte
56
57
  }
58
else
59
  {
60
    value = TCNT1;
61
    TCCR1B = 0;
62
  }
63
}

Kann mir vielleicht jemand sagen, warum die LED nur wie blöde flackert?

Ich hatte schon alle Möglichkeiten mit dem Timer durch, am Ende habe ich 
ihn einfach erst gestartet, als ne hohe Flanke kam.

Bin für jeden Tip Dankbar

von STK500-Besitzer (Gast)


Lesenswert?

Mach dein "value" noch volatile!

Hat der Attiny2313 keine InputCapture-Unit?
Damit mache ich solche Sachen immer...

von Marco D. (pendler)


Lesenswert?

Hi,

das mit Volatile muss ich mal ausprobieren.
Mit der InputCapture-Unit muss ich mal nachsehen, damit habe ich noch 
nichts gemacht, werde ich mir aber heute Abend mal ansehen.

Ich habe den Teil mit dem "Value" aus einem anderen Beispiel übernommen, 
bei dem es mit einem Atmega8 so ähnlich funktioniert hat. Ich dachte, 
wenn ich das erstmal relativ simpel halte kann ich das Programm nach und 
nach ausbauen, wenn ich weiß dass es grundsätzlich so funktioniert

Bei dem ganzen Aufbau ist es in erster Linie nicht so wichtig, ob die 
Werte genau sind, ich will darüber nur eine Beleuchtung über einen 
freien Kanal an meiner Fernsteuerung einschalten/ausschalten.

Was ich vergessen habe, an Portb hängt beim Testaufbau nur eine LED.

Was mich gewundert hat war, dass die LED an Portb immer geflackert hat, 
unabhängig davon, was ich an der Fernsteuerung gemacht habe. Die 
Leitungen habe ich alle schon durchgemessen, das Signal kommt genau so, 
wie es sein soll und die richtige Leitung habe ich auch an PD2 
angeschlossen.

Viele Grüße
Pendler

von Marco D. (pendler)


Lesenswert?

Ich habs letztens hinbekommen, war nur ein dummer Fehler. Die GND Brücke 
zwischen den beiden Stromversorgungen war nicht korrekt. Tja, so einfach 
gehts!

von Ahmet S. (arahan)


Lesenswert?

Hallo Leute,
ich muss wie "GEA (Gast)" die Empfänger Signale auslesen und auswerten 
aber komme leider nicht weit...
Meine Aufgabe ist mit Atmega32 und AVR die Signale zu lesen und Sie 
auswerten. Die Programmierung muss über C laufen...

Habt Ihr vielleicht für mich fertig Programmierte Programme welche ich 
einfach übernehmen kann? ich hab leider nicht viel Zeit da ich neben bei 
auf meine Studium Konzentrieren muss:(

viele grüße

von Carsten M. (carsten_m52)


Lesenswert?

Hallo,

musste auch ein ähnliches Problem lösen, allerdings hatte ich keinen 
freien Interrupt mehr und habe das Ganze dann etwas schmutziger per 
Busy-Wait gelöst. Funktioniert auch und hat für mich den Vorteil, dass 
ich mehr Kanäle als freie Interrupt Leitungen vorhanden sind mit einem 
AVR auslesen kann.

1
/*! Einlesen von RC-Signalen
2
 * Schmutzig per Busy Loop, dafür Interrupt unabhängig
3
 */
4
 
5
#include <avr/io.h>
6
#include <util/delay.h>
7
#include <avr/pgmspace.h>
8
#include <stdarg.h>
9
#include <string.h>
10
#include <stdlib.h>
11
12
#define F_CPU 16000000
13
14
15
uint16_t Pulsdauer;
16
uint16_t ReadChannel (void);
17
18
19
20
21
22
//###################################################################################
23
/* Hauptprogramm */
24
int main(void)
25
//###################################################################################
26
{
27
28
 char debtext [10];
29
30
31
 // RC Signal Init
32
 DDRD  &= ~(1 << PD3);    //PD3 auf Input
33
 PORTD |= (1 <<PD3);    //pullup auf PD3
34
 // Ende Init RC Signal
35
36
 for(;;) // loop forever
37
  { 
38
   //DEBUG Output
39
   Pulsdauer=ReadChannel();
40
   itoa(Pulsdauer, debtext, 10);
41
      puts("Pulsdauer Debug: ");
42
43
      puts(debtext);
44
      puts("\r\n");
45
  
46
}
47
48
uint16_t ReadChannel (void)
49
{
50
  uint16_t i;
51
  i=2000;  //Wert Initialisieren um einen positiven Wert als Ausgabe zu erzeugen
52
  while (!(PIND & (1<<PD3))){asm volatile ("nop");}
53
  while (PIND & (1<<PD3)){asm volatile ("nop");}
54
  while (!(PIND & (1<<PD3))){i--; _delay_us(10);}
55
  return (i);
56
57
}

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.