Forum: Mikrocontroller und Digitale Elektronik Zeitkritisch ?


von FrankH (Gast)


Lesenswert?

Hallo,
ich würde gerne mal wissen wieviele Takte meine Routine benötigt. Ich 
takte einen Schrittmotor und berechne zu jedem Schritt den neuen 
Matchwert des Timer1 16 Bit im fast PWM-Modus. Bei größter 
Winkelgeschwindigkeit hätte ich zwischen jeden Interrupt ca. 800 Takte 
in denen er alles neu berechnet und noch einige andere Sachen macht.

Atmega8 16MHz

Inhalt der Routine:
{
   schrittWeite++;
   if (schrittWeite < endeRampe)
   {
      Cn=Cn-1 - ((2 * Cn-1)/( 4 * (n - m) + 1));
      ICR1 = Cn;
   }
   else //Endesequenz einleiten
}

Ich hoffe ihr könnt mir da helfen. Mich würde auch echt mal 
interessieren wie sowas berechnet wird.
Gruss
Frank

von FrankH (Gast)


Lesenswert?

Achso, ich weiß nicht ob es von Bedeutung ist aber:

double schrittWeite;
double endeRampe;
double Cn;
double n;
double m;

Gruss
Frank

von Stefan Kunz (Gast)


Lesenswert?

Um die Zeit zu Messen einfach vor der zu messenden Routine PIN auf High 
legen und danach auf Low Oszi ran und dann hast du deine zeit mit 
eventuellen Jittern und anderem hässlichem Kram. Oder du guckst dir nach 
dem compilieren den Maschinencode an schlägst die Befehle nach wieviele 
Takte die brauchen und addierst die Anzahl der Takte.
Die Oszi-Variante geht schneller.

von Stefan Kunz (Gast)


Lesenswert?

Ja das hat eine Bedeutung denn floating point Operationen dauern immer 
länger als integer Operationen. Die Frage wäre auch noch was für einen 
Prozessortypen du verwendest und wie der getaktet ist.

von FrankH (Gast)


Lesenswert?

Hi, danke für die Antworten.
Also, ich habe einen myAVRUSB-Board mit einem Atmega8 16PU, statt der 
3,6864MHz habe ich einen 16 Mhz draufgelötet.
Habe gerade kein Oszi da. Maschinencode...oha   ;-)
Gruss
Frank

von FrankH (Gast)


Lesenswert?

Den Timer1 lasse ich mit 2MHz laufen.
Gruss
Frank

von Mark B. (markbrandis)


Lesenswert?

Stefan Kunz schrieb:
> Um die Zeit zu Messen einfach vor der zu messenden Routine PIN auf High
> legen und danach auf Low Oszi ran und dann hast du deine zeit mit
> eventuellen Jittern und anderem hässlichem Kram. Oder du guckst dir nach
> dem compilieren den Maschinencode an schlägst die Befehle nach wieviele
> Takte die brauchen und addierst die Anzahl der Takte.
> Die Oszi-Variante geht schneller.

Yep. Außerdem ist im Handbuch Assembler-Befehle nachschlagen nicht so 
schön wie im Labor mit dem Oszi zu werkeln :-)

von Stefan Kunz (Gast)


Lesenswert?

^^ Stimmt die Zeit benutzt man lieber für andere Sachen. Man könnte auch 
den Timer des AVR nehmen. Zwar dann ein wenig unhandlicher weil man mehr 
Quellcode schreiben muss und dadurch ein etwas ungenaueres Ergebnis 
bekommt abber möglich.
Wenn du mit den 800 Takten nicht zurecht kommst solltest du überlegen 
weg von den double-Werten zu gehen. Integer-Berechnungen sind um ein 
vielfaches schneller besonders wenn man im "nativen" Zahlenbereich des 
Prozessors bleibt. Außerdem ist ein Oszi eigentlich Pflicht wenn man was 
mit µC.

von Gast (Gast)


Lesenswert?

Oder man codet gleich mit Assembler und hat dieses Problem erst gar 
nicht. :)

von Karl H. (kbuchegg)


Lesenswert?

Man kann natürlich auch im AVR-Studio im Debugger einen Breakpoint an 
den Anfang der Routine setzen, sich den Counter merken, bis ans Ende der 
Routine durchsteppen (oder durchlaufen lassen) und mit dem Endstand 
vergleichen. AVR-Studio ist sogar so freundlich und rechnet das in eine 
Zeit um, wenn man ihm nur die Taktfrequenz des Prozessors richtig 
einstellt.

von FrankH (Gast)


Lesenswert?

-ich programmiere mit Xcode auf einem Macbook und kann AVR-Studio nicht 
laufen lassen.
-Assembler programmieren kann ich nicht.
-Ein Assembler Handbuch habe ich auch nicht.
Bleibt also nur die Oszi - Methode, dann werde ich das mal probieren.
Gruss
Frank

von FrankH (Gast)


Lesenswert?

Ok, eine Frage hätte ich da noch.
Wenn ich einen Pin toggle um die Zeit zu messen, wie viele Takte brauche 
ich für das Toggeln, damit ich das am Ende subtrahieren kann?

z.B:    PORTB = PINB^(1 << PB1);

Gruss
Frank

von holger (Gast)


Lesenswert?

>Wenn ich einen Pin toggle um die Zeit zu messen, wie viele Takte brauche
>ich für das Toggeln, damit ich das am Ende subtrahieren kann?

Ignoriere es einfach. Der Rest dauert wesentlich länger.
Macht also kaum was aus.

von Vlad T. (vlad_tepesch)


Lesenswert?

Mir ist nur überhaupt nicht klar, warum man das in floating point 
rechnen sollte.

Edit:
und mit emulierten floats brauchst du hier garantiert locker mehr als 
800 Tajkte, wenn du das in Inegern rechnen würdest, wärens vielleicht 
50.

>(2 * Cn-1)
das ist auch leicht irreführend, bist du sicher, dass das das macht, was 
du willst?

von (prx) A. K. (prx)


Lesenswert?

Da nichts in der Funktion von äusseren Ereignissen abhängt, kann man das 
auch ganz schlicht durch den Simulator vom Studio jagen. Der zeigt die 
Takte an.

von Vlad T. (vlad_tepesch)


Lesenswert?

bei so gestellten sachen muss man immer aufpassen, dass man sinnvoll 
volatile einsetzt, so das der compiler weder alles wegoptimiert, noch 
durch ein falsches volatile gar nicht optimiert.

Hat mich schon manchmal fast den Verstand gekostet, wenn ich irgend was 
messen wollte.

von FrankH (Gast)


Lesenswert?

Hi an Alle,
danke erstmal für die Antworten.
Vlad-> ich dachte mit den Float-Werten bin ich auf der richtigen Seite.
       (2 * Cn-1) ist soweit richtig, ich habe alles vorher ausgerechnet 
und
       komme genau am ende der Rampe auf meine Frequenz.
       Alle Variablen sind Global und als Volatile gekennzeichnet, 
wollte
       hier nur nicht alles dazuschreiben.
A.K.-> ich arbeite mit einem Mac und habe kein AVR Studio.

So, werde gleich mal mit dem Oszi ein abgespecktes Programm messen. Ich 
gebe dann mal das Ergebnis bekannt.
Gruss
Frank

von Oliver (Gast)


Lesenswert?

Nur so als Größenordnung: Eine float-Addition benötigt um die 180 Takte, 
eine Division ca. 500, usw.

Damit reichen 800 Takte für die ganze Berechnung bei weitem nicht aus.

Oliver

von Karl H. (kbuchegg)


Lesenswert?

FrankH schrieb:
> Hi an Alle,
> danke erstmal für die Antworten.
> Vlad-> ich dachte mit den Float-Werten bin ich auf der richtigen Seite.

Aufpassen.
float ist nicht automatisch die Lösung aller Probleme.
Mit naivem Einsatz von float kannst du dir ganz schnell einen komplett 
neuen Sack an Problemen aufmachen, an die du vorher noch nicht mal im 
Traum gedacht hast. Und Rechenzeit ist da noch das kleinere Übel.

von Stefan Kunz (Gast)


Lesenswert?

Oder wenn man Pech hat fallen sie einem erstmal gar nicht auf.
Bei Integer Berechnung kann man die Zahlen bequem anpassen, außerdem 
fallen dort Überläufe und nicht berücksichtbare kleine Zahlenbreiche 
schneller auf als bei Float.
Der Informationsgehalt der verschiedenen Zahlen Defenetionen bei 
gleicher Bitanzahl ist eh gleich. Float verleitet einfach dazu es zu 
benutzen um weniger denken zu müssen oder wenn man Ressourcen ohne Ende 
hat.

von FrankH (Gast)


Lesenswert?

Ok, ihr habt recht und ich ein Problem.
ich brauche ca. 500µs für die Berechnung.
bei 16MHz -> 2 Takte je Periode -> 1 Takt=31,25ns
500µs/31,25ns=16000 Takte

mir stehe bei größter Winkelgeschwindigkeit im fast PWM-Modus
aber nur 50µs zwischen den Takten bzw. eher 40µs zur verfügung.
Ich kann also bis 1280, besser aber so 800 Takte verwenden.
ich muss aber mit großen Zahlen rechnen.
mein SchrittZähler geht bis 11000 Schritte und
Cn kann ja bis 0xffff zählen und
n und m können theoretisch auch Werte bis 11000 annehmen.

Wie komme ich denn jezt mit Integerwerten zurecht, da fehlt mir gerade 
das Verständnis für.
Ich hoffe ihr könnt mir da Tipps geben.
Gruss
Frank

von Karl H. (kbuchegg)


Lesenswert?

So wie ich das mit dem kleinen Ausschnitt sehe, muss schrittWeite und 
endeRampe schon mal nicht float sein.

Cn=Cn-1 - ((2 * Cn-1)/( 4 * (n - m) + 1));

das müsste man jetzt mal analysieren. Was ist die mathematische Idee 
hinter dieser Formel, wie kommt sie zustande? Was sind n und m? Wieviele 
Kommastellen benötigst du für Cn, damit sich der Fehler bei einer Rampe 
nicht zu unwägbar grossen Werten aufschaukelt.

von aha (Gast)


Lesenswert?

Na die Berechnung :
Cn=Cn-1 - ((2 * Cn-1)/( 4 * (n - m) + 1));
sollte doch wohl noch in Ganzzahl gehen. Bei der division das "/" durch 
ein "div" ersetzen.

von Karl H. (kbuchegg)


Lesenswert?

aha schrieb:
> Na die Berechnung :
> Cn=Cn-1 - ((2 * Cn-1)/( 4 * (n - m) + 1));
> sollte doch wohl noch in Ganzzahl gehen.

Nicht unbedingt.
Das ist offensichtlich eine iterative Berechnung. Wenn man zuviele 
Nachkommastellen unter den Tisch fallen lässt, schaukeln sich 
Ungenauigkeiten auf.


> Bei der division das "/" durch
> ein "div" ersetzen.

In Pascal vielleicht. Das hier ist aber C.

von FrankH (Gast)


Lesenswert?

"div" funktioniert mit C irgendwie nicht, ist mir auch nicht bekannt.

ok,ich versuche das mal zu erklären.
Grundlage:
Mit dem Schrittmotor verfahre ich einen Tisch an meinem Linearteststand.
Der Schrittmotor hat eine eingestellte Auflösung von 1000 Schritte die 
Umdrehung.
Der Verfahrweg ist auf 1,21m begrenzt und das Antriebsrad hat r=0,0175m 
bzw. U=0,11m.
Mein Verfahrweg beträgt demnach 11000 Schritte.
Formel:
{
   //aktueller Schritt auf dem Verfahrweg
   schrittWeite++;

   //endeRampe begränzt die die lineare beschleunigung
   if (schrittWeite < endeRampe)
   {
      //Cn ist der aktuelle berechnete Zählwert für Timer1
      //Cn-1 ist demnach der vorherige Zählwert
      //n ist eigentlich die schreittWeite, brauche ich aber wegen
      //mehrfachbeschleunigungen in einem Fahrprofil
      //m brauche ich um von einer Geschwindigkeit V auf 0 zu verzögern
      //m entspricht der Schritt in dem V = 0 sein soll
      Cn=Cn-1 - ((2 * Cn-1)/( 4 * (n - m) + 1));
      //ICR1 ist der Zählwert des Timer1
      ICR1 = Cn;
   }
   else //Endesequenz einleiten
}

Die Formel habe ich unter anderem von
AVR446: linear speed control of stepper motor
oder auch hier
http://www.embedded.com/columns/technicalinsights/56800129?_requestid=208248

Gruss
Frank

von Stefan Kunz (Gast)


Lesenswert?

Nur mal als Frage

      Cn=Cn-1 - ((2 * Cn-1)/( 4 * (n - m) + 1));
      ICR1 = Cn;

ICR1 ist doch sicherlich ein Register im AVR. Mich wundert, dass das so 
einfach hinnimmt das dort eine float-Zahl reingeschrieben werden soll.
Ich kann mich auch täuschen, da ich bis jetzt nur mit ARM Erfahrung 
habe,
aber das sollte eigentlich funktionieren, da dass der Wert des Timers 
ist bis wohin er zählen soll und eine float Zahl, in dem Fall als double 
deklariert sollte eigentlich zu einem falschen Ergebnis führen.

von Oliver (Gast)


Lesenswert?

ICR1 ist für den Compiler ein volatile unsinged int, und dem darf man 
ohne weiteres einen float zuweisen. Das castet der automatisch richtig.

Oliver

von Karl H. (kbuchegg)


Lesenswert?

FrankH schrieb:

>       //n ist eigentlich die schreittWeite, brauche ich aber wegen
>       //mehrfachbeschleunigungen in einem Fahrprofil
>       //m brauche ich um von einer Geschwindigkeit V auf 0 zu verzögern
>       //m entspricht der Schritt in dem V = 0 sein soll

n und m sind mir noch unklar.
Was sind so typische Wertebereiche für die beiden?

von Oliver (Gast)


Lesenswert?

>oder auch hier
>http://www.embedded.com/columns/technicalinsights/...

"Oder auch hier" beginnt mit:

>A new algorithm for stepper-motor acceleration allows speed profiles to >be 
parameterized and calculated in real time. This algorithm can run on a >low-end 
microcontroller using only simple fixed-point arithmetic >operations and no data 
tables. It develops an accurate approximation for >the timing of a linear ramp 
with constant acceleration and deceleration.

Der Algorithmus ist also explizit für die Verwendung von 
Fixed-Point-Arithmetik geeignet. Keine floats erforderlich.

Oliver

von Vlad T. (vlad_tepesch)


Lesenswert?

> (2 * Cn-1) ist soweit richtig, ich habe alles vorher ausgerechnet
ok, die schreibweise/formatierung lässt vermuten, dass Cn-1 als erstes 
ausgerechnet werden soll.

von Karl H. (kbuchegg)


Lesenswert?

FrankH schrieb:

> Die Formel habe ich unter anderem von

Da hast sie aber nicht richtig übernommen.
Beachte, dass C mit dem Index (n - 1) nicht dasselbe ist, wie Cn - 1

Die Umsetzung lautet ganz einfach

     Cn = Cn - ((2 * Cn)/( 4 * (n - m) + 1));

Und freundlicherweise wird im Artikel auch erwähnt, dass es sich um 24.8 
Fixed Point Arithmetik handelt. Also 8 Bit für den Nachkommaanteil, oder 
anders ausgedrückt: Alles mal 256

von FrankH (Gast)


Lesenswert?

Hallo Karl Heinz,
eigentlich steht dort das C mit dem Index(n-1), zB. wenn x = (n-1) wäre, 
dann lautet die Formel:

Cn = Cx - ((2 * Cx)/(4 * (n - m) + 1));

ich habe auch extra nochmal nachgesehen, oder habe ich Tomaten auf den 
Augen  ;-) (kleiner Scherz)
Aber ihr habt ja alle recht, ich kann natürlich mit Ganzzahlen rechnen, 
das beschleunigt ja ungemein.

Frage:
Wenn ich mit 16Bit Werten rechne, dann komme ich von der Zeit in meiner 
Interrupt-Routine sehr gut hin, aber wie ist es denn, wenn im jetzigen 
Beispiel Cx den Wert 50000 hat und ich es mit 2 multipliziere (2 * Cx)
Wäre es dann nicht ein 32Bit Wert?
Also der Gesamtwert der Bruchrechnung ergibt ja wieder ein Wert der 
16Bit entspricht. Im Bruch selber werden Werte berechnet die über 16Bit 
liegen.
Rechnet der µC trotzdem richtig oder können dort noch Tricks angewendet 
werden?
Gruss
Frank

von Oliver (Gast)


Lesenswert?

>Und freundlicherweise wird im Artikel auch erwähnt, dass es sich um 24.8
>Fixed Point Arithmetik handelt.

>Frage:
>Wenn ich mit 16Bit Werten rechne, dann komme ich von der Zeit in meiner
>Interrupt-Routine sehr gut hin,

Antwort: Das passt halt nicht zusammen :-)
Dummerweise dauert die 32-Bit-Integer-Rechnerei (24.8 ist 32 bit) 
(erheblich) viel länger als 16 bit. Da musst du nochmals über das 
gesamte Konzept nachdenken.

Oliver

von Vlad T. (vlad_tepesch)


Lesenswert?

naja, die paar operationen, wird er locker packen

von FrankH (Gast)


Lesenswert?

Hi ich noch einmal,
danke wieder für die gegebenen Antworten und Tipps.

Stand der Dinge:
Mit den 32Bit-Werten liege ich auch gerade noch so in meinem geforderten 
Bereich.
Ich habe es noch einmal nachgerechnet und gemessen.

zwischen jeden Auslösen des Interrupts im fast PWM Modus liegen 54µs bei 
größter benötigter Winkelgeschwindigkeit. Die Berechnung der Formel mit 
32Bit Werten bräuchte ca. 44µs, sind also noch 10µs "Luft".

ich würde aber wenn es geht noch ein wenig mehr Zeit raus holen. Wäre es 
nicht schneller wenn ich die Berechnung im Assembler-Code schreibe?

Wenn ja, könnte mir jemand die folgende Berechnung mal als 
Assembler-Code schreiben

schrittWeite++;
   if (schrittWeite < endeRampe)
   {
      Cn=Cn-1 - ((2 * Cn-1)/( 4 * (n - m) + 1));
      ICR1 = Cn;
   }

Müsste ich noch irgendwas includen oder kann ich ein Assembler Codeteil 
in meinem C-Code einbinden?
Ich würde gerne mal sehen ob es da Unterschiede in der Berechnungszeit 
gibt.
Gruss
Frank

von Peter (Gast)


Lesenswert?

ich glaube nicht das asm hier viel schneller ist, da du alles mit 32bit 
machen willst ist der asm-code nicht garde überschaubar und auch recht 
kompleex im vergleich zu dem C code.

Schau doch mal in die lss Datei, dort siehst du den code den den 
compiler erzeugt hat.

Wichtig wäre mal zu wissen, ob die variabeln nicht etwas volatil sind.

von Frank H. (frankh)


Lesenswert?

So, habe mich mal hier angemeldet.

Peter schrieb:
> Wichtig wäre mal zu wissen, ob die variabeln nicht etwas volatil sind.

Ja, die Variablen sind global und alle volatile. Hat das irgendwelche 
Auswirkungen? Ausser das ich sie in einem Interrupt verwenden kann.
Gruss
Frank

von Peter (Gast)


Lesenswert?

> Ja, die Variablen sind global und alle volatile. Hat das irgendwelche
> Auswirkungen
ja, und zwar gute und schlechte.

Die schlechte ist, das sie jedes mal aus dem speicher gelesen wird wenn 
du sie verwendest.


Mache mal den vergleich und schau dir den asm code an. Einmal mit 
volatil und einmal ohne.

Und dann am besten das mal als vergleich
{
   int32_t tmp = Cn;
   tmp =tmp -1 - ((2 * tmp -1)/( 4 * (n - m) + 1));
   ICR1 = tmp ;
   Cn = tmp;
}

von Frank H. (frankh)


Lesenswert?

Hi Peter,

Peter schrieb:
> Und dann am besten das mal als vergleich
> {
>    int32_t tmp = Cn;
>    tmp =tmp -1 - ((2 * tmp -1)/( 4 * (n - m) + 1));
>    ICR1 = tmp ;
>    Cn = tmp;
> }

alles klar, werde ich morgen gleich testen.
Gruss
Frank

von Frank H. (frankh)


Lesenswert?

Als erstes muss ich mich mal bei den Leuten hier bedanken, ihr seit echt 
hilfsbereit. Wenn ich mich weiter eingearbeitet habe, hoffe ich auch 
anderen hier im Forum genauso helfen zu können.

Peter schrieb:
> Mache mal den vergleich und schau dir den asm code an. Einmal mit
> volatil und einmal ohne.

Leider kenne ich mich mit dem Assembler - Code nicht aus.
Ich habe aber deinen Tipp mit der temporären Variable umgesetzt und 
konnte damit 1 µs gewinnen.
Danke dafür.

Zur Zeit ist m eine globale volatile Variable, im nächsten Schritt 
wollte ich eine Struct anlegen, in dem wichtige Werte ( zB. m ) für die 
einzelnen Phasen meiner Fahrrampe hinterlegt sind. Meine Fragen hierzu 
wären:

Kann ich aus einem Interrupt auf eine Struktur zugreifen?
Wenn ja, muss ich die Variablen auch mit einem volatile kennzeichnen?
Gibt es dabei Wichtiges zu beachten?

Gruss
Frank

von Peter (Gast)


Lesenswert?

> Leider kenne ich mich mit dem Assembler - Code nicht aus.
> Ich habe aber deinen Tipp mit der temporären Variable umgesetzt und
> konnte damit 1 µs gewinnen.
> Danke dafür.
Dann stellt doch den asm code einfach mal hier rein.


ein Struct ist erstmal eine normale variabel es gibt dafür erstmal keine 
einsränkung was Interupts angeht.

Wie es sich aber mit volatil verhählt kann ich auch nicht sage. Ob die 
ganze struct oder nur einzelene members volatil sein sollten.

Ich finde es eh sinvoller sich erstmal mit asm auf einem µC zu 
beschäftigen, damit versteht man besser warum mancher C-Code nicht 
optimal ist.

von Frank H. (frankh)


Lesenswert?

Ja würde ich gerne, nur müsste ich wissen welcher der asm-Code ist?  ;-)
Ist das main.hex oder main.0, sorry ich programmiere auf dem Mac mit 
Xcode und kenne mich noch nicht wirklich aus.
Gruss
Frank

von Peter (Gast)


Lesenswert?

Ich kenn es nur vom GCC da wird ein lss file erzeugt.

Schau mal in alle Dateien rein. Asm sollte so in der art ausehen.

      ldi  temp1, 1<<LED
      out  led_ddr, temp1
      ldi  temp1, $00
      out  key_ddr, temp1
      ldi  temp1, $FF
      out  key_port, temp1
      mov  key_old, temp1

von Klaus W. (mfgkw)


Lesenswert?

Bevor man jedem einzeln die Grundlagen mühsam erklärt, wäre es
nicht effizienter, sich erst mal die einschlägigen Tutorials
(z.B. hier im Forum) reinzupfeifen, und dann noch offene Fragen
erklären lassen?

von Frank H. (frankh)


Lesenswert?

Klaus Wachtler schrieb:
> Bevor man jedem einzeln die Grundlagen mühsam erklärt, wäre es
> nicht effizienter, sich erst mal die einschlägigen Tutorials
> (z.B. hier im Forum) reinzupfeifen, und dann noch offene Fragen
> erklären lassen?

Hi,
ich glaube nicht das ich ein Anfänger bin dem man noch die Grundlagen 
erklären muss nur weil ich mich noch nicht mit Assembler programmieren 
beschäftigt habe.
Gruss
Frank

von Karl H. (kbuchegg)


Lesenswert?

FrankH schrieb:

> Mit den 32Bit-Werten liege ich auch gerade noch so in meinem geforderten
> Bereich.

Was hast du jetzt alles auf 32 Bit gehoben?

Frage: Müssen m und n 32 Bit sein, oder reichen dort auch 16 Bit?
Cn wird wohl auf 32 Bit bleiben müssen. Obwohl: Du benutzt ja zur Zeit 
gar keine Fixpunkt-Arithmetik!

>       ICR1 = Cn;

Sonst müsste hier sowas in der Art von

        ICR1 = Cn / 256;

stehen.

Daher nochmal die Frage: Welche Werte (Wertebereich) können Cn, n und m 
annehmen. Das ist insofern wichtig um entscheiden zu können, welche 
Teile der Berechnung unbedingt in 32 Bit und welche zb noch in 16 Bit 
erledigt werden können. Zb. kann ich mir gut vorstellen, dass es kein 
Problem ist

    n - m

als 16 Bit berechnen zu lassen, solange n und m immer im 16 Bit 
Wertebereich ist.

von Frank H. (frankh)


Angehängte Dateien:

Lesenswert?

So, ich habe das mal hier auf dem Windowscomputer in Notepad 
kompilliert, dort waren dann auch die gewünschten Files. Unter Xcode 
konnte ich die nicht finden.
Gruss
Frank

von Karl H. (kbuchegg)


Lesenswert?

Frank H. schrieb:

> ich glaube nicht das ich ein Anfänger bin dem man noch die Grundlagen
> erklären muss nur weil ich mich noch nicht mit Assembler programmieren
> beschäftigt habe.

So wie es aussieht, bist du im Teilbereich Fixpunkt-Arithmetik noch 
Anfänger.

von Klaus W. (mfgkw)


Lesenswert?

sorry, ich wollte nicht beleidigend werden.

Manches steht aber halt auch in der Doku zum jeweiligen Compiler
etc. (z.B. welche Dateien welche Bedeutung haben und sowas).

von Frank H. (frankh)


Lesenswert?

Hallo Karl Heinz,
Cn ist 32Bit
n u. m habe ich 16Bit
alle weiteren Variablen die die Schrittzahl representieren sind 16Bit.
Gruss
Frank

von Karl H. (kbuchegg)


Lesenswert?

Frank H. schrieb:
> Hallo Karl Heinz,
> Cn ist 32Bit
> n u. m habe ich 16Bit
> alle weiteren Variablen die die Schrittzahl representieren sind 16Bit.

Habs mir gerade aus dem Assembler zusammengereimt.

hier ist die bewusste Sequenz
1
      temp = temp-((2*temp)/(4*(schrittZaehler - endeRampe3)+1));
2
 14c:  20 91 60 00   lds  r18, 0x0060
3
 150:  30 91 61 00   lds  r19, 0x0061
4
 154:  e0 91 71 00   lds  r30, 0x0071
5
 158:  f0 91 72 00   lds  r31, 0x0072
6
 15c:  c8 01         movw  r24, r16
7
 15e:  b7 01         movw  r22, r14
8
 160:  66 0f         add  r22, r22
9
 162:  77 1f         adc  r23, r23
10
 164:  88 1f         adc  r24, r24
11
 166:  99 1f         adc  r25, r25
12
 168:  2e 1b         sub  r18, r30
13
 16a:  3f 0b         sbc  r19, r31
14
 16c:  22 0f         add  r18, r18
15
 16e:  33 1f         adc  r19, r19
16
 170:  22 0f         add  r18, r18
17
 172:  33 1f         adc  r19, r19
18
 174:  2f 5f         subi  r18, 0xFF  ; 255
19
 176:  3f 4f         sbci  r19, 0xFF  ; 255
20
 178:  40 e0         ldi  r20, 0x00  ; 0
21
 17a:  50 e0         ldi  r21, 0x00  ; 0
22
 17c:  2c d2         rcall  .+1112     ; 0x5d6 <__udivmodsi4>
23
 17e:  c9 01         movw  r24, r18
24
 180:  da 01         movw  r26, r20
25
 182:  e8 1a         sub  r14, r24
26
 184:  f9 0a         sbc  r15, r25
27
 186:  0a 0b         sbc  r16, r26
28
 188:  1b 0b         sbc  r17, r27
29
 18a:  07 c0         rjmp  .+14       ; 0x19a <__vector_5+0xfe>

Das sieht eigentlich schon ziemlich gut aus. Ich denke nicht, dass da 
noch viel geht.

von Frank H. (frankh)


Lesenswert?

Karl heinz Buchegger schrieb:
> So wie es aussieht, bist du im Teilbereich Fixpunkt-Arithmetik noch
> Anfänger.

Stimmt, leider bin ich kein Informationsschwamm der alles in ms 
aufsaugen kann. ;-)
Gruss
Frank

von Peter (Gast)


Lesenswert?

> So, ich habe das mal hier auf dem Windowscomputer in Notepad
> kompilliert
Wusste gar nicht das das notepas Kompileren kann...


aber die lss Datei ist die richtige. Daran sieht man recht deutlich das 
man da nicht mehr viel optimieren kann. Die meiste zeit geht bei der 
Division drauf der rest ist vernachlässigbar.

Wenn du also nicht die Division wegbekommt, geht da nichts mehr 
schneller.

von Frank H. (frankh)


Lesenswert?

Klaus Wachtler schrieb:
> sorry, ich wollte nicht beleidigend werden.
>
> Manches steht aber halt auch in der Doku zum jeweiligen Compiler
> etc. (z.B. welche Dateien welche Bedeutung haben und sowas).

Kein Problem.
Gruss
Frank

von Frank H. (frankh)


Lesenswert?

Peter schrieb:
>> So, ich habe das mal hier auf dem Windowscomputer in Notepad
>> kompilliert
> Wusste gar nicht das das notepas Kompileren kann...

Programmers Notepad [WINAVR], dann oben auf Tools und dort hast 
du(zumindest ich hier)
[WINAVR] Make All
[WINAVR] Make Clean
[WINAVR] Program

Gruss
Frank

von Frank H. (frankh)


Lesenswert?

Hallo Leute,
bis jetzt bin ich gut vorangekommen. Wie in dem oben beschrieben Artikel 
benutze ich jetzt die 24.8 Arethmetik (zumindest versuche ich das), 
klappt auch ganz gut nur bei der Verzögerungsrampe habe ich ein Problem. 
Kann auch sein das ich den englischen Text nicht richtig lesen kann.

n ist der aktuelle Schritt
m ist das Ende der Rampe
Bei der Beschleunigung ist m=0, bei der Verzögerung bekommt m den 
Endwert der Fahrstrecke zugewiesen (m > n).

   temp = temp-((2*temp+rest)/(4*( n-m )+1));
   rest=((2*temp+rest)%(4*(n-m)+1));


Kann es sein das rest=(positiver Wert)%(negativer Wert)  ein generelles 
Problem ist?
Die Berechnung liefert mir in einem C-Code auf der Konsole die richtigen 
Werte, jedoch im µC funktioniert das nicht.
Ich habe auch versucht den negativen Wert zu negieren (-(negativer 
Wert)), hat mir aber nicht geholfen. Vielleicht hat jemand einen Tipp.
Gruss
Frank

von Frank H. (frankh)


Lesenswert?

***PUSH*****
Würde dieses Problem gerne wieder in Erinnerung rufen.
Gruss
Frank

von Karl H. (kbuchegg)


Lesenswert?

Frank H. schrieb:

> Die Berechnung liefert mir in einem C-Code auf der Konsole die richtigen
> Werte, jedoch im µC funktioniert das nicht.

Lass doch mal dein Programm ansehen, wie es jetzt aussieht.
Langsam müsstest du schon begriffen haben, dass auch Details wichtig 
sein können, wie zb die verwendeten Datentypen.

Ein Unterschied zwischen PC und µC ist zb, dass ein int auf dem PC 
heutzutage meist 32 Bit ist, während er auf deinem AVR nur 16 Bit ist. 
Das kann den alles entscheidenden Unterschied machen, wenn während einer 
Berechnung ein Zwischenergebnis entsteht, welches überläuft.

> Ich habe auch versucht den negativen Wert zu negieren (-(negativer
> Wert)), hat mir aber nicht geholfen. Vielleicht hat jemand einen Tipp.

Der einzig sinnvolle Tip lautet:
Verschaff dir eine Möglichkeit, wie du Zwischenergebnisse irgendwo 
anzeigen lassen kannst. Momentan stocherst du im Nebel. Das führt zu 
nichts, wenn du anstatt einer roten eine blaue Stange zum stochern 
benutzt. Du musst den Nebel beseitigen! Das bedeutet nun mal: die 
verwendeten Zahlenwerte und Zwischenergebnisse müssen her um sie 
studieren zu können.

von Frank H. (frankh)


Angehängte Dateien:

Lesenswert?

Oha,
am liebsten würde ich meine letzte Frage zurückziehen  ;-(
Der Fehler war so simpel, das es mir schon peinlich ist.
Da habe ich doch seit gestern das Problem gesucht und erst jetzt 
gefunden.
Wie soll die Variable rest auch negative Werte annehmen können, wenn es 
eine uint16_t - Variable ist. Ich habe den Code trotzdem mal angehängt.
tztztztz

Karl Heinz-> Du hast natürlich recht, ich habe auch angefangen mein 
Programm in Teilprogramme zu spalten die ich nach einer Veränderung erst 
teste. Auch ist mir nun klar wie wichtig die Datentypen sind, ich denke 
das ich mich da langsam aber sicher hineinfuxen werden.

Gruss vom ständig Lernenden
Frank
;-)

von sam (Gast)


Lesenswert?

Es gibt da übrigens im AVR-studio eine coole funktion:  nennt sich 
simulator.
würde ich mal ausprobieren, kann man auch im einzelschritt durchs 
c-programm und man kann die prozessorzyklen dabei zählen, sogar in zeit 
umgerechnet sehen

von Michael W. (retikulum)


Lesenswert?

@ sam,
einfach mal lesen. Er programmiert auf einem Mac.

von Oliver (Gast)


Lesenswert?

>Er programmiert auf einem Mac.

Die Auswahl des richtigen Werkzeugs war schon immer entscheidend. Auch 
wenn ein Mac ein toller Rechner ist, mit einem Simulator wäre er jetzt 
schon längst fertig.

Oliver

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.