Forum: Mikrocontroller und Digitale Elektronik LCD zu langsam


von Schorsch (Gast)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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.

von Schorsch (Gast)


Lesenswert?

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

von spess53 (Gast)


Lesenswert?

Hi

Wofür sind deine Delays? Und was ist 'SPI-magic'.

MfG Spess

von маленький шумный зомби (Gast)


Lesenswert?

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.

von Hustinetten-Baer (Gast)


Lesenswert?

Dann mach' halt die Delays auch per Timer und nicht per Bremsschleife.

von Karl H. (kbuchegg)


Lesenswert?

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 :-)

von Schorsch (Gast)


Lesenswert?

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

von Karl H. (kbuchegg)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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.

von Karl H. (kbuchegg)


Lesenswert?

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.

von Schorsch (Gast)


Lesenswert?

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_t newPORTC = PINC;
2
    if ( (newPORTC ^ lastPORTC) & 0x02 && (newPORTC & 0x02) ) {
3
      if (newPORTC & 0x01 )  xVAL--; else xVAL++; 
4
      changed |= 0x01;
5
    }
6
    if ( (newPORTC ^ lastPORTC) & 0x08 && (newPORTC & 0x08) ) {
7
      if (newPORTC & 0x04 )  yVAL--; else yVAL++; 
8
      changed |= 0x02;
9
    }
10
    if ( (newPORTC ^ lastPORTC) & 0x20 && (newPORTC & 0x20 ) ) {
11
      if (newPORTC & 0x10 ) zVAL--; else zVAL++; 
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):
1
void update_lcd(const uint8_t c) {
2
  char out[16];
3
4
  switch (c) {
5
  case 1: //update x-axis
6
     set_cursor(5,2);
7
           sprintf(out,"%8.2fmm",(float)xVAL/stepsPerMmX+frameX[frame]);
8
           lcd_string(out);
9
     break;
10
  case 2: //update y-axis
11
     set_cursor(5,3);
12
     sprintf(out,"%8.2fmm",(float)yVAL/stepsPerMmY+frameY[frame]);
13
     lcd_string(out);
14
     break;
15
     case 3: //update Z-axis
16
     set_cursor(5,4);
17
     sprintf(out,"%8.2fmm",(float)zVAL/stepsPerMmZ+frameZ[frame]);
18
     lcd_string(out);
19
     break;
20
     case 4: //update Frame
21
        set_cursor(13,1);
22
     sprintf(out,"G%d",frame+54);
23
     lcd_string(out);
24
  }
25
  
26
}

die lcd_string() methode looped halt über alle chars:
1
void lcd_string(char *data)
2
{
3
    while(*data) {
4
        lcd_data(*data);
5
        data++;
6
    }
7
}

Hier hatte ich überlegt anstelle des loops alles in einen FIFO zu 
packen, der durch den timer entleert wird

Schorsc

von Falk B. (falk)


Lesenswert?

@  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.

von Karl H. (kbuchegg)


Lesenswert?

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.

von Schorsch (Gast)


Lesenswert?

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

von Falk B. (falk)


Lesenswert?

@  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.

von маленький шумный зомби (Gast)


Lesenswert?

Vielleicht mit einem Timer von 10kHz ? macht dann alle 100us etwas 
schreiben.

von Stefan (Gast)


Lesenswert?

Lies Dich mal in das Thema "State Machine" bzw. "Zustandsautomat" ein. 
Ich denke, das dies eine elegante Lösung ist.

von Frank M. (frank_m35)


Lesenswert?

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?

von Karl H. (kbuchegg)


Lesenswert?

Schorsch schrieb:

> Wie würds Du es machen?

Ich denke, ich würde das so machen
(Skizze)
1
#define NR_LINES     2
2
#define NR_COLUMNS  16
3
4
// Speicherabbild des LCD
5
char lcDisplay[NR_LINES][NR_COLUMNS];
6
7
ISR( .... )   // Timer ISR, Aufruffrequenz so gewählt, dass sich
8
              // eine gute Refreshrate ergibt, ohne exzessiv Zeit
9
              // zu verlieren
10
{
11
  static int8_t actLine = 0;
12
  static int8_t actColumn = -1;
13
14
  if( actColumn == -1 ) {
15
    lcd_gotoxyWithouWait( 0, actLine );
16
    actColumn = 0;
17
  }
18
19
  else {
20
    lcdDataWithoutWait( lcDisplay[actLine][actColumn] );
21
22
    actColumn++;
23
    if( actColumn == NR_COLUMNS ) {
24
      actColumn = -1;
25
      actLine++;
26
      if( actLine == NR_LINES ) {
27
        actLine == 0;
28
      }
29
    }
30
  }
31
}

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.

von Karl H. (kbuchegg)


Lesenswert?

>      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.

von Falk B. (falk)


Lesenswert?

@  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.

von Teo D. (teoderix)


Lesenswert?

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.

von Schorsch (Gast)


Lesenswert?

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:
1
sprintf(display[1],"X:  %3.d.%02dmm",xVALmm,xVALmmm);
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

von Falk B. (falk)


Lesenswert?

@  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.

von Frank M. (frank_m35)


Lesenswert?

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.

von Schorsch (Gast)


Angehängte Dateien:

Lesenswert?

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

von Falk B. (falk)


Angehängte Dateien:

Lesenswert?

@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

von Schorsch (Gast)


Lesenswert?

Addendum:

Um meine Testsignale zu erzeugen habe ich einen weiteren Atmega 
angeschlossen. Das ist der ganze Quellcode:
1
#include <avr/io.h>
2
#include <avr/delay.h>
3
4
int main(void)
5
{
6
    uint16_t count = 0;
7
    DDRD=0xff;
8
    for(;;){
9
      PORTD = 0x01;
10
      _delay_us(100);
11
      PORTD = 0x00;
12
      _delay_us(100);
13
      count++;
14
      if (count >= 10000) {
15
        count = 0;
16
        _delay_ms(5000);  
17
      }
18
    }
19
    return 0;   /* never reached */
20
}

Habe mit einem Logic Analyser nachgewiesen, dass eine Peridode 
tatsächlich ca. 5kHz hat

von Falk B. (falk)


Lesenswert?

@  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.

von Lötlackl *. (pappnase) Benutzerseite


Lesenswert?

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
1
#ifndef F_CPU
2
    #error F_CPU nicht definiert!
3
#endif
 auf die finger hauen.

mfg

von Schorsch (Gast)


Lesenswert?

@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

von Frank M. (frank_m35)


Lesenswert?

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.

von Sascha W. (sascha-w)


Lesenswert?

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_t newPORTC = PINC;
2
uint8_t change = (newPORTC ^ lastPORTC) & 0x2A;
3
  if (change==0) return;  //Eingänge unverändert
4
  if (change & 0x02) {
5
      if (newPORTC & 0x01 )  xVAL--; else xVAL++; 
6
  }
7
  if (change & 0x08) {
8
      if (newPORTC & 0x04 )  yVAL--; else yVAL++; 
9
  }
10
  if (change & 0x20) {
11
      if (newPORTC & 0x10 ) zVAL--; else zVAL++; 
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

von Falk B. (falk)


Lesenswert?

@  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.

von Falk B. (falk)


Lesenswert?

@  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.

von Falk B. (falk)


Lesenswert?

>Achso ich maximale Signalfrequenz sollte kleiner als 3.5 kHz sein

Macht 300us. Dann reicht ein 100us/10kHz Timer Interrutp.

von Frank M. (frank_m35)


Lesenswert?

Falk Brunner schrieb:
> @  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"

von Schorsch (Gast)


Lesenswert?

@Sasha et al:

Vielen Dank, ich werds morgen mal probieren, ihr habt recht, wenn man es 
umdreht sollte es klappen

Schorsch

von Tany (Gast)


Lesenswert?

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

von Falk B. (falk)


Lesenswert?

@  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.

von Falk B. (falk)


Angehängte Dateien:

Lesenswert?

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.

von Schorsch (Gast)


Lesenswert?

it yütt :-p

vielen Dank an alle

von Falk B. (falk)


Lesenswert?

@  Schorsch (Gast)

>it yütt :-p

Und für nicht Rheinländer? Es geht?

Welche Version? Meine oder deine?

von Schorsch (Gast)


Lesenswert?

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

von Falk B. (falk)


Lesenswert?

LCD immer noch langsam?

von Karl H. (kbuchegg)


Lesenswert?

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)

von Karl H. (kbuchegg)


Lesenswert?

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.

von Peter D. (peda)


Lesenswert?


von Falk B. (falk)


Lesenswert?

@  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.

von Karl H. (kbuchegg)


Lesenswert?

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)

von Malte S. (maltest)


Lesenswert?

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

von amateur (Gast)


Lesenswert?

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?

von Falk B. (falk)


Lesenswert?

@  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"

von Karl H. (kbuchegg)


Lesenswert?

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)

von amateur (Gast)


Lesenswert?

>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.

von Falk B. (falk)


Lesenswert?

@  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.

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.