Arduino, Frequenz mittels Encoder einstellen und ausgeben.

  • Hallo Kai, zwei Punkte hätte ich noch, mit der Bitte um Antwort.


    Mit welchem Software-Oszilloskop hast du die Impulse aufgenommen?


    Der zweite Punkt. Es ist in meinem Anwendungsfall nicht praxisgerecht, dass wenn der Arduino Spannungslos geschaltet wird, die Einstellungen verloren gehen.

    Beim Einschalten des Arduino, sollte dieser mit den zuletzt eingestellten Werten starten und die Software zur Ausführung auf die Starttaste, oder auch auf Frequenzänderungen, warten.

    Ich hoffe, die Softwareänderung ist nicht zu aufwendig.


    Grüße, Franz

  • Dann werde ich alles löschen und Arduino neu installieren.

    Die Codeänderung wie von dir in Beitrag #25 habe durchgeführt.


    Es kommt aber die Fehlermeldung:

    113:7: error: 'class Btn::ButtonSL' has no member named 'releaseOn'

    btn.releaseOn();


    Hier noch die Fehlermeldung komplett.

    C:\Users\++++\OneDrive\Dokumente\Arduino\kai3\kai3.ino: In function 'void setup()':

    kai3:110:7: error: 'class Btn::ButtonSL' has no member named 'releaseOn'

    btn.releaseOn();

    ^~~~~~~~~

    exit status 1

    'class Btn::ButtonSL' has no member named 'releaseOn'

  • Nein, es drängt mich nicht. Wichtig ist, dass ich auf meinem PC eine funktionsfähige Arduino IDE installiert habe. Es ist auch kein Problem, Arduino neu zu installieren. Ich bin auf das Ergebnis gespannt, wenn du den Sketch heute Abend mit deiner Arduino Umgebung getestet hast.

  • Wie gesagt, ich werde es heute Abend mal mit meiner Arduino IDE (ebenfalls 1.819) ausprobieren. Üblicherweise benutze ich PlatformIO. Da funktioniert das anstandslos. Sonst hätte ich die Messungen ja auch nicht vornehmen können.


    Wenn es dich so drängt, dann kommentiere die zwei ATOMIC_BLOCK Zeilen aus und schreibe das, was bei den Anweisungen zwischen den geschweiften Klammern steht, in eine eigene Zeile. Dann kommst Du ohne die Header Datei aus.

    Also ICR1 = icr1; und OCR1A = ocr1a;


    Sollte auch funktionieren…. ich habe ATOMIC_BLOCK nur als zusätzliche Sicherheit eingefügt, weil ich mir nicht sicher bin ob sich die 16Bit Werte immer schreiben lassen, ohne Interrupts kurz abzuschalten.

  • Hallo Kai,

    ich habe Arduino1.8 .19 über Windows Store installiert, als ich mir den PC im Frühjahr gekauft habe.

    Ich hatte schon das ganze AVR Verzeichnis durchsucht und auch die Arduino Corefiles. (hardware/ AVR /1.8.5 /cores / Arduino) Es gibt kein Verzeichnis /util mit der atomic.h Datei. Ich muss gestehen, mit dem Windows PC bin ich noch nicht so sehr vertraut, weil ich vorher immer mit einem Macbook PC gearbeitet habe.

  • Achte darauf, den Sketch vollständig zu kopieren. Die atomic.h gehört zu den Arduino Corefiles und sollte vorhanden sein. Es muss nichts nachinstalliert werden.


    Ich verwende die Arduino IDE nicht, aber wenn Software im WokWi-Simulator läuft und sich dort compilieren lässt, sollte sie auch in der Arduino IDE funktionieren. Ich werde das heute Abend mal mit der IDE prüfen.

  • Hallo Kai,

    herzlichen Dank für deine große Mühe und Hilfsbereitschaft!

    Nach dem Hochladen deines Sketch in den Arduino wird die Fehlermeldung "util/atomic.h: No such file or directory" angezeigt.

    Die atomic.h sollte, wenn ich richtig gelesen und verstanden habe, in der AVR LIBc enthalten sein. Wenn ich diese im Arduino-Verzeichnis Libraries installieren will, erscheint der Hinweis, dass keine gültigen Dateien in der AVR LIB sind.

    Grüße, Franz

  • Ich habe mal eine kleine Klasse geschrieben mit der, neben der Frequenz, auch das Tastverhältnis von 0 bis 100% eingestellt werden.

    Das zuvor in diesem Thread besprochene Programm habe ich entsprechend angepasst, dass beide Parameter über den Encoder eingegeben werden können.


    Die Tone Bibliothek wird nicht mehr benötigt.


    Hier mal zwei Beispiele zur Ausgabe:


    10Hz-50.PNG        12Hz-10.PNG


    Links werden 10Hz mit 50% Tastverhältnis ausgegeben, rechts sind es 12Hz mit 15% Tastverhältnis.


    Die Frequenzgenauigkeit hängt von Temperatur und Quarz des µControllers (evtl. auch vom Programm) ab. In meinem Beispiel ist die Frequenz etwas über 0,02 Hertz zu niedrig. Dafür ist der "Fehler" aber recht konstant. Der verwendete Modus ist "phasenkorrektes PWM" (Modus 10 nach ATmega Datenblatt Seite 109). Die Frequenzeingabe ist auf einen 16 Bit unsigned int Wert beschränkt. Somit wäre die maximal einstellbare Frequenz 65,535 KHz.


    Ich habe mich in diesem Beispiel jedoch nur auf den, im vorherigen Programm behandelten, Frequenzbereich beschränkt.


    Es wird der Timer1 des ATmega328P verwendet. Der Ausgabe-Pin ist auf D9 festgelegt. Das hängt mit dem verwendeten Timer-Mode zusammen und kann meines Wissens auch nicht so ohne weiteres geändert werden. Die Klasse funktioniert mit ATmega48A-PA ATmega 88A-PA ATmega 168A-PA und ATmega 328-P µControllern. In der "Arduinowelt" sind das der Nano, Uno und Pro-Mini.


    Sollten Bibliotheken in einem Programm verwendet werden, die ebenfalls den Timer 1 verwenden dann "kracht" es. Funktionen wie millis() oder delay() sind davon aber nicht betroffen. Die werden durch Timer 0 gesteuert.


    Wenn der Encoder nur kurz gedrückt wird (min. 150ms) wechselt die Eingabe zwischen den beiden Parametern Hertz und Tastverhältnis. Das drehen des Encoders ändert den ausgewählten Parameterwert. Gestartet wird die Frequenzausgabe, wenn der Encoder min. 1 Sekunde gedrückt wird.


    Im vorliegenden Beispiel ist die Klassendefinition und das Hauptprogramm in einer Datei. Schöner ist es natürlich, dass in eine Header- und eine Programmdatei aufzuteilen.


    Zum Ausprobieren:

    https://wokwi.com/projects/348767179802411604

  • Ich habe zwar keine Ahnung vom Arduino, aber ein Rechteck Signal mit einer definierten On/Off Zeit lässt sich, sieht man von einem leichten Jitter mal ab, leicht realisieren.

    Ein Timer, der sagen wir mal mit einer Clock-Rate von 0.5mS zählt, löst immer dann einen Interrupt aus, wenn der Zähler den Wert (oder wenn man runter zählt 0) erreicht. In der Interrupt Routine wird dann die neue Zeit gesetzt und man wartet erneut, bis der Zähler das Ende erreicht hat.

    Bei jedem erreichen der Ziel - Zeit wird gleichzeitig das Ausgangspin aktiviert oder deaktiviert.

    Gruss

    Pius

  • Zitat

    Könnte man das auch mit dem Tone Generator programmieren?

    Meines Wissens nicht. Da ist das Tastverhältnis auf 50/50 festgelegt. Zumindest ist es so bei der Beschreibung der Tone Bibliothek beschrieben:

    This is an Arduino Library to produce square-wave of the specified frequency (and 50% duty cycle) on any Arduino pin.


    Zitat

    Ist so eine Verschiebung überhaupt programmierbar?


    Ja ist es.

    Wie das geht, steht im Datenblatt des ATMega328 beschrieben. Da muss Du dich mit der Programmierung von Timern beschäftigen


    Mit "normalen" Arduino Mitteln gibt es analogWrite(). Hier kann das Tastverhältnis einer Frequenz, die jedoch fest vorgegeben ist, verändert werden. Darum hilft das im vorliegenden Fall nicht. Andere Mittel sind mir nicht bekannt. Außer halt, einen Timer direkt über die Register des µControllers zu programmieren.

  • 001.JPG

    Hallo Kai ich wollte dir noch zeigen, wie schön das Signal von dem Generator ist. Auch mit einem Fluke gemessen stimmt die Frequenz genau.

    Ich denke noch an eine Erweiterung.

    Interessant wäre auch z.B. 12Hz = 83 ms Periode.

    Dann ist das Signal 41,5 ms heigth und 41,5ms low.

    Wenn das Signal aber Pro Periode einstellbar z.B 10ms hight und 73ms low sein soll. Könnte man das auch mit dem Tone Generator programmieren?

    Ist so eine Verschiebung überhaupt programmierbar?

    Grüße, Franz

  • Freut mich das es klappt. Allerdings verstehe ich jetzt, beim letzten Schritt nicht wirklich, wo die Schwierigkeiten lagen, das mit der Tone Library und dem Programm zusammen zu bringen. Wenn Du Dir anschaust wo Generator.xxx eingefügt wurde, war das doch eigentlich ganz einfach :).


    Zitat

    Deshalb habe ich in der Codezeile (ich meine Zeile 91)

    const uint8_t PROGMEM tone_pin_to_timer_PGM[] = { 2, 1, 0 };

    const uint8_t PROGMEM tone_pin_to_timer_PGM[] = { 1, 2, 0 };


    OK. Das funktioniert in dem WokWi Simulator nicht, weil man dort nicht an die tone.cpp heran kommt.


    Dann kannst Du aus dem Code die timeStamp Geschichte und doBlink ja auch herauswerfen. Das wird dann nicht mehr benötigt.


  • Kai, du bist der Größte!!

    Es funktioniert super und auch genau.


    Der Tonegenerator ist ToneLibrary-1.7.1

    Dieser kann aber nur Frequenzen >32Hz.


    Deshalb habe ich in der Codezeile (ich meine Zeile 91)

    const uint8_t PROGMEM tone_pin_to_timer_PGM[] = { 2, 1, 0 };

    const uint8_t PROGMEM tone_pin_to_timer_PGM[] = { 1, 2, 0 };


    geändert.


    Herzlichen Dank

    Franz

  • Beim kompilieren werden folgende Fehlermeldungen gelistet:

    169:17: error: variable or field 'askEncoder' declared void

    void askEncoder(EncoderData& data) {

    ^~~~~~~~~~~

    neu:169:17: error: 'EncoderData' was not declared in this scope

    neu:169:30: error: 'data' was not declared in this scope

    void askEncoder(EncoderData& data) {

    ^~~~

    C:\Users\fenge\OneDrive\Dokumente\Arduino\neu\neu.ino:169:30: note: suggested alternative: 'atan'

    void askEncoder(EncoderData& data) {

    ^~~~

    atan

    neu:74:2: error: expected unqualified-id before '/' token

    */

    ^

    neu:74:2: error: expected constructor, destructor, or type conversion before '/' token

    neu:89:16: error: redefinition of 'constexpr const byte I2C_ADDR'

    constexpr byte I2C_ADDR {0x27};

    ^~~~~~~~

    C:\Users\fenge\OneDrive\Dokumente\Arduino\neu\neu.ino:18:16: note: 'constexpr const byte I2C_ADDR' previously defined here

    constexpr byte I2C_ADDR {0x27};

    ^~~~~~~~

    neu:90:16: error: redefinition of 'constexpr const byte LCD_COLUMNS'

    constexpr byte LCD_COLUMNS {16};

    ^~~~~~~~~~~

    C:\Users\fenge\OneDrive\Dokumente\Arduino\neu\neu.ino:19:16: note: 'constexpr const byte LCD_COLUMNS' previously defined here

    constexpr byte LCD_COLUMNS {16};

    ^~~~~~~~~~~

    neu:91:16: error: redefinition of 'constexpr const byte LCD_LINES'

    constexpr byte LCD_LINES {2};

    ^~~~~~~~~

    C:\Users\fenge\OneDrive\Dokumente\Arduino\neu\neu.ino:20:16: note: 'constexpr const byte LCD_LINES' previously defined here

    constexpr byte LCD_LINES {2};

    ^~~~~~~~~

    neu:101:23: error: redefinition of 'LiquidCrystal_I2C lcd'

    LiquidCrystal_I2C lcd(I2C_ADDR, LCD_COLUMNS, LCD_LINES);

    ^~~~~~~~

    C:\Users\fenge\OneDrive\Dokumente\Arduino\neu\neu.ino:21:19: note: 'LiquidCrystal_I2C lcd' previously declared here

    LiquidCrystal_I2C lcd(I2C_ADDR, LCD_COLUMNS, LCD_LINES);

    ^~~

    neu:102:1: error: 'RotaryEncoder' does not name a type; did you mean 'RotaryEncoder_h'?

    RotaryEncoder encoder(pin_in1, pin_in2, RotaryEncoder::LatchMode::FOUR0);

    ^~~~~~~~~~~~~

    RotaryEncoder_h

    neu:106:6: error: redefinition of 'Tone Generator'

    Tone Generator;

    ^~~~~~~~~

    C:\Users\fenge\OneDrive\Dokumente\Arduino\neu\neu.ino:22:6: note: 'Tone Generator' previously declared here

    Tone Generator;

    ^~~~~~~~~

    C:\Users\fenge\OneDrive\Dokumente\Arduino\neu\neu.ino: In function 'void setup()':

    neu:110:6: error: redefinition of 'void setup()'

    void setup()

    ^~~~~

    C:\Users\fenge\OneDrive\Dokumente\Arduino\neu\neu.ino:23:6: note: 'void setup()' previously defined here

    void setup(){

    ^~~~~

    C:\Users\fenge\OneDrive\Dokumente\Arduino\neu\neu.ino: In function 'void loop()':

    neu:123:6: error: redefinition of 'void loop()'

    void loop()

    ^~~~

    C:\Users\fenge\OneDrive\Dokumente\Arduino\neu\neu.ino:32:6: note: 'void loop()' previously defined here

    void loop(){

    ^~~~

    neu:129:3: error: 'askEncoder' was not declared in this scope

    askEncoder(encData);

    ^~~~~~~~~~

    C:\Users\fenge\OneDrive\Dokumente\Arduino\neu\neu.ino: In function 'void askEncoder(EncoderData&)':

    neu:170:3: error: 'encoder' was not declared in this scope

    encoder.tick();

    ^~~~~~~

    C:\Users\fenge\OneDrive\Dokumente\Arduino\neu\neu.ino:170:3: note: suggested alternative: 'askEncoder'

    encoder.tick();

    ^~~~~~~

    askEncoder

    exit status 1

    variable or field 'askEncoder' declared void

  • Also ich habe das in WokWi jetzt zusammengefügt. Habe auch Deinen unten geposteten Sketch da laufen lassen. Da blinkt jedoch nichts. Nur Dauerleuchten.

    Kann aber auch an der Simulation liegen. Oder an der verwendeten Tone Lib.


    Jedenfalls kannst Du Dir den Code da abholen. Wenn es nicht funktioniert musst du halt weiter probieren..