Sturzi's Arduino-Bastel-Projekt #1 - Es werde Licht

  • Wertebereich analoger Eingang - Warum 0 ... 1023 - Etwas über Bits, Bytes und Bit-Päckli


    Dieser Beitrag ist nicht essentiell, um in diesem Projekt weiterkommen zu können.

    Du kannst den Wertebereich bei den analogen Eingängen (0 bis 1023) auch einfach zur Kenntnis nehmen und den Rest dieses Beitrages überspringen.

    Wenn du aber wissen willst warum, solltest du diesen Beitrag lesen (interessant ist es allemal).



    Warum geht der Wertebereich bei den analogen Eingängen ausgerechnet von 0 bis 1023, und nicht etwas von 0 bis 100 oder von 0 bis 1000?


    Das hat mit der Art, wie im Computer Zahlenwerte gespeichert werden, zu tun. Die niedrigste Informations-Einheit im Computer ist ja ein Bit, welches nur die Werte 0 und 1 annehmen kann. Will man andere (grössere) Werte speichern, setzt man mehrere Bits zusammen in ein Päckli. Ein bekanntes Päckli ist ein Byte, welches immer aus 8 Bit besteht. Es sind aber auch andere Päckli gängig, z.B. 16-Bit-Worte oder 32-Bit-Worte. Wenn ein Päckli mehr als 8 Bit hat, spricht man oft von Worten, wobei man dann die Bit-Zahl angeben muss. Päckli von 4 Bit (ein halbes Byte) nennt man Nibble.


    Fangen wir einfach an. Hätten wir zum Speichern von positiven ganzen Zahlen nur Nibbles, also Päckli aus 4 Bit zur Verfügung, könnten wir nur die Zahlen 0 bis 15 speichern. Warum? Das ist wegen der binären Codierung, die in der Informatik durchgehend üblich ist:


    0000 -> 0

    0001 -> 1

    0010 -> 2

    0011 -> 3

    0100 -> 4

    0101 -> 5

    0110 -> 6

    und so weiter, bis zuletzt

    1111 -> 15


    Jedes Bit hat ein Wertigkeit. Das Bit ganz rechts (das Bit 0) ist das niederwertigste Bit, es hat den Wert 1. Das zweite Bit von rechts (das Bit 1) hat die doppelte Wertigkeit, nämlich 2. Das dritte Bit von rechts (das Bit 2) hat 4 (wiederum das doppelte von vorher) und das nächste (beim Nibble das ganz linke, das Bit 3) hat einen Wert von 8 (wiederum das doppelte). (Weil man in der Informatik mit 0 zu zählen beginnt, fängt die Bit-Nummerierung von rechts mit 0 an.)

    Wenn man nun z.B. das Bitmuster 1001 hat, errechnet man seinen Wert mit der Wertigkeit der Bits

    Bit 0 ist 1 und hat den Wert 1, also 1 x 1 = 1

    Bit 1 ist 0 und hat den Wert 2, also 0 x 2 = 0

    Bit 2 ist 0 und hat den Wert 4, also 0 x 4 = 0

    Bit 3 ist 1 und hat den Wert 8, also 1 x 8 = 8

    Zählt man nun die 4 Werte zusammen, kommt man auf 9 und in der Tat (bei der Speicherung von positiven ganzen Zahlen) hat das Nibble 1001 den Wert 9.


    Nach dem gleichen Schema verläuft das, wenn man mit Bytes "arbeitet". Dort hat wiederum das rechte Bit den Wert 0, jedes weitere Bit gegen links nimmt den doppelten Wert des vorhergehenden an. Das Bit 7 (das ganz links) hat den Wert 128. Man kann es nun selber ausrechnen, wenn alle Bits bei einem Byte 1 sind kommt man auf den Gesamt-Wert von 255. Deshalb hat (bei Speicherung von positiven ganzen Zahlen) ein Byte den Werte-Bereich 0 bis 255.


    Und nun zum eigentlichen Thema dieses Beitrages, zum Werte-Bereich der analogen Eingänge: Dafür werden Päckli von 10 Bits verwendet. Auch hier geht es nach dem gleichen Schema. Hier hat das höchstwertige Bit den Wert von 512. Wenn nun alle Bits 1 sind -> rechne selbst -> ergibt das den Wert von 1023.


    Innerhalb eines Päcklis gilt: Das niedrigstwertigste Bit (das ganz rechts) nennt man das LSB (Least Significant Bit) und das höchstwertige Bit (das ganz links) nennet man das MSB (Most Significant Bit).


    Die Wertigkeit eines Bits kann man mit seiner Position auch ausrechnen. Wertigkeit = 2 hoch Bitposition.

    Beispiele:

    Das 13. Bit von rechts (das Bit in der Position 12, weil wir mit 0 zu zählen anfangen) hat den Wert 2 hoch 12 = 4096

    Das 6. Bit von rechts (das Bit in der Position 5, weil wir mit 0 zu zählen anfangen) hat den Wert 2 hoch 5 = 32

    Das Bit ganz rechts (das Bit in der Position 0) hat den Wert 2 hoch 0 = 1


    Ich habe mehrmals in Klammern den Hinweis "bei Speicherung von positiven ganzen Zahlen" geschrieben . Das ist, weil es für andere Arten von Daten (negative Zahlen, gebrochene Zahlen, Texte, etc.) wieder andere Arten gibt, die Wertigkeiten mit Bits ins jeweilige Päckli einzupacken. Aber für den Fall, dass wir ausschliesslich mit positiven ganzen Zahlen arbeiten, funktioniert es wie oben beschrieben.


    Ich werde vielleicht bei anderen Gelegenheiten ähnliche Exkurse machen. Bei solchen, die für das Projekt nicht relevant sind, werde ich das auch dazuschreiben, damit man sie allenfalls überspringen kann.

  • Ich habe die Schaltung und das Programm Raumschiff Steuerzentrale aus dem Arduino Projektbuch durchgearbeitet. Eine tolle Sache, langsam verstehe ich, was ich dem Arduino befehle und warum er es auch macht. Es macht langsam aber sicher Spass, auch wenn jedes Mal Fehlersuche wegen dussligen Schreibfehlern angesagt ist. Braucht zum Glück bis jetzt nur immer wenige Minuten, bis es dann auch läuft.

    Gruss Erwin



    Wer rast, der verpasst das Leben.


    Kein Platz für weitere Sammelstücke ist nur eine faule Ausrede. ;) Es gibt für alles eine Lösung.

  • Wenn nach einem Moment eine Erfolgs-Meldung "Done uploading" erscheint, ist das geglückt. Andernfalls muss man das Problem zu lösen versuchen.

    Ich kann hier natürlich nicht für alle erdenklichen Probleme eine Lösung anbieten. Wenn du aber trotz Hilfe aus dem Internet nicht weiterkommst, versuche ich mit deiner Problem-Beschreibung gerne, zu helfen.

    Hoi Röbi

    Heute bin ich zum Ausprobieren gekommen. Nach einigen Irrläufen mit Windows 10 (alles abgesichert, gesperrt, mit Firewall usw.) bin ich soweit gekommen, wie das folgende Bild zeigt:

    Die IDE ist bereits die Version 2.0.2

    Mich stört der Eintrag, eine Library sei nicht gefunden worden (Arduino_BuiltIn library). Braucht es diese?


    Installiert habe ich mit dem Windows MSI und bereits angeschlossenem Arduino. So hat der MSI den Port COM5 gefunden und für die Zuordnung angeboten.

    Gruss Oski


    Nach dem Abspeichern des Sketches und dem neu laden ergab der Upload keine Fehlermeldung mehr. Die Reihenfolge des Anschliessens des Arduino und der Portauswahl durch den MSI muss den Error erzeugt haben. Natürlich bin ich selber schuld, du hast ja beschrieben, man solle den Arduino erst nachher anschliessen. Jetzt funktioniert es!

    signatur_egos.jpg

    ...auch Nichtraucher können süchtig sein nach Zündhölzern!

    Einmal editiert, zuletzt von egos () aus folgendem Grund: Edit: Fehler selber gefunden

  • Das Beispiel mit dem Potentiometer habe ich auch durchgearbeitet. Kleine Fehler passieren immer wieder, sei es beim Aufbau der Schaltung oder schreiben des Programmes. Mit den Fehlerangaben nach dem compilieren komme ich jetzt mittlerweile der Fehlerursache schneller auf die Schliche oder wie im Beispiel mit dem Potentiometer, wenn die Ausgabe 0 Volt ist, muss der Fehler nicht im Programm gesucht werden, sondern in der Schaltung, wo er auch war. Beide Drahtbrücken auf Minus gesteckt, kann keine Spannung anzeigen.


    Zuvor hatte ich das Love-o-Meter aus dem Buch abgearbeitet, das gleiche Elemente für die Serielle Ausgabe verwendet.

    Gruss Erwin



    Wer rast, der verpasst das Leben.


    Kein Platz für weitere Sammelstücke ist nur eine faule Ausrede. ;) Es gibt für alles eine Lösung.

  • Mit Hilfe des Potentiometers kann die Ein- und Ausschaltdauer der LEDs beeinflusst werden


    Zuerst das neue Programm:

    Was ist neu?

    Zeile 6: Die Konstante analogInputUsedForPoti. Hier wird eingetragen, an welchen analogen Eingang das Poti angeschlossen ist (hier A0).

    Zeile 7: Die Variable intervalFactor, die vom Poti beeinflusst werden kann. Um diesen Faktor werden Wartezeiten vergrössert.

    Zeile 8: Den Zweck der Variablen intervalFactorPreviousValue wird unten erklärt.

    Zeilen 32 bis 39: Hier wird (abhängig von der Stellung des Poti) die Variable intervalFactor bestimmt. Auch das werden wir unten genauer auseinandernehmen.

    Zeilen 47 und 49: Die neuen Wartezeiten millisToWait werden weiterhin durch Zufall bestimmt, aber mit dem intervalFactor multipliziert.


    Erklärungen sind vor Allem für die folgende Sequenz (Zeilen 32 bis 39) nötig.

    Code
      intervalFactor = analogRead(analogInputUsedForPorti) / 10 + 1;
      if (intervalFactor != intervalFactorPreviousValue) {
        for (int i = 0; i < numOfLEDsUsed; i++) {
          changeStatus(i);
        }
        intervalFactorPreviousValue = intervalFactor;
        Serial.println(intervalFactor);
      }

    Zeile 32: Der Wert, den wir über den analogen Eingang A0 einlesen ist im Bereich 0 ... 1023 (siehe Beiträge 99 und 101). Den wollen wir um den Faktor 10 verkleinern und dafür sorgen, dass er nie Null wird. Das machen wir mit dieser Anweisung.


    Zeilen 33 und 37: Mit der Variablen intervalFactorPreviousValue wollen wir sicherstellen, dass die Anweisungen 34 bis 38 nur ausgeführt werden, während wir am Poti drehen und nicht dauernd. Wir befinden uns ja schliesslich in der Funktion loop(), die schnell (mehrere tausend Mal pro Sekunde) durchlaufen wird. Um das zu ermöglichen speichern wir den letzten Wert von intervalFactor in der Variablen intervalFactorPreviousValue ab (Zeile 37).

    Das Programm würde technisch auch funktionieren ohne die Zeilen 34 bis 38 (ihr könnte sie gerne mal rausnehmen und schauen, wie es sich verhält). Aber aus zwei Gründen sind sie sinnvoll:

    1. Wir schicken den jeweiligen Wert von intervalFactor auf den Serial Monitor und wollen verhindern, dass wir pro Sekunde tausende von Meldungen schicken, auch wenn wir nicht am Poti drehen.

    2. Wenn wir ein langes Interval eingestellt haben und drehen das Poti dann wieder auf schnell, müssten wir minutenlang warten, bis wir eine Reaktion sehen.


    Ihr könnt nach wir vor die Grundwerte (Zeilen 1 bis 4) nach eurem Gusto einstellen. Die effektiven Verzögerungen sind dann einfach (je nach Poti-Stellung) bis zum 103-fachen.


    Jetzt müsstet ihr die Ein- und Aus-Intervalle durch drehen am Poti einstellen können. Wenn's funktioniert bin ich froh um eine Rückmeldung.

  • Hoi Röbi

    Es hat etwas gedauert, aber es klappt:

    Eine Frage habe ich noch zur LED 13: Diese leuchtet sehr schwach und löscht manchmal fast ab. Hat die Schaltung einen Wackelkontakt oder leuchtet diese LED nur schwach?

    Gruss Oski

    signatur_egos.jpg

    ...auch Nichtraucher können süchtig sein nach Zündhölzern!

  • Das Beispiel mit dem vorgeschaltetem Poti habe ich umgesetzt. Allerdings nur drei Ausgänge (2 - 4) belegt. Es funktioniert soweit. Sobald ich den seriellen Monitor lösche, zeigt es keine Werte mehr an, erst wieder wenn ich am Poti drehe. Ist das so korrekt?


    Die Schaltung ist hoffentlich korrekt aufgebaut.


    Gruss Erwin



    Wer rast, der verpasst das Leben.


    Kein Platz für weitere Sammelstücke ist nur eine faule Ausrede. ;) Es gibt für alles eine Lösung.

  • Eine Frage habe ich noch zur LED 13: Diese leuchtet sehr schwach und löscht manchmal fast ab. Hat die Schaltung einen Wackelkontakt oder leuchtet diese LED nur schwach?

    Oski, wie hast du den Pin 13 programmiert? Gar nicht? Dann ist das der Grund.

    Wenn du programmierst pinMode(13, OUTPUT); und dann digitalWrite(13, LOW); oder digitalWrite(13, HIGH); , dann müsste die LED 13 entweder dunkel oder kräftig hell sein. Falls du, wie ich vermute, auf Pin 13 gar nichts programmiert hast, hängt dieser Pin "in der Luft" und reagiert auf Einstreuungen von aussen.

  • Wenn ich es richtig sehe, hat Oski nur 5V und GND benutzt und keinen programmierbaren Ausgang belegt. Quasi eine einfache Schaltung wie im Projekt 1 des Arduino Projektbuches.

    Gruss Erwin



    Wer rast, der verpasst das Leben.


    Kein Platz für weitere Sammelstücke ist nur eine faule Ausrede. ;) Es gibt für alles eine Lösung.

  • zeigt es keine Werte mehr an, erst wieder wenn ich am Poti drehe. Ist das so korrekt?

    Erwin, die Zeilen 34 bis 38 sind unter anderem dazu da, dass die Meldungen an den Serial Monitor nur erzeugt werden, während dem man am Poti dreht. Würde man das nicht machen, würden pro Sekunde tausende von Meldungen erzeugt, weil das Serial.println(intervalFactor) auf Zeile 38 dann unbedingt (ohne if-Bedingung) ausgeführt würde. Der if sorgt dafür, dass alles im if-Body nur ausgeführt wird, wenn die Werte vom Poti ändern (d.h. wenn man dran dreht).

    Somit: Das ist korrekt.

  • Wenn ich es richtig sehe, hat Oski nur 5V und GND benutzt und keinen programmierbaren Ausgang belegt. Quasi eine einfache Schaltung wie im Projekt 1 des Arduino Projektbuches.

    Ja. aber das hat nichts mit dem Verhalten der LED 13 zu tun. Die Onboard-LED 13 ist intern fest mit dem Pin 13 verdrahtet. Er kann diese auch ohne externe Verdrahtung ansteuern. Um das beurteilen zu können, müssten wir sein Programm sehen.

  • Ja. aber das hat nichts mit dem Verhalten der LED 13 zu tun.

    Das ist die LED die auf dem Board mit L bezeichnet ist? Die leuchtet bei mir auch immer schwach. Wenn ich sie auf HIGH setze leuchtet sie hell und bei LOW ist sie dann aus.


    Mehr als das braucht es nicht?


    void setup() {
    pinMode(13, OUTPUT);
    }

    void loop() {
      digitalWrite(13, LOW);
    }

    Gruss Erwin



    Wer rast, der verpasst das Leben.


    Kein Platz für weitere Sammelstücke ist nur eine faule Ausrede. ;) Es gibt für alles eine Lösung.

  • wie hast du den Pin 13 programmiert? Gar nicht? Dann ist das der Grund.

    Hoi Röbi

    Es ist so, wie du vermutest. Das habe ich falsch verstanden. Ich dachte der Pin 13 leuchte einfach. Programmiert habe ich noch gar nichts. Ich war schon reif für die Insel, bis die LED aufleuchtete.

    Gruss und Dank

    Oski

    signatur_egos.jpg

    ...auch Nichtraucher können süchtig sein nach Zündhölzern!

  • Röbi und Erwin:

    Danke für die Erklärung. Nun habe ich nachgebessert. Jetzt funktioniert auch das. Es ist übrigens noch spannend, wie auf dem Arduino Board während des Uploads die RX und TX LED blinken.

    Wenn nun deine LED ziemlich schnell blinkt (zweimal ein und aus pro Sekunde), hast du die kritische Hürde geschafft und dein erstes Arduino-Programm zum Laufen gebracht. Herzliche Gratulation! Du darfst deinen Erfolg hier gern posten, dann freue ich mich mit dir.

    Das habe ich mittlerweile auch geschafft. Ich bin zwar langsam, aber dafür sicher...

    Gruss Oski


    Nun blinkt es auch unregelmässig. Auch das klappt dank Röbis Instruktion, danke auch hierfür.

    signatur_egos.jpg

    ...auch Nichtraucher können süchtig sein nach Zündhölzern!

    Einmal editiert, zuletzt von egos () aus folgendem Grund: Edit: wieder einen Schritt weiter ...

  • Fragen werde ich gerne beantworten

    Hoi Röbi

    Ich komme zwar wie immer etwas spät, aber im Beitrag #52 meldet dein Arduino-Display, der maximale Speicher sei 32256 bytes. In der neuen Version ist auf dem Display zu lesen, dass nun der maximale Speicher 253'952 bytes belegen dürfe. Hast du in der Zwischenzeit statt des Uno den Mega angeschlossen?

    Gruss Oski

    signatur_egos.jpg

    ...auch Nichtraucher können süchtig sein nach Zündhölzern!