- 3D-Druck Einstieg und Tipps         
Seite 4 von 4 ErsteErste ... 234
Ergebnis 31 bis 33 von 33

Thema: der ASURO als Wecker

  1. #31
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    29.05.2005
    Beiträge
    1.018
    Anzeige

    LiFePo4 Akku selber bauen - Video
    Hallo M1R,
    schön, dass dir die Beschreibung gefallen hat.
    Ja, das Angebot steht noch, und es kann sich nur noch um Monate handeln, bis ich dann da weiter mache.

    Hier muss ich erst mal deine sehr übersichtliche und einheitliche Schreibweise vom Code loben. Ich bin da immer extrem pingelig, aber bei deinem main()-Teil gab es (fast) nichts, was ich während des Lesens umformatiert habe. Echt Klasse.


    2 Anmerkungen zu deinem main():

    1:
    Folgenden Code kannst du noch ändern, um besser zu sehen, dass das Hauptprogramm nur etwas tun muss, wenn der Interrupt etwas ausgelöst hat:
    Code:
       StartSwitch ();
       while (switched == 0)   // wenn kein taster gedrückt ist rot leuchten
       {
          PORTB &= ~(1<<PB0);  // grün ausschalten
          PORTD |=  (1<<PD2);  // rot einschalten
       }
    
    umbauen zu:
    
       // rot hier nur einmal einschalten
       PORTB &= ~(1<<PB0);     // grün ausschalten
       PORTD |=  (1<<PD2);     // rot einschalten
    
       StartSwitch ();
       while (switched == 0)   // wenn kein taster gedrückt ...
       {
          // ... wird hier normalerweise dein Hauptprogramm ackern und
          //     heftigste Berechnungen und Motorsteuerungen machen.
          //     Allerdings darf hier auch nicht zu viel Zeit zur Bearbeitung
          //     benötigt werden, da diese Code-Konstruktion ja sonst nicht
          //     schnell genug wieder zum while() kommt um zu reagieren.
       }
       // ... und jetzt erst muss der Motor gestoppt
       //     der Rückwärtsgang eingelegt,
       //     und die getroffene Wand umfahren werden.
    Das ist jetzt für deinen Programmablauf zwar nur Haarspalterei, aber genau darum geht es ja bei den Interrupts. Es soll eben nichts 'überflüssiges' während der while()-Arbeitsschleife gemacht werden, da ja der Interrupt bzw. die Information in der Variablen switched nur dann eine Reaktion in deinem Hauptprogramm erzeugen soll, wenn der Interrupt etwas zu sagen hatte. (switched == 1)


    2:
    Erst einmal liegst du vollkommen richtig, dass es mit der Interruptfunktion "SIGNAL (SIG_OVERFLOW2)" zu tun hat.
    Eigentlich ist es nicht unbedingt notwendig dort etwas zu ändern, da 'im Prinzip' schon alles vorhanden ist, aber zum Verständnis mal folgendes:

    Annahme von mir: Deine Variable zeit sieht mir danach aus, dass du sie als Sekundenzähler nutzen willst.
    ==> if (zeit == 1) // und jetzt nach 1 sek ...
    Also muss sich der Timer2-Interrupt um diese Variable kümmern. (Du hast sie mit "volatile int zeit;" schon richtig angelegt.)

    So ist es bei dir angegeben:
    Code:
    //----------------------------------------------------------------
    //Interruptfunktion timer2 in asuro.c
    SIGNAL (SIG_OVERFLOW2)
    {
      TCNT2 += 0x25;
      count36kHz ++;
      if (!count36kHz)
        timebase ++;
    #ifdef RC5_AVAILABLE
      if (enableRC5 && !(count36kHz % 8))
        IsrRC5(); // wird alle 222.2us aufgerufen
    #endif 
    }
    Den Teil zwischen "#ifdef RC5_AVAILABLE" und "#endif" ignorieren wir hier komplett. m.a.r.v.i.n hat hierzu eine tolle Beschreibung in der HTML-Doku zur Lib direkt auf der Startseite unter dem Punkt "Neue Projekte" geschrieben.

    Es bleibt übrig:
    Code:
    //----------------------------------------------------------------
    //Interruptfunktion timer2 in asuro.c
    SIGNAL (SIG_OVERFLOW2)
    {
      TCNT2 += 0x25;
      count36kHz ++;
      if (!count36kHz)
        timebase ++;
    }
    Nun noch mal überlegen. Wann wird diese Funktion überhaupt aufgerufen?
    Ja genau. Immer dann wenn der Timer2 eine bestimmte Zeit gearbeitet hat.
    Die Vorgabe zur Initialisierung vom Timer2 hast du ja schon gefunden und als eigene Funktion in TimerInit() eingebaut.
    Und wann ist "eine bestimmte Zeit" nun genau?

    Achtung: Es wird nun kompliziert, aber die Initialisierung ist hier das A und O.
    Also mal die Bit genauer betrachten, die in den Registern gesetzt werden:

    - Register TCCR2
    -- WGM20 und WGM21 setzen den Timer in den "Fast PWM"-Mode
    -- COM20 und COM21 setzen im "Fast PWM"-Mode einen 'Output Compare Mode'
    -- auf 'Set OC2 on Compare Match, clear OC2 at TOP
    -- CS20 setzt einen Takt-Vorteiler auf 1 (8MHz / 1 = 8MHz-Takt)

    Für unsere Zeitfunktion ist es nun wichtig zu 'wissen' (Doku zur CPU), dass der 8-Bit-Zähler TCNT2 so initialisiert ist, dass er mit dem Takt von 8MHz immer von 0 bis 255 hochzählt und dann einfach wieder neu bei 0 anfängt.
    Außerdem wird noch, jetzt aufpassen, unser gewünschte Interrupt immer 'vorbereitet', wenn der Zähler bei 255 ankommt.
    Um diesen 'vorbereiteten' Interrupt auch tatsächlich zu erhalten, muss noch im:
    - Register TIMSK
    -- TOIE2 gesetzt werden.


    Jetzt können wir mal rechnen, wie lang unsere "bestimmte Zeit" nun eigentlich ist. (Teil 1, da noch nicht alles richtig sein wird)
    -> 8MHz vom Quarz geteilt durch Takt-Vorteiler 1 geteilt durch 256 (8-Bit-Zähler) sind nun
    -> 8000000Hz / 1 / 256 = 31250Hz <== Noch nicht 32kHz.
    -> Die "bestimmte Zeit" ist dann 1 / 31250Hz = 0,000032Sekunden

    Nach (ungefähr) dieser Zeit bekommen wir somit den ersten Interrupt.

    Im Interrupt aber passiert nun als aller erstes folgendes:
    -- TCNT2 += 0x25; // 0x25 sind dezimal 37
    Hier wird der Zähler TCNT2 'einfach mal zum Spaß' um 37 Werte größer gemacht.
    Da der Interrupt ja immer dann kommt, wenn der Zähler TCNT2 aber gerade bei 255 ist, und schon wieder zur 0 umschlagen möchte, heißt dies, dass der Zähler eigentlich nur von 37 bis 255 läuft.
    Tut er aber auch nicht, da das "TCNT2 += 0x25;" schon 3 Takte kostet, und somit von 37 – diese 3 Takte bis 255 läuft.
    Und warum 3 Takte und warum -?
    - Auslesen, addieren und wieder schreiben vom Register TCNT2 kosten jeweils einen Takt.
    - In Wirklichkeit läuft die Zeit ja weiter bevor wir mit der Registermanipulation fertig sind.

    Jetzt ein neues 2.tes rechnen:
    -> 8000000Hz / (256 - (37-3)) = 8000000Hz / 222 = 36036,...Hz <== Da sind unsere guten 36kHz


    Uff, jetzt geht es einfach weiter:
    36036Hz sind in Sekunden: 1 / 36036Hz = 0,00002775... Sekunden
    -- count36kHz ++; zählt also in dieser Zeit um 1 weiter.


    Nun müssen wir nur noch deine ursprüngliche Frage beantworten.
    Was muss im Interrupt gemacht werden, damit wir dort einen Zähler bekommen, der genau jede Sekunde um 1 weiterzählt?

    Wir müssen nur eine bestimmte Anzahl von Interrupts abwarten, bis wir deine Variablen zeit um 1 hochzählen können.
    Diese Anzahl ist jetzt leicht auszurechnen:
    1 Sekunde (wollen wir haben) durch 0,00002775... Sekunden (Unsere "bestimmte Zeit" vom Interrupt)
    -> 1 Sekunde / 0,00002775... Sekunden = 36036
    Upps, ist ja die Frequenz von 36kHz. Soll ja auch so sein, da Hz nun mal "Takte pro Sekunde" sind

    Also im Interrupt nun:
    Code:
    //----------------------------------------------------------------
    //Interruptfunktion timer2 in asuro.c
    SIGNAL (SIG_OVERFLOW2)
    {
    static int teiler = 0;  // static ist dafuer da, dass der Variablen-
                            // inhalt nicht verloren geht, wenn die
                            // Funktion beendet wird. 
    
      TCNT2 += 0x25;
      count36kHz ++;
      if (!count36kHz)
        timebase ++;
    
      teiler ++;
      if (teiler == 36036)
      {
        teiler = 0;
        zeit ++;
      }
    
    #ifdef RC5_AVAILABLE
      if (enableRC5 && !(count36kHz % 8))
        IsrRC5(); // wird alle 222.2us aufgerufen
    #endif 
    }

    So, damit glaube ich, dass auch der Timer-Interrupt nicht mehr so im dunkeln liegt.
    Auch hier hat es sich ja nun heraus gestellt, dass das wie bei den Tastern erklärte Prinzip vorhanden ist:
    A) Ein Programmcode in der Interruptfunktion muss von dir geschrieben werden.
    B) Der entsprechende Interrupt muss über das dazugehörende Bit im entsprechenden Steuerbyte zugelassen werden.
    C) Der CPU muss generell erlaubt werden Interrupts auszuführen.
    D) Die Verarbeitung im Hauptprogramm muss sich auf Interrupts einstellen.

    A) ist nun die Bearbeitung der Variablen teiler und zeit.
    B) war hier natürlich der einfachste Teil mit dem "TIMSK |= (1 << TOIE2);"
    Kompliziert war es ja nur an der Stelle zum Initialisieren des Timer 2 und der von waste erfundenen Manipulation am TCNT2-Register im Interrupt selbst .
    Ist schon stark, was 4 Zeilen Code alles anrichten können!
    C) hast du in deinem main() zu Anfang erledigt.
    D) musst du allerdings noch etwas umbauen.
    Hinter deinem Aufruf von TimerInit() fragst du ja sofort die Interrupt-Information zeit ab.
    Natürlich ist da dann noch keine Sekunde vergangen. Somit wirst du dann die LED nicht auf gelb setzen sondern sofort zum Ende deines Programms kommen.
    Hier hilft zum testen auch erst einmal ein schnuckeliges while():
    Code:
       // und jetzt nach 1sek led gelb mit timer2 interrupt ?????????
       //----------------------------------------------------------------
       // timer2 Interrupt
       zeit = 0;
       TimerInit ();
       while (zeit != 1)    // warten, bis die zeit bei 1 angekommen ist
          ;
       PORTB |=  (1<<PB0);  // grün einschalten
       PORTD |=  (1<<PD2);  // rot einschalten
       //----------------------------------------------------------------

    Ich hoffe, du konntest meiner Schwafelei folgen, und das dein 2-Zeiler
    Kann es sein, das ich hierfür die "SIGNAL (SIG_OVERFLOW2)" ändern müsste?
    Leider ist mir diese Funktion ziemlich unverständlich.
    nun nie wieder von dir ausgesprochen werden muss
    Klar, wenn noch (oder noch mehr?) Fragen sind, nur zu.

    Gruß Sternthaler
    Lieber Asuro programieren als arbeiten gehen.

  2. #32
    Erfahrener Benutzer Begeisterter Techniker Avatar von M1.R
    Registriert seit
    02.06.2007
    Ort
    Freiburg
    Beiträge
    213
    Hallo Sternthaler,

    vielen, vielen Dank schonmal!

    Wie immer gefällt mir deine "Schwafelei" (= anschauliche und unterhaltsame Art, komplizierte Dinge zu erklären) sehr gut.

    Es kann ein paar Tage dauern, bis ich dazukomme mich weiter damit zu befassen. Dann melde ich mich wieder.

    Schöne Grüsse
    M.

  3. #33
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    29.05.2005
    Beiträge
    1.018
    Hallo Biene Maja (hier bekannt als M1.R),
    "Honig, Honig, Honig" deine Übersetzung von 'Schwafelei'. \/

    Das ist gut wenn du dir Zeit nimmst, denn es ist tatsächlich nicht so einfach der Initialisierung und dieser 'undurchsichtigen' Zeile mit dem += 0x25 im Interrupt zu folgen.

    Hier noch ein Hinweis zu dem von mir nicht beschriebenem:
    'Output Compare Mode' setzen auf 'Set OC2 on Compare Match, clear OC2 at TOP'
    Dies ist nicht relevant für unsere Zeitbetrachtung. Es ist aber sehr wichtig für die Funktionsweise der IR-Kommunikation.

    Die eine Seite der Sende-IR-LED hängt ja am Port-Pin PB3. Dieser ist durch die Initialisierung in Init() mit dem Register-Bit OC2 verbunden.
    Wenn also dieser ominöse 'Output Compare Mode' ein 'Set OC2' und 'Clear OC2' macht, heisst dies, dass an diesem Port-Pin mal +5V (Set) und mal 0V (Clear) anliegen. Somit wird das Licht an der Sende-LED genau mit den 36kHz ein- und ausgeschaltet. Das passiert aber auch nur dann, wenn überhaupt Strom durch die LED fliesst. Dies kann nur bei 'Set OC2' und 0-Datenbit am Sendeausgang Tx passieren.
    Somit werden 0-Datenbits als Licht mit 36kHz getaktet gesendet.
    1-Datenbits hingegen bleiben im Dunkeln verborgen.
    --> Und genau so möchte der Empfänger die Daten haben. <-- 'Tolle Kiste'

    Des weiteren möchte der Empfänger am liebsten haben, dass dieses ein- und ausschalten so passiert, das 'ein' und 'aus' (möglichst) gleich lang sind.
    Dafür zuständig ist noch das
    --- OCR2 = 0x91; // duty cycle fuer 36kHz <-- Schlechter Kommentar, sollte eher 'duty cycle 50% bei 36kHz' lauten.

    - clear OC2 at TOP <-- TOP bedeutet hier, dass TCNT2 bei 255 angekommen ist.
    - Set OC2 on Compare Match <-- bedeutet hier, dass TCNT2 bei OCR2 angekommen ist.

    0x91 sind ja 145
    'Set OC2' also bei TCNT2 von 145 bis 255. Sind (grob gerechnet) 110 Takte
    Von 255 über 0; plus die 37 im Interrupt und dann wieder bis 145 sind nun auch (grob gerechnet) 110 Takte.
    Also 110 Takte Licht an und auch 110 Takte Licht aus. <-- Schon wieder eine 'Tolle Kiste' , da dies die 50% sind.


    Auch hier: 'Eile mit Weile' beim lesen und verstehen.
    Gruß Sternthaler
    Lieber Asuro programieren als arbeiten gehen.

Seite 4 von 4 ErsteErste ... 234

Berechtigungen

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

Solar Speicher und Akkus Tests