www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik RC Empfänger auswerten


Autor: GEA (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: STK500-Besitzer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>wo liegt mein Fehler?

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

Autor: Hannes Lux (hannes)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
http://www.hanneslux.de/avr/mobau/index.html

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

...

Autor: Tobias Tetzlaff (tobytetzi)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Tobias Tetzlaff (tobytetzi)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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

Autor: GEA (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: STK500-Besitzer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
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;
}
}


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.

Autor: Tobias Tetzlaff (tobytetzi)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: GEA (Gast)
Datum:

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

Autor: GEA (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: GEA (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich habs, es fehlte nur eine Klammer.

Und die Auswertung läuft auch, Super.

Ich danke euch.

Autor: Marco D. f. (pendler)
Datum:

Bewertung
0 lesenswert
nicht 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.
#define F_CPU 4000000;
#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>

uint16_t value;

int main (void)
{

  DDRB = 255;  // portb as output
  PORTB = 0;   // portb to 0  

  DDRD = 0;  // portd as input
  PORTD = 0;   // portd to 0  

  PCMSK |= (1<<PIND2);             // Pin 6 (PD2) als Interrupt setzen
  MCUCR = 1;            // External Interrupt on PinChange
  GIMSK  |= (1<<INT0);

  TCNT1 = 0;

  TIMSK |= (1<<TOIE1);                        // 16-Bit Timer Overflow-Interrupt an
  TCCR1A = 0;                        // 16-Bit Normal Mode
  TCCR1B = 0;                        // stop 16-Bit Timer 

  sei();   // Interrupts an.

  

  while(1)
  {
    if (value > 200)
    {
      PORTB = 255;
    }
    else
    {
      PORTB = 0;
    }
  }
}

ISR(TIMER1_OVF_vect)
{

}

ISR (INT0_vect)
{
  if ((PIND & 4)==4) // HIGH!
  {
    TCCR1B = 0;
    TCNT1 = 0;
    TCCR1B = 3; // Starten mit Prescaler: 4mhz / 64 > 2ms = 125 Takte

  }
else
  {
    value = TCNT1;
    TCCR1B = 0;
  }
}


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

Autor: STK500-Besitzer (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mach dein "value" noch volatile!

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

Autor: Marco D. f. (pendler)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Marco D. f. (pendler)
Datum:

Bewertung
0 lesenswert
nicht 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!

Autor: Ahmet Sanane (arahan)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Carsten M. (carsten_m52)
Datum:

Bewertung
0 lesenswert
nicht 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.

/*! Einlesen von RC-Signalen
 * Schmutzig per Busy Loop, dafür Interrupt unabhängig
 */
 
#include <avr/io.h>
#include <util/delay.h>
#include <avr/pgmspace.h>
#include <stdarg.h>
#include <string.h>
#include <stdlib.h>

#define F_CPU 16000000


uint16_t Pulsdauer;
uint16_t ReadChannel (void);





//###################################################################################
/* Hauptprogramm */
int main(void)
//###################################################################################
{

 char debtext [10];


 // RC Signal Init
 DDRD  &= ~(1 << PD3);    //PD3 auf Input
 PORTD |= (1 <<PD3);    //pullup auf PD3
 // Ende Init RC Signal

 for(;;) // loop forever
  { 
   //DEBUG Output
   Pulsdauer=ReadChannel();
   itoa(Pulsdauer, debtext, 10);
      puts("Pulsdauer Debug: ");

      puts(debtext);
      puts("\r\n");
  
}

uint16_t ReadChannel (void)
{
  uint16_t i;
  i=2000;  //Wert Initialisieren um einen positiven Wert als Ausgabe zu erzeugen
  while (!(PIND & (1<<PD3))){asm volatile ("nop");}
  while (PIND & (1<<PD3)){asm volatile ("nop");}
  while (!(PIND & (1<<PD3))){i--; _delay_us(10);}
  return (i);

}


Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.