-
        

Ergebnis 1 bis 10 von 10

Thema: RC Empfänger an ATMega16

  1. #1
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    26.06.2005
    Ort
    Gäufelden
    Alter
    31
    Beiträge
    109

    RC Empfänger an ATMega16

    Anzeige

    Hallo an Alle!

    wie manche ja vielleicht schon wissen bin ich in letzter Zeit stark am rumprobieren um mehr Verständniss für die Mikroelektronik zu bekommen. Nun wollte ich einmal einen standard RC-Empfänger durch einen ATMega16 auswerten lassen. Dazu habe ich mir folgendes Prinzip überlegt/abgeschaut:

    Timer1 soll genau 10µs brauchen um einen Überlauf zu erzeugen. Wenn nun eine positive Taktflanke vom Empfänger kommt soll der Mikrocontroller die Überläufte zählen die bis zur nächsten negativen Taktflanke auftreten und daraus auf die Pulsweite schließen. Die Pulsweite soll nun über ein LCD-Display ausgegeben werden.

    Zur Schaltung kann ich noch ergänzen das ich die GND´s der Batterie die den Empfänger antreibt mit dem GND der Platine verbunden habe (ein Fehler den ich sonst immer falsch gemacht habe).

    Nun möchte ich vor dem Code noch das Problem beschreiben:
    Der Zählerstand ändert sich nicht wenn ich den Stick der Fernbedingung verschiebe. Dazu folgt das die Zahl ein Zufallswert ist, der jedoch konstant bleibt und entweder im Bereich von 600 oder 2230 liegt. Ein Signal vom Empfänger kommt aber denn wenn ich die Fernbedinung ausschalte dann beginnt der Zahlen-Wert durch das Rauschen im Empfänger an zu springen.

    Das Projekt arbeitet mit 8MHz... jetzt der Code (dazu sei Gesagt das die LCD-Befehle in anderen Projekten funktionieren)

    Code:
    #include <avr/io.h>
    #include <stdlib.h>
    #include <avr/interrupt.h>
    #include "lcd_tools.h"
    #include <util/delay.h>
    volatile int inizialisierung;
    volatile uint16_t counter=0;
    volatile int posneg;
    volatile uint16_t Zeit=0;
    
    //LCD Ausgabe
    void ausgabe()
    {
        char Z[10];
        lcd_gotoline(1);
        lcd_writetext("Kanal 1:");
        lcd_cls_line(2);
        lcd_gotoline(2);
        itoa(Zeit,Z,10);
        lcd_writetext(Z);
    }
    
    
    
    // Timer/Counter1 Start und Ende
    ISR (TIMER1_CAPT_vect)
    {
        if (posneg<1)
        { 
            counter=0;                                //counter zurücksetzen
            TCCR1B&=~ (1<<ICES1);                    //auf fallende Flanke triggern
            posneg=1;
        } 
        else
        {
            cli();
            Zeit=counter;                        // Zeit im µs berechnen
            TCCR1B|= (1<<ICES1);                    //auf steigende Flanke triggern
            ausgabe ();                                // Ausgabe auf Display
            posneg=0;
            sei();
        }
    }
    
    // Timer/Counter1 Vergleichszähler
    ISR (TIMER1_COMPA_vect)                            // je 10µs einmal
    {
        counter++;                                    // Überläufe zählen        
    }
    
    
    int main(void)
    {
        lcd_ini();
        TIMSK |= (1 << TICIE1) | (1 << OCIE1A);        // Input Capture Interrupt Enable+Output Compare A Match Interrupt Enable
        OCR1A = (uint16_t)(0x50);                    // Vergleichswert 10µ Sekunden
        TCCR1B |= (1 << WGM12);                        // CTC Modus
        TCCR1B |= (1 << ICNC1) | (1 << ICES1);        // Noise Canceler + steigende Flanke an ICP1
        TCCR1B |= (1 << CS10);                        // Prescaler: 1
        lcd_gotoline(1);
        lcd_writetext ("Kalibrierung");
        _delay_ms(1000);
        inizialisierung=0;                            // Kalibrierung erforderlich
        posneg=0;                                    // warten auf positive Flanke
        lcd_cls();
        sei();                                        // IRQs enable
        
        while(1)
        {
        
        }
    }
    Die Variable "inizialisierung" soll später für weitere Funktionen genutzt werden.Im Moment ist sie nutzlos. Genauso wie die Ausgabe "Kalibrierung" auf dem LCD.

    Danke schon mal für die Hilfe und den Hirnschmalz.

    Viele liebe Grüße
    Jeti

  2. #2
    Erfahrener Benutzer Robotik Einstein Avatar von wkrug
    Registriert seit
    17.08.2006
    Ort
    Dietfurt
    Beiträge
    1.892
    Ich würde für diese Aufgabe den ICP Interrupt nutzen.
    Zuerst wird das sensing auf steigende Flanke gestellt.
    Wenn die dann kommt wird das ICP Timer register ausgelesen und das Sensing auf fallende Flanke umgestellt.
    Tritt die dann auf wird das ICP Register wiederum ausgelesen un der vorherige Wert abgezogen.
    Das Sensing muss dann für den nächsten Impuls wieder auf steigende Flanke umgestellt werden.
    Bei 8MHz Taktfrequenz und einen Prescaler von 8 kriegst Du damit einen Auflösung von 1µS.
    Du müsstest dann allerdings einen 16Bit Timer nehmen, weil der Zählerstand ja immer über 255 liegt.

    Die ermittelte Impulslänge kann dann in einer Variable abgespeichert werden. Ich würde dann noch ein Flag ( Bit Variable ) setzen, damit dieser neue Wert im Hauptprogramm bekannt gemacht wird und verarbeitet werden kann.

    Das System läuft gut und scheinbar im Hintergrund, da alle zeitkritischen Operationen im Interrupt stattfinden, also Laufzeiten im Hauptprogramm keinen Einfluss auf die Impulsauswertung haben.

  3. #3
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    26.06.2005
    Ort
    Gäufelden
    Alter
    31
    Beiträge
    109
    Danke für die Antwort, aber ich glaube das (oder so etwas ähnliches) versuche ich doch gerade oder? Der Empfänger hängt in meinem Fall am IPC1 also PD6. Und da ich die Anzahl der Überläufe zähle die jeweils 10µs lang sind müsste ich doch eigentlich auch auf eine Antwort kommen... ist halt nicht ganz so genau ...

  4. #4
    Erfahrener Benutzer Roboter Genie Avatar von Searcher
    Registriert seit
    07.06.2009
    Ort
    NRW
    Beiträge
    1.410
    Blog-Einträge
    101
    Hallo,
    wie ist der Empfänger am Mega16 PD6 angeschlossen? Kann es sein, daß der Empfängerausgang ein Open Collector ist und Du da noch einen Pullup Widerstand brauchst - eventuell den internen des Mega16 nutzen?

    Gruß
    Searcher
    Hoffentlich liegt das Ziel auch am Weg
    ..................................................................Der Weg zu einigen meiner Konstruktionen

  5. #5
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    26.06.2005
    Ort
    Gäufelden
    Alter
    31
    Beiträge
    109
    Ich habe im Moment einfach nur das Kabel an den Pin angeklemmt... also ohne irgendwas. Ich habe mich auch schon gefragt ob ich da noch einen Widerstand brauche aber ich hätte eher einen widerstand zwischen Signal und GND (Pulldown?!?) geklemmt... Wie kann ich denn denn den internen Pullup aktivieren oder muss ich wirklich einfach einen Widerstand anklemmen?

    Gruß

    PS: Was der Empfänger für einer ist kann ich nicht mehr sagen. Er ist ziemlich alt. Bestimmt 15 Jahre oder mehr
    Geändert von Jeti (18.04.2013 um 11:38 Uhr)

  6. #6
    Erfahrener Benutzer Roboter Genie Avatar von Searcher
    Registriert seit
    07.06.2009
    Ort
    NRW
    Beiträge
    1.410
    Blog-Einträge
    101
    Hi, bei RC Empfängern speziell kenne ich mich nicht aus. Üblich sind Open Collector bei NPN Transistoren. Bedeutet, Du brauchst einen PULLUP Widerstand. Also einfach einen 10k Widerstand von PD6 nach 5V Vcc des Mega16 schalten. Alternativ kannst Du den internen Pullup des Mega16 einschalten. Im PORTD Register das PD6 Bit auf eins setzen bei als Eingang konfigurierten PD6; PD6 ist ja schon in Deinem obigen Programm defaultmäßig auf Eingang, also noch PD6 im PORTD setzen.

    Gruß
    Searcher
    Hoffentlich liegt das Ziel auch am Weg
    ..................................................................Der Weg zu einigen meiner Konstruktionen

  7. #7
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    26.06.2005
    Ort
    Gäufelden
    Alter
    31
    Beiträge
    109
    Ich habe das mit dem Pin PD6 ausprobiert. Leider hat es das Ergebnis nicht verändert. Ich werde nun bei gelegenheit mal einen 10k Widerstand nach VCC schalten. Mal schauen ob das was ändert, dürfte es ja aber eigentlich dann nicht mehr. Sonst noch ideen was falsch sein könnte?

    Nachtrag:
    Ich habe noch ein bisschen rumprobiert und mit ist dabei folgendes Aufgefallen. Es gibt nur zwei Zählerstände die jetzt noch ausgegeben werden. Der eine ist 440... der sagt mir garnicht. Unterbreche ich die gemeinsame GND versorgung von Board und Empfänger und stelle sie wieder her, wechselt dieser zu 2060 und umgekehrt (wobei der Wert nicht bei jeder unterbrechung wechselt). 2060 wären ja dann laut programm 2060 Überkäufe mit je 10µs also genau 20,6ms... kann das sein das der Controller immer nur eine taktflanke auswertet? Entweder positiv oder negativ?
    Geändert von Jeti (18.04.2013 um 13:15 Uhr)

  8. #8
    Erfahrener Benutzer Roboter Genie Avatar von Searcher
    Registriert seit
    07.06.2009
    Ort
    NRW
    Beiträge
    1.410
    Blog-Einträge
    101
    Zitat Zitat von Jeti Beitrag anzeigen
    Code:
    // Timer/Counter1 Start und Ende
    ISR (TIMER1_CAPT_vect)
    {
        if (posneg<1)
        { 
            counter=0;                                //counter zurücksetzen
            TCCR1B&=~ (1<<ICES1);                    //auf fallende Flanke triggern
            posneg=1;
        } 
        else
        {
            cli();
            Zeit=counter;                        // Zeit im µs berechnen
            TCCR1B|= (1<<ICES1);                    //auf steigende Flanke triggern
            ausgabe ();                                // Ausgabe auf Display
            posneg=0;
            sei();
        }
    }
    Noch 'ne Idee. Wenn die Ausgabe läuft, dauert das ziemlich lange. Die Impulse mit steigenden und fallenden Flanken treffen trotzdem noch am PD6 ein und das ICP Interruptflag wird gesetzt. Sobald das sei() kommt, wird deshalb sofort die ISR erneut aufgerufen von einer lange vorher aufgetretenen Flanke und verfälscht das Ergebnis?
    Vor sei() würd ich durch eine Eins Schreiben des ICF1 Bits im TIFR Register das Interruptflag sicherheitshalber löschen.

    Welche Länge können denn die Impulse haben, die vom RC-Empfänger kommen?

    Wenn Du nicht weis ob es ein Open Collector Ausgang ist, schadet es nichts, trotzdem den internen Pullup einzuschalten.

    Gruß
    Searcher
    Hoffentlich liegt das Ziel auch am Weg
    ..................................................................Der Weg zu einigen meiner Konstruktionen

  9. #9
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    26.06.2005
    Ort
    Gäufelden
    Alter
    31
    Beiträge
    109
    Danke Searcher!

    Das war die Lösung. Seit dem setzen des ICF1 Bits im TIFR Register funktioniert alles einwandfrei.

    Super!

    Gruß
    Jeti

  10. #10
    Erfahrener Benutzer Roboter Genie Avatar von Searcher
    Registriert seit
    07.06.2009
    Ort
    NRW
    Beiträge
    1.410
    Blog-Einträge
    101
    .........

    Zitat Zitat von wkrug
    Wenn die dann kommt wird das ICP Timer register ausgelesen und das Sensing auf fallende Flanke umgestellt.
    Tritt die dann auf wird das ICP Register wiederum ausgelesen un der vorherige Wert abgezogen.
    Zitat Zitat von Jeti
    Danke für die Antwort, aber ich glaube das (oder so etwas ähnliches) versuche ich doch gerade oder?
    Hallo Jeti,
    in Deinem Programm nutzt Du nur den Interrupt, den die Interrupt Capture Funktion zur Verfügung stellt. Das Gleiche könntest Du auch mit den INt0, INT1 oder INT2 Interrupts erreichen. Die schöne Funktion, die die Input Capture Funktion noch zur Verfügung stellt, ist, daß bei dem Capture event nicht nur das Interrupt Flag gesetzt wird, sondern auch gleichzeitig der Timerstand in das ICR1H/ICR1L Register kopiert wird.

    Wenn der Timer1 nun zB mit 1MHz laufen würde, bei steigender Flanke der Input Capture zuschlägt und man dann ICR1H/ICR1L sichert, auf fallende Flanke umschaltet und beim nächsten Input Capture den gesicherten Wert mit dem neuen aktuellen ICR1H/ICR1L Wert verrechnet, hat man eine Auflösung von 1µs.

    Außerdem sollte man die ISR so kurz wie möglich halten. Die Anzeigefunktion also irgendwie in die main plazieren.

    Gruß
    Searcher
    Hoffentlich liegt das Ziel auch am Weg
    ..................................................................Der Weg zu einigen meiner Konstruktionen

Ähnliche Themen

  1. IR Empfänger
    Von harry3 im Forum Elektronik
    Antworten: 2
    Letzter Beitrag: 18.02.2008, 13:38
  2. IR- Empfänger
    Von cbr600 im Forum Elektronik
    Antworten: 1
    Letzter Beitrag: 12.05.2007, 18:07
  3. 2m Empfänger
    Von lars2002 im Forum Elektronik
    Antworten: 3
    Letzter Beitrag: 07.06.2006, 09:42
  4. lw-empfänger
    Von anabolik im Forum Elektronik
    Antworten: 2
    Letzter Beitrag: 04.10.2005, 22:00
  5. atmega16
    Von ürsu im Forum AVR Hardwarethemen
    Antworten: 16
    Letzter Beitrag: 13.01.2005, 22:05

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •