• Offizieller Beitrag

    Der INT-Eingang ermöglicht praktisch eine einfache Art und Weise, wie man im Programm die Flankenwechsel von dem Empfängersignal mitkriegt.

    Zitat

    Der andere Weg ist das Pollen eines Portpins der als Eingang geschaltet ist. Auch das geht, ist aber kniffliger und man muss besser aufpassen was man tut...


    Im Prinzip muss man ständig (nach der kleinen Aktion im Programm) sofort wieder die Ports abfragen und dann analysieren, ob sich da was an dem Empfängereingant getan hat. Sonst kommt man zu spät und die Messung von der Pulslänge ist nicht korrekt.
    Dieses ständige "nachsehen" bläht den Code etwas auf. Aber er ist etwas "betriebssicherer".

    In der Praxis würde das Programm mit dem INT-Eingang so funktionieren, dass Du zunächst mal einstellst, dass dieser Eingang auf einen positiven Flankenwechsel reagierst. Dann machst Du im Programm Deine ganz normale Geschichte, also PWM ansteuern usw. . Aber diesmal nicht die Ports manuell überwachen.
    Sobald jetzt der Empfänger eine positive Flanke schickt (= Beginn des Pulses), wird der Interrupt ausgelöst. Das Programm springt dann vom aktuellen Stand sofort in diese Subroutine. Dort startests Du dann den Timer, um die Zeit für die Pulslänge zu messen.
    Jetzt kommt der Gag: Du musst diesen Interrupt-Port jetzt umprogrammieren, damit er nicht mehr auf eine steigende Flanke, sondern auf eine fallende Flanke reagiert. Dann verlässt Du diese Subroutine und Dein Programm macht wieder da weiter, wo Du vorher warst.
    Irgendwann ist das Empfängersignal beendet, es gibt eine fallende Flanke. Der Interrupt wird ausgelöst, das Programm springt in die Interrupt-Subroutine und Du mist den aktuellen Stand des Timers. Kannst dann die Differenz ausrechnen und weist, wie lange das Empfängersignal war. Dann den Interrupteingang wieder auf "steigende Flanke" umstellen, damit das nächste Empfängersignal erwischt wird.

    Durch diese Interrupt-Routine ist das alles etwas übersichtlicher im Code. Vor allem brauchst Du jetzt nicht mehr aufpassen, dass ein Teil im Programm zu lange braucht, weil Du sonst die Abfrage vom Timer (bei einem Flankenwechsel des Empfängersignals) verschlafen hättest.

    Nachteil der Interrupt-Methode: Sobald ja eine Flankenänderung ist, wird das Programm hektisch und springt in die Interrupt-Subroutine hinein. Wenn Du Störungen am Empfängerpegel hast, dann wird Dir bei jedem kleinen Spike das Programm in die Routine springen. Also ständig da hinein-/herausspringen und Blödsinn einlesen. Damit kannst du den Prozessor praktisch "tot" machen, er tut nichts anderes mehr.

    Ich habe mich deshalb für die etwas mühsamere aber betriebssichere Methode entschieden. Das war zu der Zeit, als man nur mit 40MHz-Funken agierte und Störungen die Regel waren.
    Mittlerweile gibt es die 2.4GHz-Funken. Und die Störungen sind praktisch weg. Ich könnte also auch die zweite Möglichkeit mit der Interrupt-Methode empfehlen. Sobald Du aber mal ausnahmsweise eine 40MHz-Funke anhängst, hätte ich dazu Bausschmerzen....

    Aber: Die Hinweise von den beiden Atmel-Profis waren gut. Du solltest den Empfängereingang ruhig auf einen Port legen, wo man damit auch sogenannte Hardware-Interrupts auslösen kann. Ich bin sicher, dass Du das irgendwann mal ausprobieren wirst. ;)

    • Offizieller Beitrag
    Zitat

    Du musst diesen Interrupt-Port jetzt umprogrammieren, damit er nicht mehr auf eine steigende Flanke, sondern auf eine fallende Flanke reagiert.

    Der Atmel kann (im Gegensatz zum Pic16 :rolleyes: ) auch einen Interrupt bei jedem Flankenwechsel generieren. Dann frägt man einfach in der Interrupt-Routine den neuen Zustand ab und kann die Int-Register in Ruhe lassen.

    Zitat


    Wenn Du St�rungen am Empf�ngerpegel hast, dann wird Dir bei jedem kleinen Spike das Programm in die Routine springen. Also st�ndig da hinein-/herausspringen und Bl�dsinn einlesen. Damit kannst du den Prozessor praktisch "tot" machen, er tut nichts anderes mehr.


    Ich würde da eh noch einen kleinen RC-Tiefpass in die Leitung bauen und für alle größeren Störungen kann man ja min/max Grenzwerte in der Software definieren.

    • Offizieller Beitrag
    Zitat

    ...kann man ja min/max Grenzwerte in der Software definieren....


    Das ist klar, dass die Werte, die nicht in das Zielraster passen (< 0.8ms ; > 2.2ms) weggeworfen werden. Aber dann ist's eigentlich schon zu spät, denn die Interrupt-Routine wurde ja schon ein paarmal durch die Störungen unnötigerweise aufgerufen.

    Zitat

    Der Atmel kann (im Gegensatz zum Pic16 Augen rollen ) auch einen Interrupt bei jedem Flankenwechsel generieren.


    Ich kenne die Atmels selber ja nicht. Aber derjenige, der die kleinen Fahrtregler für die Mikromodelle baut und programmiert, von dem habe ich das auch so gehört, dass er bei jedem Flankenwechsel die Flankenrichtung umändern muss. Ist schon ein paar Jahre her, es kann sich also durchaus was bei den Atmels geändert haben. (... andere Familie, andere Features, ...)

  • Dake für die rege Beteiligung an dem Projekt! Oh mann da kommt ja mehr und mehr auf mich zu! o_O

    Ich sollte dann wohl erstmal einen PWM-Chip ausfindig machen und schauen wie das so funktioniert... Hab noch nie mit diesen Bausteinen gearbeitet...


    Die Interrupt-Methode find ich aber super!

    Zitat

    Ich bin sicher, dass Du das irgendwann mal ausprobieren wirst

    Ich hab sogar schon mit Interrups gearbeitet. Bei meinen IR-Endschaltern löse ich einen Overflow-Interrupt meines 8bit-Timers aus um meine IR-LED zu pulsen ;)

    War garnicht so leicht, das so ganz zu begreifen (z.B. die spezielle Schreibform bzw. das jeder Prozessor seine eigenen Bezeichnungen der Interrupt-Vektoren hat z.B.: TIM0_OVF_vect)... ;)

    • Offizieller Beitrag
    Zitat

    Schmitt-Trigger für definierte Pegel wie IBF das macht ebenfalls...


    Ja, das beruhigt ungemein, wenn man weis, dass es nicht irgendeinen blöden Zwischenzustand geben kann, nur weil der EmpfängerX ein anderers Ausgangssignal als der EmpfängerY hat.

    Hinweis:
    Bei den Schmitt-Triggern aufpassen, dass man einen erwischt, der auch unterhalb von 3V noch auslöst. Ich hatte zunächst einen 74HC14 eingesetzt. Der hat 3V. Klappte bei den von Futaba mitgelieferten Empfängern wunderbar. Sobald ich dann einen Empfänger-Nachbau eingesetzt hatte, war der Ausgangspegel nur noch 2.8V statt 3.1V. Und schon ging nichts mehr. Ich empfehle den 74HCT14 als Schmitt-Trigger.

  • Hö?? Okok ich glaube ich hab da was missverstanden...

    Meintet ihr mit Hardware-PWM etwa den 16bit-Timer (den ich eigendlich von Anfang an benutzen wollte)??

    Hab das jetzt mit "Hardware-PWM" so verstanden, einen externen PWM-Chip zu benutzen... ;)

    • Offizieller Beitrag

    Bei den Atmels kann ich ja nicht im Detail mitreden. Aber normalerweise braucht ein PWM-Ausgang einen Timer, damit er seine Zeiten "messen" kann. Normalerweise kann man dem PWM-Ausgang sagen, welcher von den vielen Timern er als Zeitmesser verwenden soll. Für Deine Anwendung würde ein stinkordinäer 8bit-Timer vollkommen ausreichen.

    Die Standard-Ein-/Ausgänge müssen bei der Initialisierung dann von "Standard" auf "PWM" umgestellt werden. Da geht nicht jeder Pin, muss man im Datenblatt des Prozessors nachsehen. Such' mal unter "Capture Compare" und dann "PWM" bzw. "CCP", so heißen die Ausgänge beim PIC. :D

    Normalerweise sind dann zwei zusätzliche Register da, in denen Du die Gesamtlänge (=Periodendauer) schreibst und dann, je nach gewünschter Pulslänge, den zugehörigen Timerwert für die Länge des Pulses.

    Bei der Initialisierung musst Du dann den zugehörigen Timer des PWM einstellen, wie lange der Timer gesamt laufen soll. Stichwort sind Pre- und Postscaler. Also irgendwelche Vorteiler, wo Du dann einstellen kannst, wie lange die reale Periodendauer sein wird, wenn der Timer zwischen 0 und 65535 (=16bit) läuft. Du kannst damit auswählen, ob er zwischen 0 bis 65535 Mikrosekunden laufen soll, oder (bei einem Vorteiler von 1:128 ) von 0 bis 8388480 Millisekunden braucht. (Bei einem Takt von 1Mikrosekunde pro Prozessorclock, weis ich jetzt nicht, wie der Timer vom Prozessortakt abhängig ist... .)

    Tipp: Mach' mal ein kleines Miniprogramm mit einem provisorisch verdrahtetem Atmel, wo Du den PWM ergründest. Da gibt's bestimmt auch ein paar Fallstricke, die dafür sorgen, dass der PWM nicht richtig anläuft. Die Prozessoren können mittlerweise so viel, da wird's schwierig, immer genau das einzustellen, was man gerne haben will. => Das Oszilloskop am PWM-Pin ist Dein Freund ! :D;)

  • Wie die PWM-Steuerung mit dem 16bit Timer (den ich übrigens als 10bit Timer betreibe) funktioniert weiß ich, so hab ich doch meinem Nibo das fahren beigebracht. Ist eig. nicht schwer!

    Ich glaube wir reden etwas aneinander vorbei. ;)

    Also PWM per Timer (auch die passenden Ausgänge etc.) ist mir alles ziemlich klar.

    War nur etwas irritiert, als ihr mir das mit dem Hardware-PWM erzähltet, da ich dachte damit meintet ihr einen externen PWM-Chip

    Hier nochmal ein Ausschnitt aus meinem Programm um meinen Nibo Ferngesteuert zu fahren:

    void TIMER1_init() // 16Bit PWM-Timer 1 configuration's
    {
    // Connect output Pin Channel 1
    TCCR1A |= (1 << COM1A0); // Channel 1 als invertierende PWM
    TCCR1A |= (1 << COM1A1); // Wird beim hochzählen der Vergleichswert erreicht, so wird der PIN OC1 auf "1" gesetzt.

    // Connect output Pin Channel 2
    TCCR1A |= (1 << COM1B0); // Channel 2 als invertierende PWM
    TCCR1A |= (1 << COM1B1); // Wird beim hochzählen der Vergleichswert erreicht, so wird der PIN OC2 auf "1" gesetzt.

    // PWM Mode-Select-Bits Channel 1+2
    TCCR1A |= (1 << WGM10); // 10bit Phase correct CH1
    TCCR1A |= (1 << WGM11); // 10bit Phase correct CH1
    TCCR1B &= ~(1 << WGM12); // 10bit Phase correct CH2
    TCCR1B &= ~(1 << WGM13); // 10bit Phase correct CH2

    // Clock select Channel 1+2
    TCCR1B &= ~(1 << CS10); // PWM Prescaler
    TCCR1B |= (1 << CS11); // CPU-Takt / 8
    TCCR1A &= ~(1 << CS12); // 2MHz
    }

    Also dieses Wissen habe ich mir schon mühsam erarbeiten müssen. ;)

    Einmal editiert, zuletzt von Replikator (6. November 2012 um 14:20)

    • Offizieller Beitrag
    Zitat

    Original von Replikator
    Wie die PWM-Steuerung mit dem 16bit Timer (den ich übrigens als 10bit Timer betreibe) funktioniert weiß ich, so hab ich doch meinem Nibo das fahren beigebracht. Ist eig. nicht schwer!

    Ich glaube wir reden etwas aneinander vorbei. ;)

    Also PWM per Timer (auch die passenden Ausgänge etc.) ist mir alles ziemlich klar.

    Jo ok, sorry! War nicht "besserwissertechnisch" gemeint. :D Ich hatte mich schon gewundert, dass Du das mit den Interrupts noch nicht wusstest.

    Im Prinzip ist die Auslösung des Hardware-Interrupts bei einer steigenden/fallenden Flanke des Empfängersignals also identisch zu handeln, wie der Software-Interrupt.

    (An eure genormte C-Schreibweise werde ich mich wohl nie gewöhnen ...
    TCCR1B &= ~(1 << CS10); // PWM Prescaler
    Ein Hoch auf meine PICs: CS10 =1; ... und schon wird das Bit gesetzt. :D )