Schrittmotortreiber mit dem L6208 – Mit Vollschritt voraus

Mittlerweile arbeitet das neue GREETBoard ATMega128 sehr zufriedenstellend, sodass es Zeit wurde den liegengebliebenen L6208 Schrittmotor Treiber aufzubauen und zu testen. Bereits in drei kurzen Artikeln habe ich über die Entstehung des GREETBoard L6208 berichtet. Im Ersten stellte ich den Schaltplan vor und habe diesen im Zweiten auf einer Lochrasterplatine aufgebaut um im dritten eingestehen zu müssen, dass ich zu blöd war, die Lochrasterplatine zu erstellen. 😉

Jetzt läuft der Motor!

Die Auswahl des L6208

shopbutton

Ganz zu Anfang hatte ich die Idee, dass im GREETBoard-Projekt nicht nur LEDs blinken sollten. Diese dienen nur der Simulation von Aktoren; viel besser wäre es aber einen Motor direkt anzusteuern. Warum es aber ausgerechnet ein Schrittmotor für den ersten Motortreiber sein musste weiß ich auch nicht. Die Idee stand sofort fest während ich darüber nachdachte.

Die bekannteste Schaltung ist wohl die Kombination aus L297/L298 und so begann ich einen Schaltplan auf Basis dieser beiden ICs zu erstellen. Tatsächlich ist daraus eine Leiterplatte entstanden, die jedoch nie geätzt wurde. Mitten in der Konstruktion habe ich nämlich vom L6208 Wind bekommen. Dieser hat in meinen Augen zwei wesentliche Vorteile; zum Einen wird pro Motor nur ein IC benötigt und zum Anderen ist der L6208 in der Lage Schrittmotoren mit Mikroschritten anzutreiben. Schnell stand fest, dass es dieser Baustein sein wird der meine Schrittmotoren antreiben soll.

Die Schaltung

Der Vollständigkeit halber möchte ich an dieser Stelle zum dritten Mal den Schaltplan zeigen. Er ist seit dem ersten Artikel unverändert. Die einzelnen Bauteile und die Auswahl ihrer Werte habe ich ebenfalls im ersten Artikel beschrieben, daher werde ich hier nicht darauf eingehen.

Schaltung des L6208-Boards

Schaltung des L6208-Boards

Diese Schaltung vereint die drei Schrittarten (Voll- Halb- und Mikroschritt) auf einer Leiterplatte. Mittels drei Jumper ist es möglich zwischen den Betriebsarten zu wechseln.

Jumpereinstellungen der verschiedenen Schrittarten

Jumpereinstellungen der verschiedenen Schrittarten

Die Leiterplatte ist zweiseitig konstruiert. Dabei sind Logik-GND auf der Bestückungsseite und Motor-GND auf der Lötseite als Flächen ausgeführt. Nur an einer definierten Stelle sind die beiden Flächen durch eine Brücke miteinander verbunden. Diese Stelle soll sich, laut Datenblatt, so dicht wie möglich am großen Elko befinden und nicht in der Nähe der Sensing-Widerstände um Störungen in der Logik zu vermeiden.

L6208 - Layout der Leiterplatte

L6208 – Layout der Leiterplatte

Auf der roten Seite, der Bestückungsseite, ist auch der Umriss des Kühlkörpers zu erkennen. Dieser passt ganz hervorragend auf die Platine, sodass links und rechts genügend Platz für die Abstandhalter ist. Er lässt außerdem noch genügend Platz, um die Kontakte für die Logik, Spannungsversorgung und Motoranschlüsse unterzubringen. Hier aber ein Bild ohne Kühlkörper.

L6208 - Ohne Kühlkörper

L6208 – Ohne Kühlkörper

L6208 - Die fertige Testplatine

L6208 – Die fertige Testplatine

 

Der Test

Ganz bewusst habe ich bei der Planung keine Wannenstecker vorgesehen, um bei der Verdrahtung flexibel sein zu können. Daher wurde auf das GREETBoard ATMega128 die passende Erweiterung, das GREETBoard ATMega128 Extension, aufgesteckt. Auf diesem werden die Ports des Mikrocontrollers über Klemmkontakte zur Verfügung gestellt.

GREETBoard ATMega128 - Huckepackbetrieb

GREETBoard ATMega128 – Huckepackbetrieb

Auf der Logikseite der L6208 Platine sind Schraubklemmen für die Signale Reset, Clock, CW/CCW, Enable, PWM_A und PWM_B vorgesehen. Für den ersten Test werden aber nicht alle benötigt, damit der Motor in Bewegung gesetzt werden kann.

Reset wird bereits über einen 10k-Pull Up Widerstand auf High gezogen. Damit ist der Reset grundsätzlich nicht gesetzt und ein Signal wird nur benötigt um diesen auszulösen. Für den Test braucht es hier kein Signal. Notwendig sind jedoch Signale für Clock, CW/CCW und Enable. Daher werden hier drei Signalleitungen vom Mikrocontroller benötigt. Die PWM-Eingänge sind nur für den Mikroschrittantrieb nötig. Da der Test im Vollschrittbetrieb durchgeführt wird, werden auch diese nicht verwendet.

Unter dem Strich werden also lediglich fünf Leitungen benötigt: GND, VCC, Clock, CW/CCW und Enable.

L6208 - Anschluss der Logik für Vollschritte

L6208 – Anschluss der Logik für Vollschritte

Auf der Leistungsseite wiederum werden sich die Anschlüsse auch für die kommenden Tests nicht verändern. Zum Einen wird der Motor an den vier Klemmen in der richtigen Reihenfolge angeschlossen und zum Anderen benötigt die L6208 Platine noch die Spannungsversorgung für den Motor, die bis zu 52V betragen darf. Hierfür nutze ich eine externe Spannungsquelle (24V / 2,5A / 60W).

L6208 - Motorseitige Anschlüsse

L6208 – Motorseitige Anschlüsse

Das Programm

Damit der Motor läuft, benötigt die Schaltung einen Takt am Eingang Clock. Mit jedem Impuls wird der Motor einen Schritt weiterlaufen. Zusätzlich muss Enabled auf High geschaltet werden, damit die Motorspulen mit Strom versorgt werden. Damit der Motor im Uhrzeigersinn (CW = clock wise/ CCW = Counter clock wise) dreht ist an der Klemme CW/CCW ein High-Signal anzulegen. Zusätzlich möchte ich die Anzahl der Schritte auf dem LCD Display ausgeben.

Das Programm beginnt mit dem üblichen Kopf der Definitionen, Header-Dateien und Variablen. tcount zählt die Interrupts, die durch den 8-Bit Timer0 ausgelöst werden. x ist für den Zustand des Clock-Signals zuständig und loops zählt die Signale, die an den L6208 gesendet werden.

#ifndef F_CPU
  #define F_CPU 16000000
#endif

#include <avr/io.h>             // Header-Datei f. IO-Register
#include <avr/interrupt.h>      // Header-Datei f. Interruptfunktion
#include <stdint.h>             // Header-Datei f. Standard-Datentypen
#include "i2clcd.h"             // Header-Datei f. I2CLCD

volatile uint8_t tcount;        // Globale Variable (volatile)
uint8_t x;                      // Lokale Variable zum Schalten von PD0
int loops = 0;                  // Zähler

Die Subroutine init_timer startet den Timer0 mit einem Teiler von 64.

(Taktfrequenz / TEILER) / 256 = Frequenz
1 / Frequenz = Zeit

In diesem Fall also:
(16.000.000 / 64) / 256 = 976,5625 Hz
1 / 976,5625 = 0,001024 Sekunden = 1,024 Millisekunden

TIMSK schaltet den Interrupt beim Überlaufen (Wert >255) ein.

void init_timer (void){
  TCCR0B = (1<<CS01)|(1<<CS00); // Prescaler 64 (1,024ms)
  TIMSK0 |= (1<<TOIE0);         // Overflow Interrupt erlauben
}

Der Mikrocontroller muss einige Signale ausgeben, sodass ausschliesslich Ausgänge initialisiert werden müssen. Da sich alle am Port D befinden, können die einzelnen Pins (PD0, PD1, PD2) auf einmal definiert werden.

void init_IO (void){
  DDRD = (1 << DDD0)|(1 << DDD1)|(1 << DDD2);           
  // Outputs:
  // PortD0 - Clock
  // PortD1 - CW/CCW
  // PortD2 - Enable
}

Für die Funktion ist die folgende Subroutine nicht wichtig. Sie dient lediglich dafür, dass auf dem LCD-Display eine Art Begrüßungstext erscheint und auch wieder verschwindet.

void start_text (void) {
  lcd_command(LCD_CLEAR);       // LCD-Anzeige löschen
  lcd_printlc(1,1,(unsigned char *)"GREETBoard");
  lcd_printlc(2,1,(unsigned char *)"       ATMega128");
  lcd_wait_ms(2000);            // Text 2s stehen lassen
  lcd_command(LCD_CLEAR);       // Display löschen
  lcd_printlc(1,1,(unsigned char *)"L6208 Treiber");
  lcd_printlc(2,1,(unsigned char *)"Vollschritte");
  lcd_wait_ms(2000);            // Text 2s stehen lassen
  lcd_command(LCD_CLEAR);       // Display löschen
  lcd_printlc(1,1,(unsigned char *)"Schritte:");
}

Die Interrupt Service Routine (ISR) wird ausgeführt, sobald der Timer „überläuft“ (Wert >255) und damit ein Timer Interrupt auslöst. Da eine ISR so kurz wie möglich gehalten werden soll, wird hier nur die Variable tcount um eins erhöht. Die weitere Verarbeitung von tcount erfolgt in der While-Schleife .

ISR (TIMER0_OVF_vect){
  tcount++;                     // tcount +1 pro Interrupt
}

Zu Beginn des Hauptprogramms wird der Timer gestartet und die Ausgänge initiiert. Im Anschluss wird der Clock-Zustand auf 0 gesetzt (Clock-Signal = Low) und die Variable s für die Ausgabe von loops am LCD Display definiert. Nach der Aktivierung der Interrupts (sei();) wird der I²C-Bus und das LCD-Display gestartet um daraufhin den Begrüßungstext anzuzeigen. Schlussendlich werden PD1 (CW/CCW: Drehung im Uhrzeigersinn) und PD2 (Enabled) auf High gesetzt.

int main(void){
  init_timer();                 // Start des Timers
  init_IO();                    // Ausgänge definieren

  x = 0;                        // Flag für Clock-Zustand (0/1)
  char s[10];                   // Variable für loops Ausgabe 

  sei();                        // Global Interrupts aktivieren
  i2c_init();                   // I2C initialisieren
  lcd_init();                   // LCD initialisieren
  start_text();                 // Den "Begrüßungstext" anzeigen

  PORTD |= (1<<PD2);            // ...aktiviere Port D2 (ENABLE)
  PORTD |= (1<<PD1);            // ...aktiviere Port D1 (CW)

In der While-Schleife wird ca. alle 3 Millisekunden (3 x 1,024ms) kontrolliert, ob sich das Clock-Signal im Low- (x == 0) oder im High-Zustand (x == 1) befinden sollte.

Sollte es Low sein, dann wird ein Schritt hochgezählt. Anschließend wird PD0 deaktiviert und die Schrittanzahl angezeigt. x wird auf eins gesetzt, da im nächsten Durchlauf das Clock-Signal High sein soll. Ist x == 1, dann wird PD0 auf High gesetzt. Um im nächsten Durchlauf das Clock-Signal wieder auszuschalten, wird x auf 0 gesetzt. Am Ende jedes Durchlaufs wird die Variable tcount auf 0 zurückgesetzt um wieder bis tcount > 3 hochzählen zu können.

Mit diesem Programmteil wechselt PD0, also das Clock-Signal, alle 3 Millisekunden zwischen Low und High

while(1){
    if ( tcount >= 3 ) {         // 3*1,024ms Warten
      if ( x == 0 ) {           // Wenn x gleich 0 ist
        loops++;                // loops +1
        itoa(loops, s, 10);     // loops in Text umwandeln
	PORTD &= ~( (1<<PD0));  // Deaktiviere Port D0
	lcd_printlc(2,1,(unsigned char *)s); //Anzahl der loops anzeigen
        x = 1;                  // Setze X auf 1
      }
      else {                    // Ansonsten
        PORTD |= (1<<PD0);      // aktiviere Port D0
        x = 0;                  // Setze X auf 0
      }
      tcount = 0;              // Zähler wieder auf 0 setzen
    }
  }
}

Der Motor bewegt sich

Der Motor ist sicherlich noch weit entfernt von einer perfekten Einstellung. Es ist zu erkennen, dass der Lauf noch ein bisschen ruckelig ist. Dennoch ist der Test hervorragend gelaufen und das Ziel, ein laufender Schrittmotor, wurde erreicht. Wichtig ist an dieser Stelle aber auch, dass der L6208 ohne Kühlkörper recht schnell sehr warm wird. Daher habe ich den L6208 mit Wärmeleitpaste bestrichen und den Kühlkörper aufgeschraubt. Eine Erwärmung kann ich am Kühlkörper (direkt oberhalb des IC) nicht bemerken.

Sollte das Video zu klein sein, dann stellt es auf eine höhere Auslösung (auch gerne 720p) und schaut es auch im Vollbildmodus an.

Als nächstes stehen noch weitere Tests an, wie z.B. die richtige VRef- Einstellung, der Halbschrittmodus und eine Veränderung der Geschwindigkeit während des Laufs. Und bevor ich mich an den Mikroschritt-Betrieb wage, muss ich noch das Thema PWM-Signale erschließen. Es bleibt also weiter spannend 🙂

  • Update 22.08.2013: Da ich mich gegen den Mikroschrittbetrieb mit dem L6208 zu realisieren, arbeite ich momentan an einem weiteren Schrittmotorprojekt mit dem Allegro A3979. Vielleicht ist dies auch interessant? Dann geht es hier zum ersten Artikel über den Schaltplan des A3979-Moduls.
  • Update 20.12.2013: Das Modul „GREETBoard – Stepper L6208“ findet ihr ab jetzt auch in meinem Onlineshop
  • Update 11.12.2013: Mittlerweile gibt es die fertige Version 1.0 des GREETBoard – Stepper L6208

Wie immer gilt, dass ich mich über eure Kommentare freue – positive und negative!

Im Anschluss habe ich das gesamte Programm zum Kopieren bereitgestellt:

/*
 * L6208_01.c
 *
 * Created: 05.05.2013
 * Author: Timo Gruß (timogruss.de)
 *
 * Dies ist das erste Testprogramm für das L6208 Modul. Der Schrittmotor
 * soll sich in Uhrzeiterrichtung drehen.
 */ 

#ifndef F_CPU
  #define F_CPU 16000000
#endif

#include <avr/io.h>             // Header-Datei f. IO-Register
#include <avr/interrupt.h>      // Header-Datei f. Interruptfunktion
#include <stdint.h>             // Header-Datei f. Standard-Datentypen
#include "i2clcd.h"             // Header-Datei f. I2CLCD

volatile uint8_t tcount;        // Globale Variable (volatile)
uint8_t x;                      // Lokale Variable zum Schalten von PD0
int loops = 0;                  // Zähler

void init_timer (void){
  TCCR0B = (1<<CS01)|(1<<CS00); // Prescaler 64 (1,024ms)
  TIMSK0 |= (1<<TOIE0);         // Overflow Interrupt erlauben
}

void init_IO (void){
  DDRD = (1 << DDD0)|(1 << DDD1)|(1 << DDD2)|(1 << DDD5);           
  // Outputs:
  // PortD0 - Clock
  // PortD1 - CW/CCW
  // PortD2 - Enable
  // PortD5 - LED
}

ISR (TIMER0_OVF_vect){
  tcount++;                     // tcount +1 pro Interrupt
}

void start_text (void) {
  lcd_command(LCD_CLEAR);       // LCD-Anzeige löschen
  lcd_printlc(1,1,(unsigned char *)"GREETBoard");
  lcd_printlc(2,1,(unsigned char *)"       ATMega128");
  lcd_wait_ms(2000);            // Text 2s stehen lassen
  lcd_command(LCD_CLEAR);       // Display löschen
  lcd_printlc(1,1,(unsigned char *)"L6208 Treiber");
  lcd_printlc(2,1,(unsigned char *)"Vollschritte");
  lcd_wait_ms(2000);            // Text 2s stehen lassen
  lcd_command(LCD_CLEAR);       // Display löschen
  lcd_printlc(1,1,(unsigned char *)"Schritte:");
}

int main(void){
  init_timer();                 // Start des Timers
  init_IO();                    // Ausgänge definieren

  x = 0;                        // Flag für Clock-Zustand (0/1)
  char s[10];                   // String-Variable für Ausgabe der 

  sei();                        // Global Interrupts aktivieren
  i2c_init();                   // I2C initialisieren
  lcd_init();                   // LCD initialisieren
  start_text();                 // Den "Begrüßungstext" anzeigen

  PORTD |= (1<<PD2);            // ...aktiviere Port D2 (ENABLE)
  PORTD |= (1<<PD1);            // ...aktiviere Port D1 (CW)

  while(1){
    if ( tcount >= 3 ) {         // 3*1,024ms Warten
      if ( x == 0 ) {           // Wenn x gleich 0 ist
        loops++;                // loops +1
        itoa(loops, s, 10);     // loops in Text umwandeln
	PORTD &= ~( (1<<PD0));  // Deaktiviere Port D0
	lcd_printlc(2,1,(unsigned char *)s); //Anzahl der loops anzeigen
        x = 1;                  // Setze X auf 1
      }
      else {                    // Ansonsten
        PORTD |= (1<<PD0);      // aktiviere Port D0
        x = 0;                  // Setze X auf 0
      }
      tcount = 0;              // Zähler wieder auf 0 setzen
    }
  }
}

7 Gedanken zu „Schrittmotortreiber mit dem L6208 – Mit Vollschritt voraus

  1. Tolles Projekt. Ich wünschte, mehr Entwickler würden die Zeit finden, ihre Erkenntnisse so lesbar darzustellen.

    Der Schrittmotortreiber ist sehr interessant für mich. Ich habe als Schüler (1983) eine kleine CNC-Fräse gebaut, die drei einfache Schrittmotoren einsetzt. Die eingesetzen Motoren (Berger Lahr RDM50) wurden unipolar mit Festspannung betrieben (24V über einen einfachen Kleinleistungstransistor mit Open-Kollector an 300 Ohm = 80mA). Wegen der vollständig herausgeführten Anschlüsse (8 Draht) könnte der Motor allerdings auch bipolar betrieben werden.

    Dreissig Jahre später habe ich das Projekt nun wieder aus dem Keller geholt. Weil die Motoren grenzwertig geringe Leistung liefern, möchte ich das Ganze etwas „aufbohren“, ohne die Mechanik zu ändern. Bipolare Ansteuerung ist der eine Faktor, mit dem ich „das Kupfer besser nutzen“ möchte. Ein andere Faktor ist die Betriebsspannung. Statt 24V möchte ich mit einer höheren Spannung „choppen“, um gegen die hohe Induktivität anzukämpfen. Hier ist mit vielen DIY-Schaltungen zu niedrig gegriffen (24-35V), aber mit 52V fühle ich mich besser, zumal bipolar ohnenhin nur sqrt(2) des Stroms angemessen sind.

    Wegen des geringen Stroms sind FETs eigentlich nicht nötig, aber ich tue mich schwer damit, eine andere Schaltung zu finden, die >=50V bipolar inkl. Stromregelung liefert.

    Mit der Kühlung hätte ich bei 50-80mA wohl kein Problem, aber die Frage ist, ob die Schaltung einen so geringen Strom „verkraftet“, d.h. immer noch sauber regelt?

    Andere Frage: Wird es die Platine irgendwann in Kleinauflage geben?

    1. Hallo Michael,
      Danke sehr für die netten Worte, das hat mich unheimlich gefreut!
      Der L6208 kann ja generell mit Spannungen bis 52V umgehen und über den Poti auf der Schaltung kann der Motorstrom bequem eingestellt werden. In meinem Beispiel hat der Motor einen Strom von 1A und das bedeutet, wenn ich mich recht erinnere, eine Referenzspannung von 0,25A. Für 80mA (0,08A) würde das eine Referenzspannung von 20mV bedeuten. Ob das geht weiß ich leider nicht. Und ob das mit dem Poti überhaupt einstellbar ist, muss ich zu Hause nachmessen. Dann sehe ich ja, ob der Motor vernünftig läuft. Ich schaue mal nach und melde mich dann mit dem Ergebnis, OK?

      Was deine zweite Frage angeht, habe ich tatsächlich Pläne hier eine kleine Auflage machen zu lassen. Ich habe die L6208 Seite im Blog aktualisiert, da siehst du die neue Version (ohne Mikroschritt-Elemente). Vielleicht ist die so immer noch interessant für dich?

      Alles Gute, Timo

  2. Hallo Timo,
    Danke für die schnelle Antwort. Ich schätze, dass man die Sense-Widerstände hochohmiger auslegen kann (z.B. 2,5 Ohm statt 0,25 Ohm). Das sollte dann zu einer höheren Referenzspannung führen. Der Spannungsabfall und die Verlustleistung sollten unkritisch sein; nach meiner Rechnung passt schon ein 1/8 Watt Widerstand.
    Momentan kommt meine Fräse mit Vollschritten aus, obwohl die Motoren nur rund 30 Schritte pro Umdrehung machen. Halbschritt habe ich schon probiert (zufriedenstellend), aber Mikroschritte bringen mir nichts, da die Motoren bei der typischen Ansteuerung zu nicht-linear reagieren, d.h. die Schritte sind sehr unterschiedlich gross und das Haltemoment (innerhalb des Vollschritts) ist gering.
    An der Platine wäre ich interessiert, aber ich würde wohl zunächst nur eine Achse ausrüsten, und mir die Performanz mal anschauen. Spannend ist, ob ich wirklich viel (genug) Drehmoment gewinne (gegenüber einer traditionellen Festspannung). Der Umstieg auf bipolaren Betrieb hat schon etwas gebracht, aber das liegt auch daran, dass ich zwar den Spulenstrom auf 80mA begrenze, aber immer alle 4 Spulen bediene (bipolar parallel, also 160mA pro Doppelspule), statt der bei unipolarem Betrieb „2 aus 4“. Die Gesamtverlustleistung wird also höher und die Motortemperatur steigt zu stark an. Da feht noch der Faktor sqrt(2).
    Auch für die Ansteuerung mit dem 6208 würde ich bipolar-parallel anstreben, (sonst wäre ja die Festspannung bereits 48V), so dass die Schaltung auf 160mA ausgelegt werden muss.
    Grüße, Michael

  3. Hallo Michael,
    ich habe das eben mal durchgerechnet wie der Spannungsteiler für R9/R10 aussehen müsste. Wenn du 160mA benötigst, braucht ein 2,5Ohm Rsense ein Vsense von 0,4V (0,16A x 2,5Ohm). Der würde eine Verlustleistung von 64mW (0,4V x 0,16A) erzeugen, sodass du deutlich unter dem liegst, was ein 1/4W Widerstand aushält.

    Der Spannungsteiler könntest du somit für R9 mit 22,6k und für R10 den 2k Poti auslegen. Der R9 stellt sicher, dass Vref nicht über 0,41V steigen kann (0,39V bei einem 23,7k).

    Das Datenblatt des L6208 sagt auch nicht, dass solch kleinen Werte problematisch sind. Die empfohlenen Werte liegen für Vsense -1 bis +1V und für Vref bei -0,1 bis 5V. Der Ausgangsstrom (Iout) hat noch nicht mal ein Minimum. Also ich würde sagen, dass es klappen sollte.

    Ich werde wohl nächste Woche eine Bestellung rausschicken, soll ich dir eins zuschicken, wenn sie da sind?

    LG, Timo

  4. Hallo Timo,
    was soll die Platine denn kosten? Ich habe noch einen Satz neuerer Nema17 Motoren, mit denen die Schaltung auf alle Fälle funktionieren sollte. Kennst Du eine günstige Bezugsquelle für die Bauteile, oder einfach Reichelt/Conrad? Beim Kühlkörper und allen teilen mit nicht 100%igem Rastermaß bin ich etwas vorsichtig…
    Kannst Du über die Forensoftware meine Email-Adresse sehen (vorname.nachname at lisytec dot de)? Dann brauchen wir die Details der Bezahlung hier nicht öffentlich zu machen.
    LG, Michael

  5. Hallo Timo,

    ich habe eine Frage zu deinem Quellcode: Um den Clock-Ausgang alle drei Millisekunden zu toggeln zählst du die Variable tcount hoch. In der While-Schleife fragst du aber ab, ob tcount > 3 ist – somit müssen seit dem letzten Setzen auf Null doch bereits vier Millisekunden vergangen sein! Oder habe ich da einen Denkfehler?
    Das ist natürlich kein dramatischer Fehler, aber das ist mir gerade so ins Auge gesprungen^^

    Viele Grüße
    Julian

    1. Hi Julian,
      da hast du ganz recht! Es müsste „tcount >= 3“, damit es ca. 3ms sind. In der alten Fassung „tcount > 3“ wird ein Durchlauf (und damit eine Millisekunde) zuviel gezählt. Danke für den Hinweis, das werde ich sofort ändern. Also nicht wundern, wenn du den Fehler nicht mehr findest 😉

      Alles Gute, Timo

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.