-
        

Seite 1 von 3 123 LetzteLetzte
Ergebnis 1 bis 10 von 30

Thema: Zeitschleife Mikrocontroller

  1. #1
    Neuer Benutzer Öfters hier
    Registriert seit
    14.08.2015
    Beiträge
    16

    Zeitschleife Mikrocontroller

    Anzeige

    eitschleife Mikrocontroller
    Hallo Forumnutzer,

    ich habe folgende Code für eine Zeitschleife aus AVR: http://www.mikrocontroller.net/artic...-Tutorial:_LCD

    Längere Pause für manche Befehle
    delay5ms: ; 5ms Pause
    ldi temp1, $21
    WGLOOP0: ldi temp2, $C9
    WGLOOP1: dec temp2
    brne WGLOOP1
    dec temp1
    brne WGLOOP0
    ret ; wieder zurück


    Was hier vorgeht, habe ich soweit verstanden. Jetzt möchte ich auch eine Zeitschleife für 5ms Pause von 16 Mhz (Attiny 26). Das Problem liegt bei der Bestimmung der Durchläufe. Kann mir jemand erklären, wie ich diese bestimmen kann? T=((1)/!6Mhz)= 65,2 ns-->(5ms)/(65,2ns)= 80000 Taktzyklen notwendig...weiter weiß ich nicht


    Mfg

  2. #2
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    07.04.2015
    Beiträge
    196
    Im Datenblatt des Controllers (PDF) findest Du in der Tabelle "Instruction Set Summary" in der letzten Spalte die Angabe der "Clocks". Das sind die Prozessorzyklen, die jeder Assemblerbefehl für seine Ausführung braucht. Für "ldi" z.B. 1 Zyklus, für "ret" 4 Zyklen.

    Wo mehrere Werte angegeben sind (z.B. "brne") befragst Du die Assemblerhilfe für den jeweiligen Befehl.
    Der Rest ist "aufaddieren" und ggf. in den Loops multiplizieren.

    Der schnellere Weg: Wenn Du die Frequenz weißt, die die Routine vor der Anpassung verwendete, rechnest Du einfach ( so Pi mal Daumen) $C9 * alte Frequenz / 16MHz. Das passt dann nicht auf die Nanosekunde, lässt sich aber z.B. im Simulator später durch Variieren der beiden Loop-Werte noch verbessern.

  3. #3
    Neuer Benutzer Öfters hier
    Registriert seit
    14.08.2015
    Beiträge
    16
    danke für die schnelle Antwort..Ich muss dazu sagen, dass ich erst seit einer Woche mich mit Mikrocontroller und assembler befasse.

    Also die Tabelle habe ich bereits angeschaut..
    delay5ms: ; 5ms Pause
    ldi temp1, $21--------------------------------------------------> 1 Takt
    WGLOOP0: ldi temp2, $C9-------------------------------------> 1 Takt
    WGLOOP1: dec temp2------------------------------------------> 1 Takt
    brne WGLOOP1--------------------------------------------------> Sprung 2 Takte, sonst 1 Takt
    dec temp1-------------------------------------------------------> 1 Takt
    brne WGLOOP0--------------------------------------------------> Sprung 2 Takte , sonst 1 Takt
    ret----------------------------------------------------------------> 4 Takte
    Innere Schleife ( dec + brne = 3 Takte) ..... Jedoch weiß ich nicht wie ich nicht wie ich die 80000 Takte auf die drei schleifen verteilen soll. Also ich weiß nicht wie ich die einzelnen Durchläufe nun berechnen soll.....

    MFG

  4. #4
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    07.04.2015
    Beiträge
    196
    Jo, eine Woche ist vielleicht etwas knapp.
    Du weißt aber schon etwas über Hexadezimalcodes (z.B. dieses magische $C9 ist eine 201)?

    Es sind zwei Schleifen. Die innere
    WGLOOP1: dec temp2------------------------------------------> 1 Takt
    brne WGLOOP1--------------------------------------------------> Sprung 2
    wird $C9, also 201 mal ausgeführt

    201* 3 Takte = 603 Takte


    Die äußere Schleife
    WGLOOP0: ldi temp2, $C9-------------------------------------> 1 Takt
    .//Innere Loop mit 603 Takten
    .
    dec temp1-------------------------------------------------------> 1 Takt
    brne WGLOOP0--------------------------------------------------> Sprung 2

    wird durch das vorladen von $21 in temp1 33 mal ausgeführt.
    Du kannst also rechnen 33 * (4 + 603) = 20031 Takte

    Wenn wir es ganz genau nehmen, musst Du jetzt noch Einsprung (z.B. jmp) und Rücksprung (ret) und den Takt für das Vorinitialisieren des temp1-Registers dazuzählen, das sind aber nur Peanuts.

    Ich sage Dir also auf den Kopf zu: Das sind etwa 20000 Takte, die Routine war ursprünglich für 4MHz gebaut. Der Autor war ein Elektrotechnikingenieur der alten Schule ("ohne besondere Anforderungen reichen zwei Stellen nach dem Komma").

    In der Praxis setz einfach ein $32 anstatt der $C9, dann klappst auch mit den 16MHz.

    - - - Aktualisiert - - -

    FALSCH FALSCH FALSCH: In der Praxis setze für die $21 eine $84 ein.
    (ich hab's noch gemerkt)

  5. #5
    Neuer Benutzer Öfters hier
    Registriert seit
    14.08.2015
    Beiträge
    16
    Brauche ich da eigentlich nicht eine dritte schleife? Wie kommst du aus ($21= 33, $84=132 bzw $32=50)??

  6. #6
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    07.04.2015
    Beiträge
    196
    Hatte ich ja fast geahnt, dass Du die Hexadezimalschreibweise nicht kennst.

    Führende "$" oder "0x" vor Zahlen kennzeichnen im AVR Assembler die Hexadezimaldarstellung einer Zahl.

    Statt der Zehnerbasis unseres herkömmlichen Zahlensystems verwendet diese die 16er-Basis. Mit der 16er-Basis stellst Du einen Bytewert mit 2 Stellen dar.
    Die Praxis. Du zählst: 0,1,2,3,4,5,6,7,8,9, STOPP, jetzt kommt nicht 10, es geht weiter mit A,B,C,D,E,F, STOPP, jetzt kommt nicht G, weil mit "F" hast du eigentlich "15" gemeint, jetzt geht es weiter mit der nächsten Stelle, also 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 1A, 1B, 1C, 1D, 1E, 1F, 20,...
    bei FF hast Du damit den höchstmöglichen Wert 255 für ein Byte erreicht.

    Sinn dieses durchaus für Außenstehende völlig unverständlichen Machwerkes der Hexadezimalcodierung ist die Zusammenfassung eines Bytes (8 Bits) in zwei Zeichen. Du fasst dabei jeweils die unteren 4 und die oberen vier Bits zu einem Zeichen 0..F zusammen.

    Witz des ganzen: Geübte rechnen Dir in Windeseile diese Hexadezimalzahlen in reale Zahlen um und auch wieder zurück, aber nicht nur dass: Am Zahlenwert 201 musst Du erst rechnen, ob das vierte Bit von unten gesetzt ist oder nicht. In der Hexadezimalschreibweise ist das ein Hingucken: 4tes Bit ist in der unteren Gruppe, also in der 9. 9 ist größer als 8, also ist die 8 gesetzt, also ist das vierte Bit von unten gesetzt.

    Die Hexadezimalschreibweise ist also ein guter Kompromiss zwischen der normalen Ganzzahldarstellung (einzelne Bitwerte lassen sich nicht ablesen) und der Binärschreibweise (8 Stellen sind zu lang zum Schreiben)

    Kleine Übung: Wenn Du's nicht verstanden hast (ich bin kein Lehrer), Google es woanders nach, aber spätestens dann müsstest Du mir sagen können, was die Zahl $AA in unserem Zahlensystem ist. Wenn Du das nicht drauf hast, brauchst Du mit Assembler nicht weiter zu machen. Das begegnet Dir so oft, da kann man sich kaum verweigern.

    Die dritte Schleife brauchst Du nicht, weil du mit dem Zahlenbereich der äußeren Schleife hinkommst. Statt 20000 Takten willst Du 80000 Takte warten, daher kannst Du den Schleifenzähler $21 mit 4 multiplizieren, das macht dann $84.
    Geändert von Holomino (14.08.2015 um 22:15 Uhr)

  7. #7
    Neuer Benutzer Öfters hier
    Registriert seit
    14.08.2015
    Beiträge
    16
    oh, eigentlich weiß ich was die hexadezimaldarstellung ist und wie diese berechnet wird. $AA entspricht doch 170 (Dezimalzahl). Ich weiß dass bei 16 MHz und 5 ms 80000 Takte notwendig sind, dass was ich nicht weiß wie ich quasi die Durchläufe ( Hexazahlen) bestimmen soll....
    Zum Beispiel wenn ich eine dritte Schleife dazufüge..

    ldi R17, ?????
    WGLOOP0: ldi R18, ?????
    WGLOOP1: ldi R19, ?????
    WGLOOP2: dec R19
    brne WGLOOP2
    dec R18
    brne WGLOOP1
    dec R17
    brne WGLOOP0

    Danke

  8. #8
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    07.04.2015
    Beiträge
    196
    Die beiden inneren Loops durchlaufenen 20000 Takte. Du willst 80000 Takte haben? Dann musst Du wohl die inneren Loops vier mal durchlaufen. Dann nimm doch 4 als Startwert für die äußere Loop. Wo ist das Problem? Ob Du den Prozessor 100 mal bis zehn oder zehn mal bis hundert zählen lässt, ist dem ziemlich egal. Der merkt nicht, wenn er sich in der Nase bohrt.

    Warum Du allerdings darauf bestehst, eine dritte Loop außen rum zu bauen, verstehe ich noch nicht. Das kostet Dich ein Register für den dritten Schleifenzähler. Assembler ist keine Hochsprache, Register werden nicht wie Variablen gescoped. Wenn Du also dieses dritte Register zufällig oder beabsichtigt vor dem Aufruf Deiner Wartefunktion verwendest, ist der Inhalt nach dem Durchlauf der Wartefunktion wech.
    Allgemeine Maßnahmen dagegen sind:
    - Verwende Register pragmatisch in einer Routine (so wenige wie möglich. So viele, wie nötig)
    - verwende Push und Pop, damit Du im aufrufenden Programmteil nicht unbeabsichtigt etwas überschreibst. Erst wenn Du in Deinen Routinen zu Anfang die Inhalte aller verwendeten Register (die NICHT als Eingabeparameter oder Rückgabewerte verwendet werden) auf den Stack pushst, dann veränderst und am Ende in umgekehrter Reihenfolge wieder die Inhalte zurückpoppst, bist Du auf der sicheren Seite.

  9. #9
    Neuer Benutzer Öfters hier
    Registriert seit
    14.08.2015
    Beiträge
    16
    Es tut mir leid für die nervige Fragen.. also ein letztes mal . Ja ich will 80000 Takte. Wie meinst du mit ich muss die inneren loops vier mal durchlaufen bzw 4 als Startwert nehmen?



    vielen vielen Dank

    - - - Aktualisiert - - -

    also warum ich eine dritte schleife noch mit einfügen möchte, weil die mir empfohlen wurde. Ich habe zusätzlich diesen Beitrag aus einem Forum gelesen und dachte es wäre notwendig.

    Beitag aus Forum:

    Also, gesetzt den Fall, ein djnz-Befehl bräuchte nur 1 Taktzyklus. Nehmen wir mal an, die CPU würde mit 4,772727 MHz betrieben (ich weiß gar nicht, wie ich jetzt auf so'n komischen Wert komme...) Dann bedeutet das, sie hat 4772727 Takte pro Sekunde und um 2 Sekunden zu überbrücken, muß man 2 x 4772727 = 9545454 Takte durchlaufen lassen - oder anders ausgedrückt: So oft muß die innere Schleife durchlaufen werden, wenn der Befehl nur 1 Takt verbraucht. Verbraucht er mehr Takte, muß man den Wert durch die Anzahl Takte teilen, wenn er z.B. 3 Takte verbraucht, wäre der "Ticker-Wert" = 3191919 (eben 9545454 / 3).

    Von diesem Wert wird ja rückwärts nach 0 gezählt. Register sind ja immer binär, daher also z.B. 8 oder 16 oder 32 bit breit (ja, es gibt auch 4- oder 12-bit Register...), das heißt, der Wert ist im Falle von 8-Bit-Registern immer nach genau 8 bit zu teilen.
    Wäre er also 9545454, wäre das binär (als 24-bit-Wert) :
    100100011010011011101110, der ist also immer nach 8bit zu teilen:

    10010001 10100110 11101110, oder 145, 166 und 238 - und genau das sind die Werte, die nach R2, R1 und R0 müssen (nach R0, weil das die innerste Schleife ist, muß der unterste Wert, also hier 238, nach R1 müßte 166 und nach R2 dann 145).

    Einfachere Möglichkeit ist, einfach immer durch 256 zu teilen:
    9545454 / 256 = 37286, Rest 238
    32786 / 256 = 145, Rest 166
    (145 / 256 = 0, Rest 145 - aber das braucht man ja nicht mehr zu "berechnen"...)
    Diese Teilungsreste sind dann (sozusagen im Zahlensystem der 256) die einzutragenden Werte.
    (Ja, oder man wandelt die Zahl einfach ins Hexadezimalsystem und nimmt immer 2 Ziffern... Leider gibts heutzutage Assembler-Programmierer, die noch nie was vom Hexadezimalsystem gehört haben, deswegen weiß ich da manchmal nicht, ob ich das wie früher einfach voraussetzen kann...)

    .............

  10. #10
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    07.04.2015
    Beiträge
    196
    Die Verwendung des dritten Registers ist eine Ressourcenverschwendung. Zu Anfang denkt man sich: "Ich hab doch 32 davon (R0..31)". Dann stellt man fest, man kann nur mit den oberen 16 alle Assemblerbefehle nutzen und eigentlich gehen davon auch noch die obersten 6 Register noch einmal ab, weil nur damit die 16-Bit-Adressierungen über X, Y und Z möglich sind.
    Was bleibt, sind magere 10 Registerchen zur vollen Verwendung.

    Zum Abschluss und zum Gedanken anregen:
    Wenn es Dir gelingt, eine 1Mikrosekunde-Warteschleife zu verfassen
    Wait1u:
    //Einsprung 3 Takte über rcall
    nop //10*1
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    nop
    ret //Rücksprung 3 Takte
    //16 Takte


    Dann kannst Du doch auch eine Routine über 100 Mikrosekunden verfassen, in der Du die Wait1u-Routine wiederverwendest:
    Wait100u:
    //3 Takte Einsprung über rcall
    push r16 //1
    ldi r16, 84 //1
    Wait100u_Loop:
    rcall Wait1u //16 Takte
    dec r16 //1
    brne Wait100u_Loop //2
    Wait100u_End:
    pop r16 //1
    ret //3
    //19*84 + 9 = 1605


    Dann kannst Du auch nach der gleichen Form eine Wait1m schreiben
    Wait1m:
    //3 Takte Einsprung über rcall
    push r16 //1
    ldi r16, 10 //1
    Wait1m_Loop:
    rcall Wait100u //1605 Takte
    dec r16 //1
    brne Wait1m_Loop //2
    Wait1m_End:
    pop r16 //1
    ret //3
    //1608*10 + 9 = 16089 Takte


    Und ganz zum Schluss
    Wait5m:
    //3 Takte Einsprung über rcall
    push r16 //1
    ldi r16, 5 //1
    Wait5m_Loop:
    rcall Wait1m //16089 Takte
    dec r16 //1
    brne Wait5m_Loop //2
    Wait5m_End:
    pop r16 //1
    ret //3
    //16089*5 + 9 = 80454 Takte

    Diese Routinen (ich hab's jetzt hier im Editor geschrieben, mag noch irgendwo ein Fehlerchen drin sein) sind erweiterbar (Du kannst Dich damit bis in den Stundenbereich hochkaskadieren), anpassbar (Du musst nur die unterste Funktion an die Frequenz anpassen) und einfach wartbar (die Wartefunktionen haben immer die gleiche Form).
    Aber das Wichtigste: das einzige verwendete Register r16 ist in jedem Fall save, weil es in jeder Aufrufebene gepusht und gepoppt wird. Du kannst es also vor dem Aufruf einer der o.g. Wartefunktionen mit einem Wert beschreiben und nach dem Aufruf immer noch sicher sein, dass in r16 noch das steht, was Du dort hineingeschrieben hast.
    Geändert von Holomino (15.08.2015 um 01:08 Uhr)

Seite 1 von 3 123 LetzteLetzte

Ähnliche Themen

  1. Zeitschleife Mikrocontroller
    Von sisi im Forum Bauanleitungen, Schaltungen & Software nach RoboterNetz-Standard
    Antworten: 4
    Letzter Beitrag: 08.10.2015, 21:44
  2. [ERLEDIGT] Zeitschleife zu kurz....ATTiny2313
    Von oderlachs im Forum C - Programmierung (GCC u.a.)
    Antworten: 2
    Letzter Beitrag: 10.03.2013, 16:10
  3. Taster mit Zeitschleife
    Von bnitram im Forum Basic-Programmierung (Bascom-Compiler)
    Antworten: 15
    Letzter Beitrag: 28.05.2010, 19:01
  4. Zeitschleife
    Von Exodus im Forum AVR Hardwarethemen
    Antworten: 4
    Letzter Beitrag: 07.06.2006, 18:32
  5. Zeitschleife
    Von Exodus im Forum AVR Hardwarethemen
    Antworten: 1
    Letzter Beitrag: 01.06.2006, 15:34

Berechtigungen

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