Das Stroboskop II – oder wie ich mich mit den Arduino Einschränkungen arrangiere

Im Arduino Hannover Blog http://arduino-hannover.de/2014/03/15/mein-paket-ein10w-power-led-modul/#more-842 hatte ich bereits meine ersten Erfahrungen mit meinem LED-Stroboskop zur Verfügung gestellt. Die ersten Schritte im Bereich von relativ langsamen Millisekunden und länger sind hier noch recht simpel nachvollziehbar und funktionieren alle wunderbar. Wenn jedoch bei höheren Frequenzen die Anforderungen in den Mikrosekundenbereich hinein steigen, erscheinen recht schnell diverse Fragezeichen. Der Sketch verhält sich nicht wie erwartet. Um das nicht nachvollziehbare Timingverhalten besser analysieren zu können, habe ich angefangen ganz einfache Sketche zu schreiben und die Ergebnisse dann mit einem Oscilloscope untersucht und nachfolgend dokumentiert.DigitalWrite

/*************************************************************/
#define LEDPIN             12               // Output pin 12 for the scope
/*************************************************************/
void setup() {
  pinMode(LEDPIN, OUTPUT); 
}
/*************************************************************/
void loop() {
  digitalWrite(LEDPIN, HIGH);
  digitalWrite(LEDPIN, LOW);
}
/*************************************************************/

DigitalWrite_4000nsH_4500nsLWie auf dem Screenshot zu erkennen, beträgt die HIGH-Zeit etwa 4us, während die LOW-Zeit etwa 4,5us beträgt. Eigentlich sollte man erwarten können, dass beide Zeiten identisch sind.

Im nächsten Versuche habe ich in der loop() die beiden Zeilen umgetauscht und erst angefangen den Ausgang auf LOW zu setzen und dann erst auf HIGH. Nun beträgt die HIGH-Zeit 4,5us und die LOW-Zeit knapp 4us. Die Verhältnisse haben sich nun umgekehrt. Die Differenz von etwa 0,5us ist dabei nahezu konstant geblieben und entspricht bereits einer Abweichung von ca. 6%. Die Periodendauer von 8,5us entspricht dabei einer Frequenz von f = 1/T  = 1/ 8,5us = 117,647kHz.

Im nächsten Sketch habe ich mehrere der digitalWrite() Sequenzen innerhalb der loop() einfach mehrfach hintereinander kopiert. Interessanterweise beträgt die Periodendauer dann ziemlich symmetrische 8us (125kHz) in Summe. Es sei denn, man schaut sich genau das Ende bzw. den Beginn der loop() an. Überraschung!

DigitalWrite_loop_10usHier ist dann plötzlich eine HIGH-Zeit von ca. 10us statt der erwarteten 4us zu erkennen! Eine wirkliche Erklärung habe ich derzeit nicht dafür. Ich vermute allerdings, dass dieses unerwartete Verhalten im Aufbau der loop() Funktion begründet ist. Für fundiertere Erklärungen wird sicher erst eine deutlich tiefere Untersuchung des generellen Arduino Sketchaufbaus erforderlich sein. Möglicherweise hat hierzu aber auch ein erfahrener C-Programmierer bereits eine Erklärung für dieses Verhalten.

Was ist eine Portmanipulation?

Atmega168PinMappingÜblicherweise werden beim Arduino die digitalen IO-Pins wie im obigen Sketch über die Funktionen digitialWrite() und digitalRead() oder auch pinMode() angesprochen. Da ist sehr komfortabel aber teilweise eben auch langsam, da innerhalb der jeweiligen Funktionen noch mehrere Sicherheitsüberprüfungen quasi im Hintergrund stattfinden. Dazu zählt eine Plausibilitätsprüfung des angegebenen Pins oder auch ggf. das Abschalten des PWM. Wer mehr dazu wissen möchte, schaut einfach mal in die zur Arduino IDE gehörende Datei wiring_digital.c hinein. Bei meinem Windows XP PC ist diese Datei unter folgendem Pfad zu finden:

C:\Program Files\Arduino\hardware\arduino\cores\arduino

Bei einem Mac sollte sie hier zu finden sein:

/Applications/Arduino.app/Contents/Resources/Java/hardware/arduino/cores/arduino

Nun zu den Details der Portmanipulation. Alle IO-Pins sind zu sogenannten Ports in jeweils einem 8-bit Register zusammengefasst.

Port B              Digital Pin 13 bis 8                   (Bits 6/7 nicht verwenden, funkt der Quarz)
Port C              Analog Input Pin A5 bis A0 (Bei einigen Arduino Boards auch bis A7)
Port D              Digital Pin 7 bis 0                     (Bits 0 uns 1 nicht verwenden, da RX und TX)

Zu jedem Port gehören weitere Register mit denen das Verhalten bestimmt oder der Port ausgelesen oder gesetzt wird. Das x ist ein Platzhalter und wird durch den jeweiligen Port B oder C oder D ersetzt.

DDRx              Data Direction Register         – Schreiben/Lesen (entspricht pinMode())
PORTx           Data Register                               – Schreiben/Lesen (entspricht digitalWrite())
PINx                Input Pins Register                   – nur Lesen (entspricht in etwa digitalRead())

Das MSB (Most Significant Bit) also das höchstwertige Bit  steht im Register immer ganz links, das LSB (Least Significant Bit), das niederwertigste immer rechts.

Port B Port C PORT D
LSB Digital Pin 8 Analog Pin 0 Digital Pin 0
MSB Digital Pin 13 Analog Pin 5 Digital Pin 7

PINx ist hier die Variable für das Eingangsregister. Alle 8 Eingänge der Digital Pins 13 bis 8 beispielsweise können hier über PINB gleichzeitig parallel eingelesen werden.

Mit dem DDRx-Register wird die Datenrichtung einzelner Pins bestimmt, also ob der jeweilige Digital Pin als Eingang oder Ausgang arbeitet. LOW oder auch 0 bedeutet Eingang, 1 oder HIGH bedeutet der Pin arbeitet als Ausgang.

 DDRB = B00000000;          // Setze PORTB (Digital Pin 13 bis 8) als Eingang
DDRD = B11111111;            // Setze PORTD (Digital Pin 7 bis 0) als Ausgang

Da am Port D auch die RX/TX Leitungen zur Kommunikation mit dem USB-Anschluss verbunden sind, werden diese üblicherweise über eine entsprechende ODER-Verknüpfung ausmaskiert.

DDRD = DDRD | B11111100;

Die Pins 0 und 1 (RX/TX) werden so ausgeklammert und nur die Pins 2 bis 7 explizit als Ausgang gesetzt. Die Pins 0 und 1 behalten ihren ursprünglichen Zustand!

Eine ODER-Verknüpfung bedeutet hier, dass nur wo eine 1 steht, der jeweilige Portpin explizit auf HIGH und damit hier als Ausgang gesetzt wird. In Form einer Wahrheitstabelle sieht das wie folgt aus:

E1       E2       A
0          0          0
0          1          1
1          0          1
1          1          1

Nur wo mindestens ein Pin  E1 oder E2 gleich 1 also HIGH ist, wird der Ausgang A auf 1 gesetzt.

Über beispielsweise das Register PORTD setzen wir nun den Status der zuvor als Ausgang definierten Pins auf HIGH oder LOW.

PORTD = B10101000;          // Setze Digital Pins 7, 5, 3 HIGH

Zum Löschen bzw. Rücksetzen einzelner Bits auf 0 bzw. LOW wird aus ähnlichen Sicherheitsüberlegungen wie weiter oben bereits beschrieben, eine UND-Verknüpfung verwendet. Die Tilde ~ negiert hier den binären Inhalt der zuvor definierten Konstante PORTMASK mit B00010000 zu B11101111.

PORTB &= ~PORTMASK;       // Set digital pin 12 to LOW

Das Bit 4 (Zählweise beginnt immer ganz rechts mit dem LSB Bit 0) des Registers PORTB entspricht dem Digital Pin 12. Durch die UND-Verknüpfung des Bits 4 mit seinem Inhalt 0 können wir nun nur diesen einen oder natürlich auch mehrere Pins gezielt auf 0 zurücksetzen. Die Wahrheitstabelle sieht folgendermaßen dazu aus

E1       E2       A
0          0          0
0          1          0
1          0          0
1          1          1

Sofern nur ein Pin E1 oder E2 auf 1 bzw. HIGH steht, bleibt der Pin A auf 0. Nur wenn beide Pins, also E1 und E2 auf 1 gesetzt sind, wird der Ausgang auch auf 1 gesetzt. Das bedeutet im Umkehrschluss für das Beispiel oben: Ist der Digital Pin 12 bereits 0, bleibt er auf LOW, ist er auf 1 bzw. HIGH, wird er über die UND-Bedingung auf 0 gesetzt. Digital Pins, die ihren ursprünglichen Zustand behalten sollen, bleiben mittels der UND-Verknüpfung mit 1 unangetastet.

Gute Tutorials zu diesem Thema sind auch hier und hier zu finden.

Portmanipulation

Da ich mich vor einiger Zeit bereits einmal mit der Portmanipulation beschäftigt hatte, habe ich den ersten Sketch von oben nochmals umgeschrieben.

/************************************************************/
#define LEDPIN                 12                     // Output pin 12 for the scope
#define PORTMASK         B00010000  // Pin 12 masked
/*************************************************************/
void setup() {
  pinMode(LEDPIN, OUTPUT); 
}
/*************************************************************/
void loop() {
  PORTB |= PORTMASK;                           // Set digital pin 12 to HIGH
  PORTB &= ~PORTMASK;                       // Set digital pin 12 to LOW
}
/*************************************************************/

 Screenshot 2014-03-15 20.49.42Die Periodendauer des geschalteten IO-Pins beträgt hier exakt 1us, entsprechend 1MHz. Allerdings ist hier das Verhältnis noch deutlich unsymmetrischer. Die HIGH-Zeit beträgt hier nur 120ns zu 880ns LOW-Zeit. Wieder habe ich die beiden Zeilen in der loop() getauscht. Wie erwartet ändern sich nun auch die Schaltzeiten, wie nachfolgend gut zu sehen ist.

Screenshot 2014-03-15 20.55.19Als nächstes kopiere ich wieder mehrere der beiden obigen Zeilen innerhalb der loop()einfach wie folgt hintereinander.

.

.

.

PORTB |= PORTMASK;           // Set digital pin 12 to HIGH
PORTB &= ~PORTMASK;       // Set digital pin 12 to LOW
PORTB |= PORTMASK;           // Set digital pin 12 to HIGH
PORTB &= ~PORTMASK;       // Set digital pin 12 to LOW
PORTB |= PORTMASK;           // Set digital pin 12 to HIGH
PORTB &= ~PORTMASK;       // Set digital pin 12 to LOW
PORTB |= PORTMASK;           // Set digital pin 12 to HIGH
PORTB &= ~PORTMASK;       // Set digital pin 12 to LOW
PORTB |= PORTMASK;           // Set digital pin 12 to HIGH
PORTB &= ~PORTMASK;       // Set digital pin 12 to LOW

Screenshot 2014-03-15 21.03.32Wie auch auf dem Scope zu erkennen, habe ich 5  der HIGH-LOW Sequenzen in die loop() kopiert. Die Schaltzeiten innerhalb einer Sequenz sind wie weiter unten zu sehen, hier für HIGH und LOW mit  jeweils 120ns erwartungsgemäß identisch. Die Periodendauer von 240us entspricht einer Frequenz von f = 1/T = 1/240ns = 4166,667kHz oder auch knapp 4,2MHz. Direkt nach diesen 5 HIGH-LOW Sequenzen finden wir jedoch am Ende der loop() bis zum erneuten Beginn am Anfang der loop() eine Totzeit von etwa 850ns.Screenshot 2014-03-15 21.10.10

Screenshot 2014-03-15 21.06.16Damit wäre zumindest wieder einmal bewiesen: Es gibt in der Elektronik keine idealen Zustände.

Mit den Erkenntnissen aus diesen Versuchen, ist es zumindest nicht weiter verwunderlich, wieso meine hochgesteckten Erwartungen bei meinem ersten Stroboskopsketch nicht erfüllt worden sind. In Assembler wäre das vermutlich nicht passiert, da bin ich mir schon ziemlich sicher. Das ist ein offensichtlicher Nachteil der komplexeren Hochsprachen. In C zu programmieren ist allerdings doch deutlich komfortabler als in Assembler.

Da ich jetzt einmal dabei bin, mich mit dieser generellen Problematik auseinanderzusetzen, noch ein weiterer Sketch mit der analogRead() Funktion.

AnalogRead

Der Sketch wird nun minimal aufwändiger.

/************************************************************/
#define LEDPIN                  12                     // Output pin 12 for the scope
#define PORTMASK          B00010000  // Pin 12 masked
#define ANALOGIN           A0                     // A0 analog input
/*************************************************************/
void setup() {
  pinMode(LEDPIN, OUTPUT); 
}
/*************************************************************/
void loop() {
  analogRead(ANALOGIN);             // Read 10 bit analog value
  PORTB |= PORTMASK;                    // Set digital pin 12 to HIGH
  PORTB &= ~PORTMASK;               // Set digital pin 12 to LOW}
/*************************************************************/

Mit einem analogRead() im Sketch beträgt die Totzeit nun 112us.

Screenshot 2014-03-16 09.50.08

Screenshot 2014-03-16 09.51.09

Die HIGH-Pegelzeit beträgt hier nun relativ genau gemessen 124ns.

Das HIGH Signal ist wie erwartet trotz der jetzt eingebauten analogRead() Funktion konstant geblieben und hat darauf keinen Einfluss. Allerdings die nun gemessenen 112us LOW-Zeit verglichen mit den 880ns zuvor, bestätigen meine Vermutung. Die analogRead() Funktion ist hier allein mit gut 111us extrem zeitintensiv.

 

Der Systemtakt des AD-Wandler

Nach all den Versuchen ist es nun an der Zeit mit etwas Theorie weiterzumachen, um die gesammelten Erkenntnisse besser zu verstehen, zu präzisieren und zu vertiefen. Dazu ist es angebracht das 660 Seiten starke Manual von der Atmel Homepage herunterzuladen. Keine Panik, es wird jetzt nicht alles darin benötigt. In Kapitel 24 ab Seite 242 sind die relevanten Details zum ADC beschrieben. In Kapitel 24.8 ist mir nebenbei noch ein vielleicht mal in einem anderen Projekt benötigtes Feature aufgefallen. Der Prozessor hat einen integrierten Temperatursensor, der über den Kanal 8 des Multiplexers ausgelesen werden kann. Nun aber erst einmal wieder zurück zum Thema.

10_Bit_ADC_8_Channel_MuxerDer Atmega328P im Dual-Inline Gehäuse beinhaltet einen 10-bit AD-Wandler mit einem 8-Kanal Multiplexer davor, die in der Arduino IDE über A0 bis A5 bzw.  einigen Derivaten sogar von A0 bis A7 angesprochen werden können.

Der Systemtakt des Controllers bei einem Arduino Uno oder Duemilanove beträgt üblicherweise 16MHz, das entspricht einer Periodendauer T = 1/f von exakt 62,5ns. Die oben gemessenen 124ns entsprechen daher eher 125ns, also genau 2 Taktzyklen zu je 62,5ns. Der AD-Wandler selber wird laut Arduino Spezifikation mit einem 128stel über einen Vorteiler davon betrieben. 16MHz / 128 = 125kHz entsprechen 8us Periodendauer.

Dazu sollte man jetzt noch wissen, dass die erste Wandlung 25 Taktzyklen benötigt und jede weitere dann 13. Teilt man nun obige 125kHz durch diese 13 Taktzyklen beträgt die höchste Sample Rate gerade mal 9,615kHz.

In Kapitel 24.9.2 wird das Register ADCSRA, das ADC Control und Status Register A beschrieben.

ADCSRA

MSB

 

 

 

 

 

 

LSB

Bit

7

6

5

4

3

2

1

0

(0x7A)

ADEN

ADSC

ADATE

ADIF

ADIE

ADPS2

ADPS1

ADPS0

Read/Write

R/W

R/W

R/W

R/W

R/W

R/W

R/W

R/W

Initial Value

0

0

0

0

0

0

0

0

Relevant sind hier die 3 niederwertigen Bits (ADC Prescaler Select) ADPS[2:0], mit denen der Vorteiler für die Taktfrequenz des Analog-Digital Wandlers eingestellt werden kann.

ADPS2 ADPS1 ADPS0 Division
Factor

0

0

0

2

0

0

1

2

0

1

0

4

0

1

1

8

1

0

0

16

1

0

1

32

1

1

0

64

1

1

1

128

Ausgehend vom üblichen 16MHz Systemtakt, hier nun geteilt durch 16, entspricht das jetzt einer Taktrate für den Wandler von 1MHz bzw. einer Periodendauer von 1us. Bei 1MHz Wandlertaktrate und 13 Taktzyklen für eine vollständige Wandlung beträgt die theoretische Sample Rate nun immerhin 76,923kHz oder auch 76923 Samples je Sekunde. Die maximale Signalbandbreite die abgetastet werden kann, ist auf Basis des Nyquist Theorems auf 38,461kHz begrenzt.

Keinesfalls verschwiegen werden darf noch, dass bei solch hohen Taktraten für den Wandler die Auflösung von 10-bit nicht mehr unbedingt erreicht werden kann. Die im Wandler integrierte Sample&Hold-Schaltung ist bei zu hohem Takt unter Umständen nicht mehr in der Lage sich auf den vollen Wert aufzuladen. Ähnliches gilt auch bei deutlich zu niedrigem Takt, da dann die S&H-Schaltung u. U. schon wieder einen Teil des gespeicherten Inhaltes vergessen hat. Aus dem Grunde wird im Datenblatt auf Seite 245 empfohlen, die Wandlertaktrate grob zwischen 50kHz und 200kHz einzustellen, um dann mit der vollen 10-bit Auflösung arbeiten zu können. Ich habe dann noch eine interessante Application Note AVR120 „Characterization and Calibration of the ADC on an AVR“ gefunden, in der einige weitere Tipps und Hinweise zum ADC zu finden sind. Unter anderem ist unter 2.8 geschrieben, dass mit Taktraten unter 1MHz die Auflösung nur unwesentlich verschlechtert wird. Oberhalb von 1MHz ist dann allerdings nichts weiter spezifiziert.

 Mein Fast AnalogRead

Über bitClear() und bitSet() lässt sich nun recht einfach dieser Teilerfaktor beeinflussen. Mit der Bitfolge 100 wird der Teilerfaktor auf 16 eingestellt. Nachfolgend der geänderte Sketch.

/************************************************************/
#define LEDPIN                    12                        // Output pin 12 for the scope
#define PORTMASK           B00010000      // Pin 12 masked
#define ANALOGIN             A0                        // A0 analog input
/*************************************************************/
void setup() {
  pinMode(LEDPIN, OUTPUT); 
  bitClear(ADCSRA,ADPS0);                         // Set ADC Prescaler to 16
  bitClear(ADCSRA,ADPS1);
  bitSet    (ADCSRA,ADPS2);
}
/*************************************************************/
void loop() {
  analogRead(ANALOGIN);                           // Read 10 bit analog value
  PORTB |= PORTMASK;                                   // Set digital pin 12 to HIGH
  PORTB &= ~PORTMASK;                              // Set digital pin 12 to LOW
}
/*************************************************************/

Aus den theoretisierten Vorüberlegungen im vorigen Kapitel, nun noch die gemessenen Daten dazu.

Mit jetzt nur noch 17uScreenshot 2014-03-16 15.58.08s gegenüber vorher mit etwa 112us, sind wir nun tatsächlich auch hier signifikant schneller geworden.

Mit der potentiell etwas geringeren Auflösung kann ich in meinem nachfolgenden Stroboskopprojekt gut leben.

Das Stroboskop II

Hier nochmals der Aufbau der Hardware, die noch dem ersten Entwurf entspricht.

Ardu Stroboskop_Steckplatine

 Aufbauend auf den obigen Erfahrungen, habe ich nun dazu folgenden Sketch geschrieben.

/**************************************************************************/
/* Simple Stroboscope with an Arduino and a 10W Power-LED-Module 10V white
 *
 * Origin Author:        Olaf Meier
 *
 * Modified by:         
 *
 * Hardware connection:  Pin 12 to Gate via 1k, LED to +12V via open Drain N-Channel
 *
 *
 * ToDo:
 *
 */
/**************************************************************************/
/*
 * Example of output:
 *
 */
/**************************************************************************/
/**************************************************************************/
/***  Declaration of global constants and initialization of variables. Add includes.  ***/
/**************************************************************************/
/***  Software release and date  ***/
const char* sketchname    =  „Stroboscope II“;
const char* revision              =  „R.0.9“;
const char* author                =  „Olaf Meier“;
const char* date                    =  „2014/03/16“;
/**************************************************************************/
/***  Declare constants and variables for the stroboscope  ***/
#define LEDPIN                    12
#define PULSEPOTI             A0                   // Connect mid pin of pot to analog pin A0
#define DELAYPOTI             A1                   // Connect 10k pot here for frequency
#define PORTMASK           B00010000  // MSB = unused; LSB = digital pin 8; her pin 12 masked
 
int pulse                                =  0;
 
int cycle                               =  5000;          // 1s = 1.000.000 microseconds = 1.000ms
int factor                             =  10;               // Percentage of the total cycle to pulse high
/**************************************************************************/
/**************************************************************************/
void setup() {
  pinMode(LEDPIN, OUTPUT);
  pinMode(PULSEPOTI, INPUT);              // Percentage of the cycle
  pinMode(DELAYPOTI, INPUT);
  /***  Set ADC Prescaler to divider = 16  ***/
  bitClear(ADCSRA,ADPS0);
  bitClear(ADCSRA,ADPS1);
  bitSet  (ADCSRA,ADPS2);
}                                                                             // End of void setup()
/**************************************************************************/
/**************************************************************************/
void loop() {
  cycle = map(analogRead(DELAYPOTI), 0, 1023, 100, 16383);// Max. 16383, bug in micros
  /***  Pulse length between 1% and 50%; (or >>4 = divide by 16 = 1024/16=64)  ***/
  factor = map(analogRead(PULSEPOTI),0,1023, 1,50);// Or just use instead of map >>4;
  pulse = cycle / 100 * factor;                    
  PORTB |= PORTMASK;                             // Set digital pin 12 to HIGH
  delayMicroseconds(pulse);                 // Determing HIGH-time
  PORTB &= ~PORTMASK;                        // Set digital pin 12 to LOW
  delayMicroseconds(cycle-pulse);    // Determing LOW-time
}                                                                           // End of void loop()
/**************************************************************************/
/**************************************************************************/

In den nachfolgenden Screenshots ist das Timingverhalten dazu recht gut nachzuvollziehen. Die im Sketch vorgegebene Periodendauer liegt zwischen 100us und 16383us. Größere Werte funktionieren hier nicht, da offensichtlich in der Funktion delayMicroseconds() noch ein Bug vorhanden ist. Die Pulsdauer kann separat über ein zweites Poti zwischen 1% und 50% eingestellt werden.Screenshot 2014-03-16 19.18.50

Bei den relativ langen Zeiten von etwa 16,5ms stimmt das Puls-Pausenverhältnis mit ca. 50% nicht perfekt, aber akzeptabel.

Screenshot 2014-03-16 19.19.02

Auch Pulszeiten mit nur 1% der Periodendauer passen noch sehr gut mit etwa 165us ins Schema. Zeiten im derzeit kleinsten vorgegeben Bereich von 100us werden nun mit immerhin etwa 260 bis 300us in der Praxis realisiert. Wie sich in weiteren Versuchen hierzu nebenbei herauskristallisierte, sind hier die map() Funktionen wie auch die if-Abfragen relativ zeitintensiv.

In der jetzigen Konstellation bewegen sich die Pulszeiten zwischen 1,2us und 50us im schnellsten Bereich.

Weitere Optimierung lassen sich sowohl am Sketch als auch noch an der Hardware durchführen. Die grundsätzliche Funktion ist hiermit aber auf jeden Fall nachgewiesen. In einer weiteren Baureihe würde ich vermutlich auf die analogRead() Funktionen verzichten und die Werte per Tastatur oder Drehimpulsgeber direkt eingeben. Ob auch noch genügend Zeit für ein LCD übrigbleibt, ist allerdings fraglich.

Werbeanzeigen

2 Kommentare zu „Das Stroboskop II – oder wie ich mich mit den Arduino Einschränkungen arrangiere

  1. Hallo,
    ich habe gelesen, dass man ein wirklich stabilis Timing nur hinkriegt, wenn:
    a) Interrupts abgeschaltet werden
    b) man eine Schleife nutzt, in der die Befehle abgearbeitet werden.
    while (1) {
    port einschalten
    port ausschalten
    }
    In der Loop-Schleife ist, Arduino-Compiler bedingt, immer eine unwucht.
    Ein direktes ansprechen der Ports, durch setzen oder löschen von Bits im entsprechenden Register, bringt auch bessere Ergebnisse. Vor allem noch mehr Geschwindigkeit.

    1. Hallo Michael,

      das stimmt grundsätzlich. Bei den im Stroboskop relativ niedrigen Frequenzen hier spielt das aber nur eine untergeordnete Rolle. Soll es jedoch tatsächlich genauer und auch deutlich schneller reagieren, verwendest Du die Portmanipulation.

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden /  Ändern )

Google Foto

Du kommentierst mit Deinem Google-Konto. Abmelden /  Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden /  Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden /  Ändern )

Verbinde mit %s