Hallo zusammen,
bin mal wieder auf der Suche nach einer Idee:
Habe vor einiger Zeit eine Steuerungelektronik für eine CNC-Fräse
gebastelt, läuft alles über TTL, auf ein Signal für vorwärts/rückwärts
eins für die Pulse (Anzahl der Schritte), das ganze für 3 Achsen. Läuft
super.
Nun fehlt nur noch eine Anzeige, die zeigt, wo sich das ganze denn nu
befindet. Da dachte ich mir ich mach mal eben.....
ich benutze die 3x2 Signale als Eingang an einen atmega8, über SPI-magic
habe ich ein LCD Display angeschlossen. Das funktioniert auch alles, nur
ist das Display so langsam, dass der mega8 ein paar Signale verschluckt.
Hier und da mal dieses _delay_us(42) - da addiert sich ganz schön was
zusammen.
Es gibt, denke ich, zwei Möglichkeiten:
1. Ich bastele eine neue Platine, mit einem größeren Controller und
benutze die externen Trigger und mach das alles als Interrupt Handling
2. Ich muß die lcd_data() und lcd_command() Aufrufe irgendwie besser
verteilen, dann ist die Chance ein Signal zu sehen viel größer. Diese
Lösung bevorzuge ich momentan.
Man könnte die ganzen lcd_data() und lcd_command() -Aufrufe in einen
FIFO packen, und die dann Stück für Stück abarbeiten. Hat jemand sowas
schonmal gemacht, Erfahrungen damit?
Achso ich maximale Signalfrequenz sollte kleiner als 3.5 kHz sein
Gruß und Danke im Voraus
Schorsch
Schorsch schrieb:
Lösung 3)
Da kein Mensch si schnell lesen kann, ist es auch völlig unsinnig ein
LCD mehr als 3 oder 4 mal in der Sekunde mit neuen Werten zu versorgen.
Also: nicht nach jedem Schritt die aktuelle Schrittnummer ans LCD geben,
sondern einen Timer aufsetzen, der 3 oder 4 mal in der Sekunde sich die
momentan gerade aktuelle Schrittnummer holt und ans LCD weitergibt.
In der Praxis macht man das so, dass man sich mit dem Timer ein Job-Flag
bedient, welches 3 oder 4 oder 5 mal in der Sekunde auf TRUE geht und
nur dann wenn dieses Flag auf TRUE ist, gibt die Schrittroutine
zwischendurch noch schnell mal die aktuelle Schrittzahl aufs LCD aus und
setzt das Flag wieder zurück.
-> Fazit: Der Zeitverlust durch das LCD bewegt sich unter "ferner
liefen" irgendwo im Zehntel-Promille-Bereich.
Man kann wunderbar damit arbeiten, dass wir Menschen aus Sicht eines µC
extrem langsam sind und für alles (auch für das Lesen einer Anzeige)
lange brauchen. Es ist daher gar nicht notwendig JEDE einzelne schnelle
Änderung auf einer Anzeige anzuzeigen.
Karl Heinz Buchegger schrieb:> Also: nicht nach jedem Schritt die aktuelle Schrittnummer ans LCD geben,> sondern einen Timer aufsetzen, der 3 oder 4 mal in der Sekunde sich die> momentan gerade aktuelle Schrittnummer holt und ans LCD weitergibt.
Gerade probiert....
Ist auch zu langsam:
Beispielrechnung - Wenn ich nur 8 Zeichen übertrage ist alleine die
Delay_Zeit 8*42µs = 0.33ms. Dazu kommt noch die eigentliche
Command-Zeit. D.h. während diese Zeit bekomme ich die Signalwechsel
einfach nicht mit
Schorsch
Dann waere vielleicht ein groesseres graphisches LCD besser, da kann man
die Wechsel auflisten und hochscrollen. Der Controller muss dann auch
etwas mehr Dampf haben.
Schorsch schrieb:> Karl Heinz Buchegger schrieb:>> Also: nicht nach jedem Schritt die aktuelle Schrittnummer ans LCD geben,>> sondern einen Timer aufsetzen, der 3 oder 4 mal in der Sekunde sich die>> momentan gerade aktuelle Schrittnummer holt und ans LCD weitergibt.>> Gerade probiert....>> Ist auch zu langsam:>> Beispielrechnung - Wenn ich nur 8 Zeichen übertrage ist alleine die> Delay_Zeit 8*42µs = 0.33ms.
Dann ürtrag halt nicht alle 8 Zeichen am Stück :-)
Hallo,
Ich benutze im wesentlichen diese
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/LCD-Ansteuerung
Funktionen, um mit dem LCD zu reden.
Nach der übertragung eines jeden Chars (siehe Code) muß eine delay-Zeit
eingehalten werden.
Anstelle das LCD direkt anzuschließen habe ich eine hc595
dazuwischengeschaltet, da der mega8 zu wenige Beinchen hat. Das meine
ich mit SPI-Magic.
Größere Displays halte ich nicht für zielführend. Einzig µC mit mind
drei externen Trigger Eingängen wären nützlich
Schorsch
Ich denke es wird Zeit die Ratespielchen und Ratschläge ins Blaue zu
beenden und du solltest mal etwas Code zeigen.
Dann kann man sich die Sache auch mal ansehen und qualifiziert was
sagen, ohne sich in allgemeine Strategien zu flüchten.
Schorsch schrieb:> Hallo,>> Ich benutze im wesentlichen diese> http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/LCD-Ansteuerung> Funktionen, um mit dem LCD zu reden.>> Nach der übertragung eines jeden Chars (siehe Code) muß eine delay-Zeit> eingehalten werden.
Man kann das ganze aber auch ein wenig intelligent organisieren. Niemand
sagt, dass der µC in dieser Zeit Däumchen drehen muss. Er kann zb in
dieser Zeit bereits das nächste Zeichen zurechtlegen.
> Anstelle das LCD direkt anzuschließen habe ich eine hc595> dazuwischengeschaltet,
Und auch die Ausgabe (selbst wenn das die Hardware SPI macht) geschieht
ja auch nicht in 0-Zeit. Zeit, die du problemlos von deiner Wartezeit
für das LCD abziehen kannst.
Hustinetten-Baer schrieb:> Dann mach' halt die Delays auch per Timer und nicht per Bremsschleife.
Jup. Ist auch eine gute Möglichkeit.
Eine andere ist es, sich im Speicher ein LCD-Abbild zurecht zu legen in
dem die Änderungen durchgeführt werden.
In einer Timer-ISR wird reihum dieses LCD-Abbild durchgegangen und
jeweils immer nur 1 Zeichen ans LCD weiter gegeben. Das geht schnell,
danach ist die ISR schon wieder fertig und beim nächsten ISR-AUfruf
kommt die nächste LCD-Position (das nächste Zeichen) drann.
Hm,
mein Code ist ein bisschen unorganisiert.... :-p
daher möchte ich hier nicht alles posten. Nur ein paar Ausschnitte:
Hier werden die Signale eingelesen:
1
uint8_tnewPORTC=PINC;
2
if((newPORTC^lastPORTC)&0x02&&(newPORTC&0x02)){
3
if(newPORTC&0x01)xVAL--;elsexVAL++;
4
changed|=0x01;
5
}
6
if((newPORTC^lastPORTC)&0x08&&(newPORTC&0x08)){
7
if(newPORTC&0x04)yVAL--;elseyVAL++;
8
changed|=0x02;
9
}
10
if((newPORTC^lastPORTC)&0x20&&(newPORTC&0x20)){
11
if(newPORTC&0x10)zVAL--;elsezVAL++;
12
changed|=0x04;
13
}
14
lastPORTC=newPORTC;
Mit dieser Routine wird die aktuelle Postion, umgerechnet in mm
ausgegeben (die Frames spielen hier erstmal keine Rolle):
@ Schorsch (Gast)
>Gerade probiert....>Ist auch zu langsam:
Weil garantiert falsch umgesetzt.
>Beispielrechnung - Wenn ich nur 8 Zeichen übertrage ist alleine die>Delay_Zeit 8*42µs = 0.33ms. Dazu kommt noch die eigentliche>Command-Zeit. D.h. während diese Zeit bekomme ich die Signalwechsel>einfach nicht mit
Eben, weil falsch umgesetzt. So eine LCD-Ausgabe ist sowohl zeitlich als
auch funktional UNKRITISCH, kann demnach eher langsam ausgeführt und
ggf. auch oft durch einen Interrupt unterbrochen werden. Und genau
so MUSS man es machen. Die LCD-Ausgabe als "nebensächliches" Funktion
innerhalb der Hauptschleife. Wie das geht, sieht man im Artikel
Multitasking und Interrupt. Irgendwelche Delays sind dabei nicht
zu finden, bestenfalls im einstelligen Mikrosekundenbereich.
Möglichkweiten gibt es viele.
Aber eine FIFO gehört in deinem Fall (IMHO) nicht dazu.
Eine FIFO nimmt man wenn die Daten schubweise schnell anfallen und dann
wieder eine Zeit lang Ruhe ist.
Wie groß machst du denn die FIFO und was wird wohl deine FIFO dazu
sagen, wenn ich deine Steuerung auf allen 3 Achsen gleichzeitig eine
halbe Stunde lang mit 3.5kHz Pulsen zuballere, wenn dein Mega jetzt
schon nicht hinterher kommt.
Die Lösung deines Problems liegt in der intelligenten Nutzung der
Wartezeiten vom LCD. Dein Mega muss aufhören Däumchen zu drehen, wenn er
an anderer Stelle genug Arbeit hat.
Hallo,
Karl Heinz Buchegger schrieb:> Die Lösung deines Problems liegt in der intelligenten Nutzung der> Wartezeiten vom LCD. Dein Mega muss aufhören Däumchen zu drehen, wenn er> an anderer Stelle genug Arbeit hat.
da gehe ich mit!
Ich glaube aber, wir meinen das gleiche.... zumindest wäre mir sonst
nicht klar, wie ich das umsetzen sollte.
Ich muß doch an igendeinder Stelle im Programm sagen "verändere folgende
Stellen mit Werten soundso". Meiner Meinung nach müsste man all diese
Kommandos irgendwo niederschreiben und nach und nach abarbeiten. Selbst
wenn ich den 'sich verändernden' Teil des Displays abbilde brauche ich
ein zwischen dem schreiben dem Setzen der Cursor-Position und dem
Schreiben des ersten Chars ein Delay von 42µs.
Wie würds Du es machen?
Schorsch
@ Schorsch (Gast)
>ein zwischen dem schreiben dem Setzen der Cursor-Position und dem>Schreiben des ersten Chars ein Delay von 42µs.
Ist ja OK, solange du dabei nicht die Interrupts sperrst.
>Wie würds Du es machen?
Siehe Multitasking.
Immer noch frage ich mich was ist SPI-Magic? Ist dein Display über einen
parallelen port oder über SPI angeschlossen?
Ziemlich Zeitintensiv sind die sprintf Routinen die du verwendest. Muss
es unbedingt float sein? Würde auch Long, bzw. Integer schon reichen?
Wandelst du manuell die float in String um, hast du eine enorme Bremse
beseitigt. Und wahrscheinlich dein Problem schon gelöst.
Dennoch noch für den Rest: Wie oft aktualisierst du momentan dein
Display? Wie oft sollte es aktualisiert werden?
Du sendest 6 Zeichen, d.h. 6*42us = 252us die deine LCD Routine
benötigt. D.h. du könntest dein Display mit 4kHz ohne Probleme
aktualisieren wenn ich jetzt mal nichts übersehen habe.
Was bedeutet für dich Daten verschluckt? Musst du die Signale mit 3.5kHz
abtasten? Brauchst du all diese Daten? Warum reicht es nicht alle 100ms
die Daten zu erfassen?
Damit hab ich erst mal eine ISR, die sukzessive bei jedem Aufruf ein
bischen was am LCD macht und Schritt für Schritt die Anzeige auf dem LCD
mit dem Inhalt von lcDisplay gleich zieht. Dadurch, dass sie Funktionen
benutzt, die am Ende eben nicht warten, entsteht da auch keine
großartige Verzögerung. Die notwendige Verzögerung fürs LCD entsteht
dadurch, dass es ja eine Zeit dauert, bis der nächste ISR Aufruf kommt,
an dem dann wieder was am LCD gemacht wird :-)
Um etwas auszugeben, genügt es dann, dasjenige einfach ins lcDisplay
Array zu schreiben. Die ISR gibt es dann 'gemächlich' im Hintergrund
sukzessive aus.
Das wäre mein Ansatz für ein LCD, welches mir in der Hauptschleife
möglichst nicht in die Quere kommt.
> sprintf(out,"%8.2fmm",(float)yVAL/stepsPerMmY+frameY[frame]);
Der float und der sprintf sind da aber auch nicht gerade das, was man
ein flinkes Wiesel nennen würde.
@ Karl Heinz Buchegger (kbuchegg) (Moderator)
>> sprintf(out,"%8.2fmm",(float)yVAL/stepsPerMmY+frameY[frame]);>Der float und der sprintf sind da aber auch nicht gerade das, was man>ein flinkes Wiesel nennen würde.
Spielt bei 5 Hz Updaterate keine Rolle, der Fehler steckt sowieso
woanders.
Falk Brunner schrieb:> Eben, weil falsch umgesetzt. So eine LCD-Ausgabe ist sowohl zeitlich als> auch funktional UNKRITISCH, kann demnach eher langsam ausgeführt und> ggf. auch oft durch einen Interrupt unterbrochen werden. Und genau> so MUSS man es machen. Die LCD-Ausgabe als "nebensächliches" Funktion> innerhalb der Hauptschleife. Wie das geht, sieht man im Artikel> Multitasking und Interrupt. Irgendwelche> Delays sind dabei nicht> zu finden, bestenfalls im einstelligen Mikrosekundenbereich.
Wenn auch nicht gerade elegant mit Delays, werde die ja auch vom
Interrupt unterbrochen. Die Signalerfassung über Interrupt zu machen
reicht völlig für seine Zwecke.
Hallo zusammen,
sooooo...
also habe die meisten Vorschläge umgesetzt, viele davon helfen.
Folgendes gemacht:
1. Ein Abbild des Displays in den Speicher, zyklisch wird alles über der
Timer übertragen, alle Delays sind raus -> hilft, reicht aber nicht
(16Mhz Clock, 8bit Timer, prescaler auf 256 -> ca 4 Updates vom
kompletten Display pro Sekunde, wie vorgeschlagen)
2. sprintf mit floats rausgeschmissen, erstmal alles mit den RAW-Values
ausprobiert. Erstaunlicher Weise hat das Weglassen der entsprechenden
Linker-Flags zur Folge, dass der Code 50% !!! kleiner wird, hätte ich
nie gedacht. Reicht immer noch nicht
3. Frisieren der SPI-Magic. Hatte die SPI SCK auf f/16, hab sie jetzt
mal auf f/4 frisiert, das hilf -> dadurch verliere ich in 30000 Impulsen
á 5kHz nur noch 2 - 3 Impulse. Die 1.5kHz zusätzlich sollten mir ein
bisschen Sicherheit geben. Immer noch 2-3 Pulse zu viel.
4. Prescaler auf 1024 (1 Update pro Sekunde) läuft immer noch..., habe
bis jetzt in 250k Pulsen noch keinen verloren. Dieser Weg scheint zu
funktionieren
5. Habe an Stelle der float-artigen sprintf-funktion per Hand einen
float-string anchgebaut:
sofort verliere ich Pulse. Selbst, wenn ich nur die Teile austausche,
die ich austauschen muß:
1
sprintf(writeOut,"%4d",xVALmm);
2
strncpy(&display[1][5],writeOut,4);
3
4
sprintf(writeOut,"%-2d",xVALmmm);
5
strncpy(&display[1][10],writeOut,2);
verliere ich Pulse.
-> Heißt mit anderen Worten:
Jetzt ist mein Display super langsam, und ich kann nur noch die Schritte
nicht mehr die Werte pro mm anzeigen. Vorschläge?
Danke Schorsch
@ Schorsch (Gast)
>Jetzt ist mein Display super langsam, und ich kann nur noch die Schritte>nicht mehr die Werte pro mm anzeigen. Vorschläge?
Zeig mal deinen VOLLSTÄNDIGEN Quelltext als Anhang und deinen
Schaltplan, Denn wir wissen immer noch nicht so recht, wie du deine
Signale erfasst. Mit der richtigen Konzept UND der richtigen UMSETZUNG
sollte es auch mit printf und float Variablen gehen.
Es gibt zwei Wege:
1: In einer Hauptschleife werden die Werte erfasst und ein Timer updatet
das Display.
Das Problem dabei: Wenn deine Routine in deinem Timer, oder deine
Hauptschleife generell länger dauert als eine Periode deines Signals, so
verlierst du ein Signal.
Das ist bei dir gerade der Fall. Du rechnest mit floats die sehr
Zeitintensiv sind. Rechne mit ganzen Zahlen. Wenn deine Zahlen klein
sind, dann mach alles um einen Faktor 10 bzw. 100 größer und du hast
Gleitkommazahlen umgangen. Ebenso geht dann die Displayausgabe deutlich
simpler, da du dann einen Integer in Character umwandlen musst, was
trivial ist. Den Punkt noch an die richtige Stelle einfügen, und fertig
ist die Sache.
2: In einer Hauptschleife die Displayausgabe und Berechnung, mit einem
Timer werden die Messwerte erfassen.
Das wird das einfachere und sicherere sein, da der Interrupt dein
Programm aus jedem momentanen Zustand unterbricht und sich den Messwert
holt. Dadurch musst du dir keine Sorgen machen, dass deine Hauptschleife
zu langsam ist, da es egal ist. Ist dein uC gerade an der Rechnung oder
am Daten ans Display senden, so unterrbricht er es kurz, holt sich den
Messwert, und führt die Rechnung/Sendung dann fort. Dadurch wird dein
Programm auch wieder übersichtlicher und simpler. Ein Buffer für das
Display ist dann überflüssig.
OK....
hier einmal das Schematic und der Quellcode
habe bislang nur die x-achse einprogrammiert, alles ist ein bisschen
häßlich und nicht-sortiert, sorry aber schön machen kann ichs immer noch
:-p
die Frames sind hier auch noch nicht reinprogrammiert. die frames sind
dafür da um verschiedene Null-Punkte für die CNC-Fräse anzugeben, mit
anderen Worte es handelt sich um eine Verschiebung der absoluten
Koordinaten
Gruß Georg
@Schorsch (Gast)
Was bitte soll man mit DEM "Schaltplan" anfangen? Nicht nur, weil nicht
alle Eagle haben, sondern weil der Inhalt unter alles Sau ist. Siehe
Anhang. Aber Ok, wir sind kreativ.
Schaltplan richtig zeichnen>habe bislang nur die x-achse einprogrammiert, alles ist ein bisschen>häßlich und nicht-sortiert,
IN der Tat.
> sorry aber schön machen kann ichs immer noch>:-p
Irrtum die Ite. Mit deinem Chaoscode macht du dir JETZT schon das Leben
schwer.
Strukturierte Programmierung auf Mikrocontrollern
Und dein Problem ist leicht erkennbar. Du stellt sämtliche, anerkannte
Programmierregeln zum Thema Interrupt auf den Kopf! Das kann nix
werden! Die LCD-Ausgabe hat im Interrupt NICHTS zu suchen! Deine
Encoderdekodierung muss in einen schnellen Timerinterrupt! Siehe
Drehgeber. Dann weißt du auch, bis zu welcher Frequenz du sicher
keine Schritte verlierst. Dann klappts auch mit einer nahezu beliebig
langsamen Hauptschleife.
(Warum war das mal wieder klar?)
MFG
Falk
@ Schorsch (Gast)
>angeschlossen. Das ist der ganze Quellcode:
Da fehlt ein
#define F_CPU 10e6
VOR
#include <avr/delay.h>
wenn es nicht in den Projekteinstellungen drin ist. Ich persönlich finde
es im Quelltext besser platziert.
Falk Brunner schrieb:> Da fehlt ein>> #define F_CPU 10e6>> VOR>> #include <avr/delay.h>>> wenn es nicht in den Projekteinstellungen drin ist. Ich persönlich finde> es im Quelltext besser platziert.
Er kann sich ja gerne auch damit
@Falk:
Das ist genau der Grund weshalb ich diese Daten nicht zeigen wollte.
Weil ich keine Bock auf dieses unkonstruktive rumgemeckere habe.
Thema Schaltplan:
Ich habe ich den letzen 10 Jahren etliche Schalpläne gezeichnet, dies
ist sicherlich nicht der schönste aber meine Datein, die ich hier
freiwillig veröffentlicht habe, so zu verunglimpfen in eine pure
Frechheit,
@FORENMASTER: Bitte Datei umbenennen! Oder löschen
weiter...
Beschwer dich nicht über meinen Quellcode, Du wolltest Ihn haben...
Falk Brunner schrieb:> Die LCD-Ausgabe hat im Interrupt NICHTS zu suchen! Deine> Encoderdekodierung muss in einen schnellen Timerinterrupt! Siehe> Drehgeber. Dann weißt du auch, bis zu welcher Frequenz du sicher> keine Schritte verlierst. Dann klappts auch mit einer nahezu beliebig> langsamen Hauptschleife.
jetzt kommt sogar ein konstruktive Beitrag von Falk...
die LCD Ausgabe in den Interrupt war ein Vorschlag aus diesem Thread von
Karl Heinz Buchegger (kbuchegg) (Moderator), habe ich ihn möglicherweise
falsch verstanden?
Hm... schneller Timerinterrupt? Du meinst ich soll einen timer laufen
lassen, der regelmäßig schaut, ob sich das Signal verändert hat? Was
soll das bringen? Mittlerweile steht nur noch die Signalabfrage in der
main-routine... externe Interrupts kann ich mit der fertigen Platine
nicht mehr anschließen, außerdem hat der mega8 nur 2
an... nochmal Falk:
>Da fehlt ein>#define F_CPU 10e6
ist ja schön, wenn Du deinen mega mit 10MHz betreibst, ich tue das
nicht, ich hab meine Taktfrequenz im Makefile stehen
Schorsch
Das was Falk angesprochen hat habe ich dir in meinem vorherigen Post
versucht zu erklären. Die Ausführung deines Interrupts benötigt eben
länger als die Periode deines Signals ist.
wie schon gesagt, dreh den Spieß einfach um und lese die Eingänge über
einen Interrupt ein und gebe die Daten an das Display über die
Hauptschleife aus.
Als Interrupt kann ein schnell genuger Timer dienen, der oft genug
einspringt, oder besser, falls du ein Taktsignal hast mit dem die Daten
gesendet werden, kannst du mit dem Input Capture Modul einen Interrupt
genau zur richtigen Zeit, eben durch den externen Takt gesteuert,
initiieren.
Du hast es implementiert wie dir empfohlen wurde, nur leider hat's eben
nicht funktioniert, da das Problem eben weniger das Display und mehr die
Textzusammensetzung ist. Du kannst dein Programm weiter aufbohren indem
du case 37 in einzelne cases aufteilst, sodass die Timerroutine
schneller ausgeführt wird. Ebenso auf floats verzichtest um die
Zahlenumwandlung in Text beschleunigst, da selbst wenn du sprintf selbst
implementiert hast, es immer noch deutlich langsamer ist als wenn du
Integer in Text, mit einer sogenannten uitoa Routine, umwandeln würdest.
Aber einfacher ist es, wenn du den Spieß einfach umdrehst.
Schorsch schrieb:> Hm... schneller Timerinterrupt? Du meinst ich soll einen timer laufen> lassen, der regelmäßig schaut, ob sich das Signal verändert hat? Was> soll das bringen?
eben das diese Timer-ISR immer ausgeführt wird egal was sonst gerade so
läuft.
lass die ISR mal mit 50 .. 100µs laufen
Abfrage noch ein bisschen opt. ...
1
uint8_tnewPORTC=PINC;
2
uint8_tchange=(newPORTC^lastPORTC)&0x2A;
3
if(change==0)return;//Eingänge unverändert
4
if(change&0x02){
5
if(newPORTC&0x01)xVAL--;elsexVAL++;
6
}
7
if(change&0x08){
8
if(newPORTC&0x04)yVAL--;elseyVAL++;
9
}
10
if(change&0x20){
11
if(newPORTC&0x10)zVAL--;elsezVAL++;
12
}
13
lastPORTC=newPORTC;
14
return
mit einem weiteren Timer sorgst du dafür das das Display 4x pro sec die
Werte schreibt. Aber im Timer nur ein Flag setzen, das Update aus Main
heraus machen.
Sascha
@ Schorsch (Gast)
>Ich habe ich den letzen 10 Jahren etliche Schalpläne gezeichnet, dies>ist sicherlich nicht der schönste aber meine Datein, die ich hier>freiwillig veröffentlicht habe, so zu verunglimpfen in eine pure>Frechheit,
Informier dich mal zum Thema Kritikfähigkeit.
>Beschwer dich nicht über meinen Quellcode, Du wolltest Ihn haben...
Beschweren? Nö, ist mir am Ende egal wie der aussieht. DU willst ein
lauffähiges Programm haben, DU willst, dass Leute dir helfen.
>die LCD Ausgabe in den Interrupt war ein Vorschlag aus diesem Thread von>Karl Heinz Buchegger (kbuchegg) (Moderator),
Glaub ich nicht.
>habe ich ihn möglicherweise>falsch verstanden?
Das schon eher ;-)
>Hm... schneller Timerinterrupt? Du meinst ich soll einen timer laufen>lassen, der regelmäßig schaut, ob sich das Signal verändert hat?
Ja.
> Was soll das bringen?
Dass die wichtigem, zeitkritischen Sachen GARANTIERT abgearbeitet
werden. Eine mirkosekunden dauernde Unterbrechung der LCD-Ausgabe ist
vollkommen unkritisch, eine Millisekundenunterbrechung der
Signalerfassung tödlich.
> Mittlerweile steht nur noch die Signalabfrage in der>main-routine... externe Interrupts kann ich mit der fertigen Platine>nicht mehr anschließen,
Brauchst du nicht. Nimm den Timer.
@ Frank M. (frank_m35)
>Du hast es implementiert wie dir empfohlen wurde,
Nö. Wo wurde empfohlen, die LCD-Ausgabe in der ISR zu machen?
> nur leider hat's eben>nicht funktioniert, da das Problem eben weniger das Display und mehr die>Textzusammensetzung ist.
Nö, er macht grundlegend was falsch.
> Du kannst dein Programm weiter aufbohren indem>du case 37 in einzelne cases aufteilst, sodass die Timerroutine>schneller ausgeführt wird. Ebenso auf floats verzichtest um die>Zahlenumwandlung in Text beschleunigst, da selbst wenn du sprintf selbst>implementiert hast, es immer noch deutlich langsamer ist als wenn du>Integer in Text, mit einer sogenannten uitoa Routine, umwandeln würdest.
Rumdoktern an den Symtomen. Die Ursache ist was ganz anderes.
Beitrag "Re: LCD zu langsam"
"Also: nicht nach jedem Schritt die aktuelle Schrittnummer ans LCD
geben,
sondern einen Timer aufsetzen, der 3 oder 4 mal in der Sekunde sich die
momentan gerade aktuelle Schrittnummer holt und ans LCD weitergibt.
In der Praxis macht man das so, dass man sich mit dem Timer ein Job-Flag
bedient, welches 3 oder 4 oder 5 mal in der Sekunde auf TRUE geht und
nur dann wenn dieses Flag auf TRUE ist, gibt die Schrittroutine
zwischendurch noch schnell mal die aktuelle Schrittzahl aufs LCD aus und
setzt das Flag wieder zurück.
"
Ok, der zweite Absatz ist wegen Betriebsblindheit unvollständig. Müsste
heißen
In der Praxis macht man das so, dass man sich mit der Timer ISR ein
Job-Flag bedient, welches 3 oder 4 oder 5 mal in der Sekunde auf TRUE
geht und nur dann wenn dieses Flag auf TRUE ist, gibt die Schrittroutine
in der Hauptschleife zwischendurch noch schnell mal die aktuelle
Schrittzahl aufs LCD aus und setzt das Flag wieder zurück.
Sascha Weber schrieb:> eben das diese Timer-ISR immer ausgeführt wird egal was sonst gerade so> läuft.Schorsch schrieb:> Vielen Dank, ich werds morgen mal probieren
Glaubt einfach dem Mann. Es wird funktionieren!
Mein ähnliches Projekt funktioniert auf diese Weise einwandfrei, obwohl
die LCD-Ausgabe (240x64 im Graphikmodul) 10ms! dauert.
Vielen Erfolg
Tany
@ Frank M. (frank_m35)
>>>Du hast es implementiert wie dir empfohlen wurde,>> Nö. Wo wurde empfohlen, die LCD-Ausgabe in der ISR zu machen?>Beitrag "Re: LCD zu langsam">Beitrag "Re: LCD zu langsam"
Naja, klassisches Missverständnis. Von endlosen sprintf Brocken, Float
und Stringoperationen in einem Stück auf das LCD ist dort keine Sekunde
die Rede. Aber so komplex muss man es gar nicht machen.
Noch ein Tip. Man muss auf die 32 Bit Werte für x, y, und z atomar
zugreifen, sonst gitb es komische Effekte, siehe Interrupt. Ich hab
es mal grob umgestellt, neudeutsch refactoring. Siehe Anhang.
Bin auch kein Rheinländler sondern Ruhrpottler, aber Deine Übersetzung
ist korrekt.
Habe eine eigene Version geschrieben, werde aber noch Deine Vorschläge
mit Umsetzen. 100µs reichten übrigens nicht aus, 40µs schon. Hab die
Pulse jetzt sogar auf 10kHz raufgedreht, habe 1 Million Pulse drüber
gejagt, keiner ist verloren gegangen. Echt super. Wenn ich den Code
aufgeräumt habe, werde ich ihn hier noch posten.
Georg
Schorsch schrieb:> die LCD Ausgabe in den Interrupt war ein Vorschlag aus diesem Thread von> Karl Heinz Buchegger (kbuchegg) (Moderator), habe ich ihn möglicherweise> falsch verstanden?
Sorry.
Hab den Thread nicht mehr weiter verfolgt.
Ja, hast du.
Von einem sprintf oder sonstigen Dingen in der ISR hab ich nicht das
Geringste gesagt. Mein Vorschlag zielte darauf hinaus, lediglich EINE
Aktion mit dem LCD pro Interrupt Aufruf zu machen und das ganze so zu
gestalten, dass dadurch laufend das LCD refreshed wird, ohne auf die
Abarbeitung des Befehls vom LCD zu warten.
War wohl zu unorthodox für dich.
Aber davon, dass in der ISR Zahlen-Ausgaben aufbereitet werden, davon
war zu keinem Zeitpunkt die Rede.
Aber in der Zwischenzeit wurde das System ja ohnehin umgedreht und die
Flankenabfrage in den Interrupt gelegt - was ja auch ok ist.
(Nur für die nächsten, die diesen Thread entdecken)
Frank M. schrieb:> Du hast es implementiert wie dir empfohlen wurde
Nö, hat er nicht.
Von
xVALmm = xVAL/stepsPerMmX;
xVALmmm = abs(xVAL*100/stepsPerMmX - xVALmm*100);
//sprintf(display[1],"X: %3.d.%02dmm",xVALmm,xVALmmm);
sprintf(writeOut,"%4d",xVALmm);
strncpy(&display[1][5],writeOut,4);
sprintf(writeOut,"%-2d",xVALmmm);
strncpy(&display[1][10],writeOut,2);
innerhalb der ISR war überhaupt nie die Rede.
Und was er da mit seiner currentDIsplay aufgeführt hat, geht auch auf
keine Kuhhaut. Dabei hab ich so drauf geachtet, dass in der Vorlage
keine Verzögerungen entstehen ausser dem unvermeidlichen Warten zwischen
der Ausgabe der beiden Nibbles im 4 Bit Modus. Und selbst das könnte man
noch abstellen.
> nur leider hat's eben> nicht funktioniert
Ja, weil er wieder mal sein eigenes Süppchen gekocht hat.
> da das Problem eben weniger das Display und mehr die> Textzusammensetzung ist. Du kannst dein Programm weiter aufbohren indem> du case 37 in einzelne cases aufteilst, sodass die Timerroutine> schneller ausgeführt wird.
Quatsch. Er braucht es nur richtig machen.
Pro ISR Aufruf EINE Übertragung aufs LCD und anstelle auf den Vollzug zu
warten sofort wieder raus aus der ISR.
Nur muss man das ganze so organisieren, dass das auch tatsächlich genau
so läuft. Dann läuft das Schaufeln der Daten ans LCD nebenher und
verbraucht 0.001% Rechenzeit.
Ist also dieselbe Kategorie wie die PeDa Entprellung. Das läuft alles
nebenher und irgendwie 'magisch' kann ich mir aus Speicherstellen die
Tastenwerte abholen. Hier ist es halt umgekehrt: Ich schreibe das
auszugebende in den Speicher und irgendwie 'magisch' landet die Ausgabe
auf dem LCD. Nicht sofort, sondern mit ein paar ms Verzögerung. Aber das
macht ja nichts. So schnell kann eh keiner lesen.
@ Karl Heinz Buchegger (kbuchegg) (Moderator)
>Hab den Thread nicht mehr weiter verfolgt.
Dich wollte ich eigentlich nicht triggern ;-)
>Von einem sprintf oder sonstigen Dingen in der ISR hab ich nicht das>Geringste gesagt.
Direkt nicht, aber man konnte die missverstehen.
Beitrag "Re: LCD zu langsam"> Mein Vorschlag zielte darauf hinaus, lediglich EINE>Aktion mit dem LCD pro Interrupt Aufruf zu machen und das ganze so zu>gestalten, dass dadurch laufend das LCD refreshed wird, ohne auf die>Abarbeitung des Befehls vom LCD zu warten.
Ist sicher eine elegante Methode, aber schon um einiges aufwändiger. Der
einfachste und dennoch sichere UND schnelle Weg ist, die Ausgabe ganz
lehrbuchartig in die Hauptschleife zu legen und per ISR auszulösen. Das
hat der OP aber nun verstanden.
Falk Brunner schrieb:> Ist sicher eine elegante Methode, aber schon um einiges aufwändiger.
Zweifellos.
Die Absicht war, wenn ich mich recht erinnere, die Flankenauswertung in
der Hauptschleife belassen zu können und nur die eigentliche Ausgabe zu
verlangsamen.
> Der> einfachste und dennoch sichere UND schnelle Weg ist, die Ausgabe ganz> lehrbuchartig in die Hauptschleife zu legen und per ISR auszulösen.
Ist im Nachhinein gesehn die bessere und vor allen Dingen die für ihn
naheliegendere Lösung. Ich glaub, das hat er nicht wirklich kapiert, wie
das gedacht war. Das löst dann auch gleich das Problem, dass er nur dann
sprintf's macht, wenn Zeit ist und nicht nach jedem Puls. Das hatte
nämlich ich wiederrum nicht bedacht (aber ich hätte nicht damit
gerechnet, dass er die Rechnerei in die ISR rein stellt - da geht mir
die Hutschnur hoch)
Ich finde, das ist sehr lebensnah programmiert. So eine
Interruptbehandlung im Alltag kann schon mal viel viel aufwändiger sein
als die Tätigkeit, an der man eigentlich gerade saß. Vielleicht hatte
Schorsch ja so einen Tag. In Code gegossen ist das schon mindestens ein
sprintf() außer der Reihe wert.
SCNR
Beim Lesen dieses Forums haben sich zwei Fragen aufgedrängt:
1. Kennt irgendjemand ein CNC-Dingsbums, das irgendwas mit
Fließkommazahlen anfangen kann? Die mir bekannten Geräte konnten
einen Schritt machen oder es sein lassen, aber keine 0,xxx Schritte.
Oder anders gefragt, wozu wird überhaupt umgerechnet.
P.S. Ich habe auch schon von Mikroschritten gehört. Diese waren
aber immer 1/2, 1/4, 1/8 oder 1/16. Wer glaubt, mechanisch
belastbar auch 1/256 Schritt fahren zu können, nun der soll es
tun.
2. Die Ausgabe: Wenn ich von maximal 3 gleichzeitig veränderbaren
Koordinaten ausgehe, eine Irrsinnsdarstellung von 99 Metern mit
1/1000 mm Auflösung postuliere, also 99999,999 maximal, so komme
ich auf folgende Aktivitäten:
3 x setze Position
3 x Ausgabe 9 Zeichen (immer um den Hintergrund sauber zu halten)
Und diese Aktivität soll nicht noch so nebenbei ablaufen können? Vor
allem bei vom Auge lesbarer Geschwindigkeit?
@ amateur (Gast)
> Oder anders gefragt, wozu wird überhaupt umgerechnet.
Um die Schritte in mm umzurechnen.
>2. Die Ausgabe: Wenn ich von maximal 3 gleichzeitig veränderbaren> Koordinaten ausgehe, eine Irrsinnsdarstellung von 99 Metern mit> 1/1000 mm Auflösung postuliere, also 99999,999 maximal, so komme> ich auf folgende Aktivitäten:> 3 x setze Position> 3 x Ausgabe 9 Zeichen (immer um den Hintergrund sauber zu halten)
Du hast die Umrechung vergessen. Ausserdem müssen erstmal die Zahlen in
Strings gewandelt werden, kan man unter Ausgabe einordnen.
>Und diese Aktivität soll nicht noch so nebenbei ablaufen können?
Doch, wenn man es richtig macht (tm).
Beitrag "Re: LCD zu langsam"
amateur schrieb:> Und diese Aktivität soll nicht noch so nebenbei ablaufen können? Vor> allem bei vom Auge lesbarer Geschwindigkeit?
Genau den Punkt hast du ausser acht gelassen.
Wenn man nämlich so wies Schorsch nach JEDEM Puls erneut ausrechnet, wo
die Achse gerade in Millimeter ausgedrückt steht, dann kommt man da
nicht mehr hinterher.
(und wenn man das dann auch noch auf Biegen und Brechen 1000 mal in der
Sekunde macht, dann kommt man erst recht nicht hinterher)
>Um die Schritte in mm umzurechnen.
Eine Ganzzahl zu Multiplizieren, in einen String umzuwandeln und ev.
manuell einen Punkt oder Komma zu setzen, ist auch etwas ganz anderes
als das ganze Fließkommapaket anzuwerfen.
>(und wenn man das dann auch noch auf Biegen und Brechen 1000 mal in der>Sekunde macht, dann kommt man erst recht nicht hinterher)
Da muss ich Dir leider zustimmen.
Ich habe bei rechenintensiven Sachen immer die Angewohnheit die Axt zu
holen und den Kram in handliche Teile zu zerlegen. Oft erübrigt sich
dann auch die ganze Warterei.
@ amateur (Gast)
>>Um die Schritte in mm umzurechnen.>Eine Ganzzahl zu Multiplizieren, in einen String umzuwandeln und ev.>manuell einen Punkt oder Komma zu setzen, ist auch etwas ganz anderes>als das ganze Fließkommapaket anzuwerfen.
Mir musst du das nicht erzählen, ich weiß wie Festkommaarithmetik
funktioniert ;-)
>Ich habe bei rechenintensiven Sachen immer die Angewohnheit die Axt zu>holen und den Kram in handliche Teile zu zerlegen. Oft erübrigt sich>dann auch die ganze Warterei.
Wenn man das Grundproblem und auch die Lösung kennt, ist das immer
einfach. Aber Multitasking ist Anfängern eher ein Fremdwort,
zumindest in der Umsetzung.