- 3D-Druck Einstieg und Tipps         
Seite 2 von 4 ErsteErste 1234 LetzteLetzte
Ergebnis 11 bis 20 von 33

Thema: der ASURO als Wecker

  1. #11
    Erfahrener Benutzer Begeisterter Techniker Avatar von M1.R
    Registriert seit
    02.06.2007
    Ort
    Freiburg
    Beiträge
    213
    Anzeige

    E-Bike
    Hallo Sternthaler,

    würdest du mir vielleicht trotzdem bei Gelegenheit die Interrupt-Geschichte erklären?

    Gruss
    M.

  2. #12
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    29.05.2005
    Beiträge
    1.018
    Hallo M1.R,
    oh je mi ne.

    Ich bin mir relativ sicher, dass du schon alle möglichen Doku's gelesen hast. Ich grüble deshalb schon lange darüber nach, was ich dir da noch wie schreiben kann. Na gut, wollen wir das mal angehen.

    Vorweg:
    Es gibt unterschiedliche Arten von Interrupts.
    1) Durch externe Dinge ausgelöst: Ein Pin am Prozessor ändert die Spannung.
    2) Durch interne Dinge ausgelöst: Z.B. ein Timer läuft ab, oder der ADC ist fertig.
    3) Durch dein Programm ausgelöst: Nennt sich Softwareinterrupt und lassen wir hier weg.

    Alle Interrupts haben folgendes gemeinsam:
    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.

    Warum aber so ein Aufwand?
    Dein Hauptprogramm im Asuro hat ja folgenden Aufbau:
    Code:
    int main (void)
    {
      Init ();
      while (1)
      {
        tu_was ();
      }
      return 0;
    }
    An der Stelle tu_was(); arbeitet dein Programm deine Hauptaufgabe ab und der Asuro ist die ganze Zeit damit beschäftigt endlos etwas zu tun.
    Wenn die Aufgabe nun darin besteht, dass der Asuro einfach geradeaus fahren soll, bis ein Taster gedrückt wird um zu wenden, kannst du in der While()-Schleife ja "immer die Tasten abfragen" und dann entsprechend reagieren.
    Dieses "immer die Tasten abfragen", nennt man 'pollenden' Betrieb, da du dich in der Schleife selbst drum kümmerst, auf die Tasten zu achten.
    Somit sieht dein Programm nun ungefähr so aus:
    Code:
    int main (void)
    {
      Init ();
      while (1)
      {
        if (PollSwitch () > 0)
          fahre_ein_stueck_zurueck_und_drehe ();
        else
          tu_was ();
     }
     return 0;
    }
    Nun kommt der Interrupt ins Spiel,
    damit du dich eben nicht um solche Dinge kümmern musst.
    Hier bietet es sich natürlich an, das man einen externen Interrupt nutzt, um den durch den Taster verursachten Spannungswechsel zu registrieren.

    In der Lib gibt es dazu folgende Funktionen:
    A) Die Interruptfunktion:
    Code:
    SIGNAL (SIG_INTERRUPT1)
    {
      switched = 1;
      GICR &= ~(1 << INT1);                 // Externen Interrupt 1 sperren 
    }
    B) Die Vorbereitung, das der Interrupt am Pin INT1 zugelassen wird:
    Code:
    void StartSwitch (void)
    {
      SWITCH_OFF;                           // Port-Bit auf LOW
      DDRD &= ~SWITCHES;                    // Port-Bit SWITCHES als INPUT
      MCUCR &= ~((1 << ISC11) | (1 << ISC10));  // Low level erzeugt Interrupt
      GICR |= (1 << INT1);                  // Externen Interrupt 1 zulassen
    }
    C) Die allgemeine Erlaubnis, dass Interrupts ausgeführt werden dürfen:
    Code:
    void Init (void)
    {
      ...
      ...
      sei ();
    }
    Bis dahin haben wir nur Arbeit gehabt und noch keinen Nutzen.
    Jetzt aber wird es Spannend.

    Dein Hauptprogramm ändern wir nun ein kleines bisschen ab:
    Code:
    int main (void)
    {
      Init ();
      switched = 0;
      StartSwitch ();
      while (1)
      {
        if (switched == 1)
        {
          fahre_ein_stueck_zurueck_und_drehe ();
          switched = 0;
          StartSwitch ();
        }
        else
          tu_was ();
     }
     return 0;
    }
    Bäh. da kommt ja immer mehr Programmcode zusammen.
    Das ist zwar nicht schön, aber es bringt einen entscheidenden Vorteil. Du nutzt jetzt eine Interruptfunktion, die darauf aufpasst, ob ein Taster gedrückt wurde.
    Und was ist daran so toll?
    Du sparst enorm viel Rechenzeit in deiner while()-Schleife, da du dich dort nicht mehr darum kümmern musst die Information, ob eine Taste gedrückt wurde, zu ermitteln. Du kannst dich in deinem Programm auf die Auswertung dieser Information konzentrieren und hast dann dafür mehr Rechenzeit für die tu_was()-Funktion zur Verfügung.

    Was aber, wenn man genau wissen will welche Taste gedrückt wurde?
    Hier reicht es nun, dass im Hauptprogramm nur genau einmal die PollSwitch()-Funktion aufgerufen wird. Und zwar dann natürlich, wenn feststeht, dass eine Taste gedrückt wurde.
    Also ändern wir wieder ein bisschen:
    Code:
    int main (void)
    {
      unsigned char taste;
    
      Init ();
      switched = 0;
      StartSwitch ();
      while (1)
      {
        if (switched == 1)
        {
          taste = PollSwitch ();
          fahre_ein_stueck_zurueck_und_drehe (taste);
          switched = 0;
          StartSwitch ();
        }
        else
          tu_was ();
     }
     return 0;
    }
    Hier haben wir nun die Interruptfunktion dazu benutzt, dass uns angezeigt wird, dass irgendeine Taste gedrückt wurde. Nun holen wir wie gewohnt mit der PollSwitch()-Funktion die Info, welche Taste(n) das waren und geben diese Info einfach an unsere fahre_ein_stueck_zurueck_und_drehe()-Funktion weiter. Die kann dann entscheiden, ob nach rechts oder links gedreht wird.
    Aber entscheidend ist hier, dass die PollSwitch()-Funktion nicht permanent aufgerufen werden muss.
    Das heißt nun einfach 'Interrupt'-Betrieb. (im Gegensatz zum 'pollenden' Betrieb)

    Was uns bis jetzt noch fehlt, ist eine Möglichkeit, dass wir in unserem Hauptprogramm die Interruptfunktionalität abschalten können. Denn ist sie einmal aktiv, dann wird man sie so schnell auch nicht wieder los.

    Dafür gibt es in der Lib die folgende Funktion:
    Code:
    void StopSwitch (void)
    {
      GICR &= ~(1 << INT1);                 // Externen Interrupt 1 sperren
    }

    Und wo bitte wurde die Variable switched definiert?
    - In der Lib gibt es die Datei globals.c
    -- Darin wird mit:
    volatile int switched;
    diese Variable definiert. Hier ist es ganz wichtig, dass dieses 'volatile' angegeben ist. Damit verbieten wir dem Compiler, dass er diese Variable in einem CPU-Register speichert. Sie muss vom Compiler im RAM gespeichert werden.
    Das ist immer dann notwendig, wenn der Inhalt sowohl in der Interruptfunktion als auch außerhalb davon benutzt/geändert werden soll. Und hier wollen wir ja den Inhalt dazu benutzten, dass dein Hauptprogramm mitgeteilt bekommt das etwas passiert ist.

    Und was passiert nun eigentlich?
    - Dein Hauptprogramm macht alle technische Vorbereitungen:
    -- sei(); <== Interrupts grundsätzlich erlauben
    -- GICR |= (1 << INT1); <== Steuerbit INT1 im Steuerregister GICR setzen

    - Dein Hauptprogramm macht logische Vorbereitungen:
    -- switched = 0; <== Information initialisieren

    - Dein Hauptprogramm dreht sich im Kreis und arbeitet:
    -- tu_was();

    - Nun kommt die Wand und drückt unerwartet eine Taste
    -- INTERRUPT-FUNKTION setzt nur switched = 1;

    - Dein Hauptprogramm berücksichtigt diese Information und wertet sie aus:
    -- if (switched == 1)

    - Und zu guter letzt, initialisiert dein Hauptprogramm eine weitere Interrupt-Behandlung:
    -- if (switched == 1)
    -- {
    ---- switched = 0;
    ---- StartSwitch ();
    Dies ist hier notwendig, da die Interruptfunktion nicht nur die Variable switched auf 1 setzt, sondern hier auch noch den Punkt B) rückgängig macht und somit einen weiteren Tasteninterrupt nicht mehr zulässt.
    Dies ist hier sinnvoll, da der Interrupt sonst so lange permanent aufgerufen wird, bis alle Tasten losgelassen wurden. Das aber wiederum dauert aus CPU-Sicht sehr, sehr lange bis die Motoren den Asuro endlich von der Wand wegbewegt haben. Und das wiederum würde uns nur kostbare Rechenzeit stehlen.


    So, da ich nicht weiß, ob dir diese Beschreibung überhaupt weitergeholfen hat, höre ich hier erst einmal auf. (Ist doch etwas aufwändig)
    Wenn dir das aber helfen konnte, dann melde dich mal, und ich werde auch noch zu internen Interrupts (ADC, Timer) etwas schreiben.

    Gruß, und natürlich ein 'Schönes neues Jahr' wünscht dir
    Sternthaler
    Lieber Asuro programieren als arbeiten gehen.

  3. #13
    Erfahrener Benutzer Robotik Einstein Avatar von inka
    Registriert seit
    29.10.2006
    Ort
    nahe Dresden
    Alter
    77
    Beiträge
    2.180
    hi sternthaler,
    auch ich habe auf deine antwort zu den interrupts gespannt gewartet...wie immer sehr lehrreich, kurz & prägnant, mit praktischen - asuro - beispielen ergänzt...danke...
    gruß inka

  4. #14
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    29.05.2005
    Beiträge
    1.018
    Guten Morgen zusammen.

    Zitat Zitat von inka
    .. kurz & prägnant, ..
    Ich dachte eher, das dies ein Buch wird. :P
    Wenn ihr noch mehr haben wollt, sagt Bescheid. Ich hätte da z.B. die Verschachtelung von Interrupts auf Lager. So á la Timer-Interrupt startet ADC nachdem Taster-Interrupt ausgelöst wurde um ADC-Interrupt zu provozieren.

    Gruß Sternthaler
    Lieber Asuro programieren als arbeiten gehen.

  5. #15
    Moderator Robotik Einstein Avatar von damaltor
    Registriert seit
    28.09.2006
    Ort
    Milda
    Alter
    38
    Beiträge
    4.064
    deine geduldist bewundernswert. ohne diskussion. wir sollten mal beginnen, die lehrreichsten beitrage z uprämieren
    Read... or die.
    ff.mud.de:7600
    Bild hier  

  6. #16
    Erfahrener Benutzer Begeisterter Techniker Avatar von M1.R
    Registriert seit
    02.06.2007
    Ort
    Freiburg
    Beiträge
    213
    Hallo Sternthaler,
    dir auch ein Gutes Neues!
    Vielen , vielen Dank für deine ausführliche Erläuterung!
    Meine Hoffnung steigt, dass ich die Interrupts doch noch eines Tages kapieren werde.
    Da im Moment mein PC krank ist, kann ich mich vorläufig leider noch nicht näher damit befassen.
    (Ohne Ausprobieren hilft mir alle Theorie nicht wirklich weiter)
    Dafür bin ich zur Zeit am Zusammenbasteln meines Dosen-ASUROs "DORO M2.R". Vor ein paar Tagen hat er seinen Mechanik-Test bestanden:
    http://de.youtube.com/watch?v=qkaaG6ElcVE
    Jetzt ist auch die Platine fertig gelötet und der Selbsttest scheint zu funktionieren, soweit ich das ohne IR-Kommunikation beurteilen kann.
    Gruss
    M.

    @damaltor
    Zitat Zitat von damaltor
    deine geduldist bewundernswert. ohne diskussion. wir sollten mal beginnen, die lehrreichsten beitrage z uprämieren
    du bist auch sehr geduldig mit uns Doofies - von dir habe ich schon sehr viel gelernt!
    Gruss
    M.

  7. #17
    Moderator Robotik Einstein Avatar von damaltor
    Registriert seit
    28.09.2006
    Ort
    Milda
    Alter
    38
    Beiträge
    4.064
    danke... aber irgendwann haben wir alle mal klein angefangen...
    Read... or die.
    ff.mud.de:7600
    Bild hier  

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

    kurzer Zwischenbericht zu den Interrupts:
    das Prinzip habe ich jetzt (glaube ich) verstanden, zumindest bei der Tastergeschichte

    Nach unserem Roboter-Wettbewerb werde ich mich weiter damit beschäftigen und versuchen mit den internen Interrupts klarzukommen. Dann melde ich mich wieder.

    Also nochmal vielen Dank!

    Gruss
    M.

  9. #19
    Erfahrener Benutzer Robotik Visionär Avatar von oberallgeier
    Registriert seit
    01.09.2007
    Ort
    Oberallgäu
    Beiträge
    8.686
    Hallo Sternthaler,
    Zitat Zitat von Sternthaler
    ... hätte da z.B. die Verschachtelung von Interrupts auf Lager...
    Jetzt schlag mich bitte nicht, wenn ich als Newbie mit Besserwisserischer i-Tüpfel-Reiterei daherkomme. Interrupts sind ja beim AVR hardwaremässig so implementiert, dass sie immer sequentiell abgearbeitet werden. Schachteln dagegen erinnern mich an diese Babutschkas - die russischen Holzpuppen. In einer ist dann wieder eine, die enthält eine, die enthält eine - - - so sehe ich "verschachtelt".

    AVR-Interrupts sind ja sehr brav und geradeaus - da wird IMMER erst eine Arbeit fertig gemacht. Das ist doch ein wichtiger, kleiner und wirklich feiner (im Sinne von prächtig, nicht von "dünn") Unterschied.

    Daher muß ja Dein Beispiel
    ... So á la Timer-Interrupt startet ADC nachdem Taster-Interrupt ausgelöst wurde um ADC-Interrupt zu provozieren ...
    auch sequentiell abgearbeitet werden, oder irre ich mich?

    Verschachtelte Interrupts stelle ich mir so vor - mit wirklich verschachteltem Ablauf - nicht nur mit verschachteltem Request:
    Code:
    [Interrupt 1 fängt an und ..
        [Interrupt 2 fängt an und ...
            [Interrupt 3 fängt an ... fertig
            ]
         .. I2 macht weiter ... fertig
        ]
     .. I1 ... fertig
    ]
    . . und ich glaube ziemlich sicher, ich hätte das beim seligen Z80 so gehabt. Ich glaube, bayerische Programmierer nennen so eine Interrupt-Organisation statt verschachtelt "verschandelt".
    Ciao sagt der JoeamBerg

  10. #20
    Moderator Robotik Einstein Avatar von damaltor
    Registriert seit
    28.09.2006
    Ort
    Milda
    Alter
    38
    Beiträge
    4.064
    Zitat Zitat von oberallgeier
    Hallo Sternthaler,
    Zitat Zitat von Sternthaler
    ... hätte da z.B. die Verschachtelung von Interrupts auf Lager...
    Jetzt schlag mich bitte nicht, wenn ich als Newbie mit Besserwisserischer i-Tüpfel-Reiterei daherkomme. Interrupts sind ja beim AVR hardwaremässig so implementiert, dass sie immer sequentiell abgearbeitet werden. Schachteln dagegen erinnern mich an diese Babutschkas - die russischen Holzpuppen. In einer ist dann wieder eine, die enthält eine, die enthält eine - - - so sehe ich "verschachtelt".

    AVR-Interrupts sind ja sehr brav und geradeaus - da wird IMMER erst eine Arbeit fertig gemacht. Das ist doch ein wichtiger, kleiner und wirklich feiner (im Sinne von prächtig, nicht von "dünn") Unterschied.
    das stimmt nicht ganz - wenn man das interrupt enable bit manuell wieder setzt bzw sei ausführt in der interruptroutine, können interrupts durchaus geschachtelt werden. allerdings erst ab diesem moment.
    Read... or die.
    ff.mud.de:7600
    Bild hier  

Seite 2 von 4 ErsteErste 1234 LetzteLetzte

Berechtigungen

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

12V Akku bauen