- 3D-Druck Einstieg und Tipps         
Seite 2 von 2 ErsteErste 12
Ergebnis 11 bis 17 von 17

Thema: Dividieren

  1. #11
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    08.08.2004
    Ort
    Zwolle
    Alter
    68
    Beiträge
    531
    Anzeige

    E-Bike
    Hallo RedBaron

    Wie leitest du die Interrupt-Routine ein? mit SIGNAL oder INTERRUPT?
    Mit SIGNAL, aber wass ist den uberhaupt INTERUPT? Die kenn ich noch nicht.

    Ubrigens gibts mehr fremde Dinge mit interrupts. Ich benutze ein integer zahler im interrupt. Wenn ich die so deklariere:

    static unsigned int uiMeinZahler;
    Dann wird:
    if(uiMeinZahler==1000){
    NICHT ausgefuhrt, und wenn deklariert als globalen variabele

    volatile unsigned int uiMeinZahler;
    dann funktioneirt es.

    Fremd...

    gruss

    Henk

  2. #12
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    25.10.2005
    Alter
    71
    Beiträge
    157
    Hallo Henk,

    eine mit SIGNAL deklarierte Routine wird normalerweise nicht durch andere Interrupts unterbrochen. Eine mit INTERRUPT deklarierte schon, wenn der neue Interrupt eine höhere Priorität hat.

    Schaltest du in deiner Routine explizit oder durch eine andere Funktion, die du aufruftst, die Interrupts wieder ein? (z.B. durch 'sei()').

    -------------------

    Die Lösung zum Problem mit 'uiMeinZahler' liegt im Schlüsselwort 'volatile'. Wenn eine Variable als 'volatile' gekennzeichnet ist, geht der Compiler davon aus, dass sich der Wert asynchron zum eigentlichen Programmfaden (thread) ändert (also z.B. durch einen zwischendurch aufgetauchten Interrupt). Der Variablenwert wird deshalb bei jedem Zugriff erneut aus dem Speicher geladen.

    Ist eine Variable nicht als 'volatile' gekennzeichnet, geht der Compiler davon aus, dass sie sich nicht zwischendurch ändert und optimiert entsprechend. Wenn sie also einmal in einem Register ist, wird stets das Register genommen und nicht mehr nachgeladen. Wegen dieser Optimierung ist es auch sehr schwierig, die Ursache eines Problems zu erkennen, wenn die Codeschnipsel zu klein sind. Man kann dann nur raten.

    Wenn du also in deinem Programm Variablen hast, die sowohl im Hauptprogramm als auch in einer Interrupt-Routine oder aber in mehreren Interruptroutinen angesprochen werden, egal ob lesend oder schreibend, must du sie als volatile deklarieren, damit es einwandfrei klappt.

    Gruß Red Baron

  3. #13
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    08.08.2004
    Ort
    Zwolle
    Alter
    68
    Beiträge
    531
    Hallo RedBaron,

    Danke fur das Antwort,.
    Das mit die 'volatile' ist mir jetzt klar.

    Uber dass dividieren mochte ich noch folgendes bemerken.
    Vom (SIGNAL) interrupt heraus lasst sich keine function anrufen denn dann functioniert die interrupt function nicht richtig mehr.
    Wenn innerhalb die interrupt function eine complexere dividierung statt finded dann wird die complexere dividierung durch die compiler compiliert nach einen anruf von eine 'divmod' function. Weil es hier um ein anruf eines function auserhalb die interrupt function handelt wird auch hier die interrupt function nicht mehr richtig ausgefuhrt.

    Warum eine function anruf vom interrupt hinaus nicht functioniert das werde ich heute oder morgen schon ausfinden.

    gruss,

    Henk

  4. #14
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    08.08.2004
    Ort
    Zwolle
    Alter
    68
    Beiträge
    531
    Hallo RedBaron,

    Die Lösung zum Problem mit 'uiMeinZahler' liegt im Schlüsselwort 'volatile'. Wenn eine Variable als 'volatile' gekennzeichnet ist, geht der Compiler davon aus, dass sich der Wert asynchron zum eigentlichen Programmfaden (thread) ändert (also z.B. durch einen zwischendurch aufgetauchten Interrupt). Der Variablenwert wird deshalb bei jedem Zugriff erneut aus dem Speicher geladen.
    Wie erklarst du denn dass ein volatile variabele benutzt werden soll in main() wenn mann die variabele standig in main() abfragen will und wenn mann dieselben variabele in einen Interrupt function andert?

    Was ist met der Wert gemeint? Die Wert vom C-variabele oder die Wert vom Register die fur die C-variabele vom Assembler dafur benutzt wird?

    Ich meine:

    Vorbild:
    unsigned char MeinVar;
    MeinVar=0x33;

    Da wird vom Assembler irgend ein Register (z.B. R16) benutzt um die 0x33 darin zu speichern.

    Ich denke, wenn nicht als 'volatile' deklariert, dann wird in main() Register R16 abgefragt und nicht die MeinVar variabele.

    Was meinst du davon?

    gruss

    Henk

  5. #15
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    25.10.2005
    Alter
    71
    Beiträge
    157
    Hallo Henk,

    Vom (SIGNAL) interrupt heraus lasst sich keine function anrufen denn dann functioniert die interrupt function nicht richtig mehr.
    Doch! Das ist ohne Probleme möglich!

    unsigned char MeinVar;
    MeinVar=0x33;
    Hier benutzt der Compiler ein Register. Das steht dann in der Interrupt-Routine nicht zur Verfügung.

    volatile unsigned char MeinVar;:
    hier wird ein Speicherplatz im Heap angelegt, wenn die Variable außerhalb einer Funktion (auch main()) deklariert wird. Auf den Heap kann man von jeder Stelle aus zugreifen.

    Beispiel (aus asuro.c):


    volatile unsigned char count72kHz;

    /* uses timer2 (36kHz for IR communication */
    /* counts falling and rising edge => 36kHz*2 = 72kHz */
    SIGNAL (SIG_OUTPUT_COMPARE2)
    { count72kHz ++;
    }

    void dummy(int p){} // Damit der Compiler nicht optimieren kann.

    int main(void)
    { while (count72kHz < 100)
    dummy(count72kHz);
    return 0;
    }

    Sowohl die Interrupt-Routine als auch 'main()' greifen korrekt auf 'count72kHz' zu.

    ------------------------------------

    Interrupts erfolgen immer(!) asynchron zum Hauptprogramm, d.h. zu unvorhersehbaren Zeitpunkten. In der Interruptroutine weiß der Compiler deshalb nicht, welche Belegung die Register gerade haben.
    Zum Beginn einer Interruptroutine werden deshalb zuerst alle Register, die in der Routine benutzt werden, gesichert (auf dem Stack) und am Ende wieder zurückgespeichert. Dies betrifft z.B. r24 im Beispiel:

    **** SIGNAL (SIG_OUTPUT_COMPARE2)
    push __zero_reg__
    push __tmp_reg__
    in __tmp_reg__, __SREG__
    push __tmp_reg__
    clr __zero_reg__
    push r24
    **** count72kHz ++;
    lds r24, count72kHz
    subi r24, lo8(-(1))
    sts count72kHz, r24
    pop r24
    pop __tmp_reg__
    out __SREG__, __tmp_reg__
    pop __tmp_reg__
    pop __zero_reg__
    reti

    **** void dummy(int p){}
    ret

    **** int main(void)
    **** { while (count72kHz < 100)
    .....

    lds r24,count72kHz
    cpi r24,lo8(100)
    brsh .L26
    .L24:
    **** dummy(count72kHz);
    lds r24,count72kHz
    clr r25
    rcall dummy
    lds r24,count72kHz
    cpi r24,lo8(100)
    brlo .L24



    Hier wird r24 mit dem Inhalt (Wert) von 'count72kHz' geladen. Das passiert auch, obwohl in 'main()' ebenfalls 'count72kHz' ins r24 geladen wird. r24 kann an anderer Stelle anderweitig benutzt worden sein. Der Compiler weiß eben nicht, ob der Interrupt nicht an dieser Stelle eintritt.

    In 'main()' wird r24 zunächst für den Vergleich mit 'count72kHz' geladen. Kurz darauf für die Rarameterübergabe an 'dummy()' noch einmal, obwohl der Wert doch eigentlich schon in r24 steht. Da neue Laden ist aber notwendig, da eventuell zwischendurch der Interrupt eingetroffen sein könnte. Dieser würde den Inhalt von 'count72kHz' verändern. Theoretisch könnte es sein, dass der Vergleich (count72kHz < 100) und der Aufruf von Dummy mit unterschiedlichen Werten von 'count72kHz' erfolgen kann. Wenn man dies verhindern will, muss man 'count72kHz' in eine nicht als volatile deklarierte Variable zwischenspeichern:

    unsigned char x;

    x = count72kHz;
    while ( x < 100)
    { dummy(x);
    x = count72kHz;
    }

    ----------------------------------------
    Was ist met der Wert gemeint? Die Wert vom C-variabele oder die Wert vom Register die fur die C-variabele vom Assembler dafur benutzt wird?
    Wenn eine Variable als volatile gekennzeichnet ist, benutzt der Compilier kein Register!


    Gruß Red Baron

  6. #16
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    08.08.2004
    Ort
    Zwolle
    Alter
    68
    Beiträge
    531
    Hallo RedBaron,

    Verzeihung um die spate antwort aber ich hatte noch viele andere Sachen zu klaren.

    Danke fur die Erklarung, die wird ich mich nochmal richtig ansehen.

    Ich sehe in meine Interuptfunction bei einem Teilung z.B. die anruf von
    'rcall divmodh14'

    Meine Frage ist: soll Ich selber die benutzte register auf/vom Stack pushen und poppen oder macht dass die ' divmodh14' function selber?

    Wenn ich vom innerhalb meine interrupt function eine eigene test Function anrufe (die viele variabelen benutzt) dan gibts nirgendwo ein push oder pop in die listfile zu sehen! Nicht bei die Anruf und nicht in die angerufene test Function. Wie ist dass den moglich? Vermutlich ist dies die Ursache von meinem Problem.

    Auch sind keine push/pos zu sehen wenn ich meine test Function sich selber (rekursief) anrufen lass.

    (Beim anfang und ende vom interrupt function sehe ich viele 'push' und 'pops'.)

    Vielleicht soll ich mich die 'makefile' ansehen ob da irgendeine Compiler flage nicht anwesend ist?

    Gruss

    Henk

  7. #17
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.802
    Der Compiler fügt nur dort push und pop-Anweisungen in den Code ein, wo sie auch gebraucht werden.

    Die Übergabe von Argumenten wird in der Regel ohne push und pop erledigt, weil die Argument in Registern übergeben werden.

    In den Funktionen ist auch nicht unbedingt push/pop notwendig, sondern nur denn, wenn Register verwendet werden, die durch einen Funktionsaufruf nicht verändert werden bzw nach einem Funktionsaufruf unverändert vorliegen ("call saved regs"). Für die Register, die eine Funktion verwenden kann ohne sie vorher zu sichern ("call clobbered regs") ist natürlich kein push/pop notwendig.

    Auf keinen Fall darfst du irgendwo in den Code ein "push" einfügen oder so, das führt zum Absturz -- Ausnahme ist, wenn du selber Inline Assembler einfügst und du genau weisst was du tust und genau weisst, welchen Code der Compiler sonst generiert.

    Wenn du "reinen" C-Code schreibst, brauchst du dich darum nicht zu kümmern.

    Das gilt auch für die (implizit aufgerufene) divmodhi4-Funktion, das erledigt alles der Compiler.
    Disclaimer: none. Sue me.

Seite 2 von 2 ErsteErste 12

Berechtigungen

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

12V Akku bauen