-         

Seite 1 von 2 12 LetzteLetzte
Ergebnis 1 bis 10 von 15

Thema: einfache Division mit Atmega AVR?

  1. #1
    Neuer Benutzer Öfters hier
    Registriert seit
    19.07.2007
    Beiträge
    26

    einfache Division mit Atmega AVR?

    Anzeige

    Hallo,
    //alles Folgende bezieht sich auf einen assemblerprogrammierten
    //Atmega 324P
    Ich möchte meinen Roboter mit einer Art Tacho ausstatten, der die Geschwindigkeit ermittelt:

    Dazu sind an den Rädern Impulssensoren angebracht (3 Impulse/Umdrehung). Die Zeitdauer zwischen zwei Impulsen wird mit einem Hardwaretimer exakt gemessen. Um nun die Geschwindigkeit zu erhalten muss man bekanntermaßen folgende Formel anwenden:


    Geschwindigkeit = zurückgelegter Weg / dafür benötigte Zeit


    Der Weg ist in meinem Fall kostant, die Zeit ändert sich. Um die Aufgabe mit Mikrocontroller (in meinem Fall: Atmega324P) zu lösen, verwendet man in der Regel Routinen, die prinzipiell das schriftliche, dezimale Dividieren nachbilden und relativ viel Zeit (einige 50 Taktzyklen) benötigen.
    Ich habe mir gedacht, dass man solche Aufgaben eigentlich schneller lösen können müsste, wenn man die Division in eine Multiplikation umwandelt und die mit dem Hardwaremultiplizierer des Controllers durchführt:


    Ergebnis = Divident * (1/Divisor)


    Allerdings hat man das Problem nur verlagert, da man vorher den Reziprokwert des Divisors bilden muss (1/Divisor).
    Ich könnte mir aber vorstellen, das dies auf binärer Ebene durch einfache Bitmanipulationen machen kann (analog funktioniert es ja schließlich auch bei Addition/Subtraktion).

    Meine Frage an euch:
    Funkioniert das so? Oder kann man auf anderem Wege die Division beschleunigen?
    Ich hab auch schon eine ganze Weile mit Papier und Bleistift überlegt und auch im Internet nachgesehen habe aber nichts passendes gefunden. (vielleicht steh ich aber einfach nur auf dem Schlauch)

    Vielen Dank für sämtliche Bemühungen
    Gruß,
    wolli_bolli

    PS.: Ich möchte das ganze in Assembler programmieren.

  2. #2
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    15.03.2005
    Ort
    gerne in den Bergen
    Alter
    33
    Beiträge
    429
    Rechnen und Assembler ist eine "gute" sache

    Der Denkanstoss in Richtung Multiplikation ist gut. Hast du einmal daran gedacht, dass du die Konstante Weg hoch minus 1 machen würdest! Dieser Wert ändert sich nicht. Dafür hast du dann eine Kommazahl. Also müsstest du je nach gewünschter Genauigkeit beide Werte mit einem bestimmten Wert multiplizieren (einfachhalber ein Vielfaches von 2 -> rol, ror)
    Oder so ähnlich...
    ...wer nicht findet hat nicht gesucht...

  3. #3
    Neuer Benutzer Öfters hier
    Registriert seit
    19.07.2007
    Beiträge
    26
    Ich habe auch schon daran gedacht, einfach den Reziprokwert des Weges zu bilden. Wenn ich den dann aber mit der Zeit multipliziere kommt als Ergebnis der Reziprokwert der Geschwindigkeit heraus, da ich dann letztendlich Zeit durch Weg teile. Ich brauche aber den "echten" Wert der Geschwindigkeit (und nicht den reziproken). Insofern komme ich um eine Division durch die sich ändernde Zeit nicht herum.

    Gruß wolli_bolli

  4. #4
    Erfahrener Benutzer Roboter-Spezialist
    Registriert seit
    15.03.2005
    Ort
    gerne in den Bergen
    Alter
    33
    Beiträge
    429
    Ach ja stimmt. Irgendwie war mir klar, aber während dem schreiben sind mit Zweifel gkommen. Darum schrieb ich auch: Oder so ähnlich...
    Leider habe ich mit Assembler nur die Addtion und Subratkion gebraucht. Ich wollte mir einmal eine Sammlung von Rechenmakros schreiben, die dann je nach Anwedung direkt includiert werden können!
    ...wer nicht findet hat nicht gesucht...

  5. #5
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    25.11.2003
    Beiträge
    1.111
    Durch geschickte Wahl der Konstanten, des TimerPrescalers, des µCTaktes SOWIE der möglich messbaren Zeitspanne ist es möglich, die Division in eine Subtraktion zu überführen.
    Geschickt heißt, alle benutzten Werte müssen 8Bit breit sein und der gesamten GeschwBereich abdecken und dabei die Geschw in einer geeigneten Einheit darstellen.
    Beispiel:
    v_min = 255 TimerWerte entsprechen 1cm/s
    v_max = 1 TimerWert entspricht 255cm/s
    255 und 1 sind die 8Bit TimerWerte der Messung.
    Dann entspricht:
    v = 255-TimerWert der aktuellen Geschwindigkeit in cm/s.
    Bei zB TimerWert = 64 --> 255-63 = 192cm/s
    oder TimerWert = 196 --> 255-196 = 59 cm/s
    Letztendlich müsstest Du in diesem Beispiel dafür sorgen, dass 255 Timerzählung der min Geschw entsprechen und das kann recht viel sein. Eventuell wird ein Softwareteiler notwendig, der den TimerPrescaler zusätzlich teilt. Aber das alles hängt von den genauen Bedingungen ab.

    Wenn Du keinen Softwareteiler benutzen willst, kannst Du einen anderen Timer dazu verwenden, die minimale Auflösung darzustellen, in dem Du dessen CompareMatches während der Zeitmessung zählst und anschließend umrechnest. Damit ist es möglich genauer zu messen, weil Du am Ende Anzahl der CompMatches hast UND den letzten TimerWert des 2. Zählers. Aber das bringt Dir nichts hinsichtlich Rechenzeit.
    Gruß

  6. #6
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.801
    50 Takte ist ja nicht die Welt...

    Du hast ja nichma geschrieben, um welche Division es geht. 32/32 oder 8/8 Bits???

    Bei 8/8 und konstantem Dividend ging ne Tabelle wenns schnell gehen muss, braucht aber natürlich Platz.

    Als Referenz für ne DIV/MODULO-Implementierung ist avr-gcc ganz gut, da kann man nachschauen wie es dort gemacht ist, ist vielleicht schneller?

    Hier mal ein Link an die Quelle der libgcc.S, hoffe mal der Link geht. Ist kommentierter GNU avr-asm:

    http://gcc.gnu.org/viewcvs/trunk/gcc...66&view=markup

    Da gibts Division+Modulo for 32 bit (si), 16 Bit (hi) und 8 Bit (qi), signed und unsigned. Die 8-Bit unsigned Version heisst zB udivmodqi4, die signed 16-Bit Version divmodhi4 etc.
    Disclaimer: none. Sue me.

  7. #7
    Neuer Benutzer Öfters hier
    Registriert seit
    19.07.2007
    Beiträge
    26
    @SprinterSB: es geht um eine 16bit/16bit Division (Wegkonstante ~ 5200, Zeit 1...2048 ergibt Weg in cm/s), meine bisherige Divisionsroutine ähnelt dem avr-gcc Code.

    @Gock: deine Möglichkeit scheint genial, ist aber ungenau, da sie die Geschwindigkeit als lineare Funktion der Zeit annimmt, in Wirklichkeit ist der Graph der Zeit - Geschwindigkeitsfunktion aber keine Gerade sondern eine Hyperbel. Durch geschickte Bereichswahl und eventuelle Vorfaktoren (Multiplizieren geht ja sehr einfach und schnell) kann man die Abweichung aber gering halten. Werde mal morgen früh durchrechnen ob das für mein Problem genau genug ist.

    Außerdem könnte es sein, dass man, wenn man für die Zeitmessung ein Compare Match Interrupt im CTC-Modus verwendet durch kontinuierliches Senken des Vergleichswertes die Hyperbel der Funktion quasi zu einer Gerade "strecken" kann. Dann könnte man mit höherer Genauigkeit Gocks Formel anwenden. Auch dazu werd ich mir mal Gedanken machen.

    Gruß wolli_bolli

  8. #8
    Erfahrener Benutzer Robotik Einstein Avatar von wkrug
    Registriert seit
    17.08.2006
    Ort
    Dietfurt
    Beiträge
    1.892
    Guck mal http://www.avr-asm-tutorial.net/avr_...n.html#div8bin
    die Routine kannst Du für deine 16 Bit einfach erweitern.

  9. #9
    Erfahrener Benutzer Roboter Genie
    Registriert seit
    25.11.2003
    Beiträge
    1.111
    Hyperbel???
    Du meinst, Deine Geschwindigkeit ändert sich hyperbolisch??? Das ist aber eine merkwürdige Geschwindigkeit! Vielleicht meinst Du "nichtlinear".
    Das macht aber dann keinen Unterschied zu Deiner Variante mit der Division, denn da nimmst Du sie auch linear an und bildest den Mittelwert über dieselbe Periode wie ich.
    Sollte sich die Änderung der Geschwindigkeit (also die Beschleunigung) innerhalb des Messintervalls so stark ändern, dann ist das bereits ein Problem der Hardware -> zu geringe Auflösung der Encoder.
    Solche Probleme sollte man nicht unbedingt versuchen zu korrigieren, wenn man nur 50 Takte zur Verfügung hat.
    Allerdings habe ich im Nachhinein festgestellt, dass Du mehrere 50 Takte meintest. Bei 16Bit Operationen sind die dann natürlich auch notwendig.
    Der GCC Link von Sprinter ist echt gut, wenn auch etwas unübersichtlich auf den ersten Blick.
    Mit dem Link von wkrug kann ich nicht so viel anfangen, weil da kein Code zu finden ist.
    Wenn es nicht 32Bit sein müssen kann ich nur die optimierten Routinen von Atmel selbst empfehlen. Es gibt sie Code- und Speed-Optimized, sie funktionieren sicher und es sind jeweils Code und Taktverbrauch angegeben.
    Gruß

    PS: Danke, ich finde meine Methode auch genial...

  10. #10
    Neuer Benutzer Öfters hier
    Registriert seit
    19.07.2007
    Beiträge
    26
    Ich würde schon sagen, dass sich die Geschwindigkeit hyperbolisch ändert, schließlich geht die Geschwindigkeit gegen unendlich, wenn die Zeit gegen null geht. Um die Geschwindigkeit gegen Null gehen zu lassen, muss prinzipiell eine unendliche Zeit vergehen. Das sind genau die Eigenschaften einer Hyperbel und nicht die einer Gerade, wenn ich mich nicht irre, was aber durchaus sein kann.
    Wie dem auch sei, ich habe jetzt ersteinmal die mit dem Kopf durch die Wand Methode angewandt und mir von Excel eine Tabelle mit 2000 16-bit Werten berechnen lassen und das ganze im Flash des Controllers abgespeichert. Somit wird nicht mehr dividiert sondern einfach nachgeschaut. Da ich sowieso erst ca. 2,5 KByte von meinen 32 KByte Speicher mit Programm gefüllt hab, stört der relativ große Speicherhunger der Tabelle vorerst nicht.
    Dennoch nochmal danke für eure Hilfe
    Gruß
    wolli_bolli

Seite 1 von 2 12 LetzteLetzte

Berechtigungen

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