Ist das 1,3 Zoll OLED-Display für mein Projekt nicht geeignet!?!

Moin.
Ich habe ein Problem, mit dem ich mich gerne an euch wenden und euch um Rat fragen möchte. Für eure Anteilnahme bedanke ich mich im Voraus bei euch.
Folgendes Problem ist entstanden und ich weiß dafür momentan keine Lösung!

Projekt-Aufgabe:
Mein Vorhaben ist es mit einem Mikrocontroller Impuls zu zählen und diese auf einem 1.3 Zoll OLED-Display auszugeben. Ein Impuls hat dabei die Periodendauer von 5 mSek, sprich 200 Hz. Dabei habe ich den Impuls in einen HIGH-Anteil von 500 uSek und ein LOW-Anteil von 4500 uSek unterteilt.

Projekt-Ablauf: Schritt 1
Zu Beginn meines Projektes habe ich erst einmal mit einem DUE den Impuls von 5 mSek (HIGH-Anteil 500 uSek, LOW-Anteil 4500 uSek) erzeugt und von einem UNO verarbeitet. Zur Verarbeitung habe ich die Funktion digitalRead() verwendet. Zur Kontrolle habe ich mein Oszi eingesetzt. Beide Impulse wurden mir sehr schön angezeigt (Sende-Impuls = Empfang-Impuls) und ich habe mich dann der Zählung und Darstellung gewidmet.

Projekt-Ablauf: Schritt 2
Für die Implementierung des OLED-Displays habe ich zuerst die Bibliothek u8g2 genutzt. Ich habe also die Impulse (anhand der Funktion digitalRead()) zählen lassen und den Zählvorgang auf dem Display ausgegeben. Den Vorgang habe ich mir dann auf dem Oszi angeschaut. Mir ist dabei aufgefallen, dass mit zunehmender Vorkommastelle (10, 100, 1.000, 10.000), als beim hoch Zählen, der Impuls des UNOs auf dem Ozsi zugenommen hat. D.h. dass sich der HIGH-Anteil des Impulses auf dem Oszi von den ursprünglichen HIGH-Anteil 500 uSek um einige hunderte Mikrosekunden zugenommen hat. Umso größer die Zahl die dargestellt werden sollte wurde, um so länger dauerte der Impuls auf einmal. Es war dann so, dass bei der Darstellung der Zentausender der HIGH-Anteil des Impulses fast der gesamten Impulsdauer von 5 mSek entsprach.
Das machte mich an der Stelle sehr stutzig, da ich auf dem OLED-Display nur den Zählvorgang dargestellt hatte und eigentlich noch vorhatte zusätzlichen Text ect. mit darstellen zu wollen. Und dann ist mir die Idee eingefallen den Zählvorgang nicht einmal, sondern gleich 3 mal auf dem Display ausgeben zu lassen. Zum Vergleich habe ich ein 2tes OLED-Display mit nur einen Zählvorgang gebaut. Das Ergebnis war, dass das OLED mit den 3 Zählvorgängen die Zählung langsamer lief, als bei dem mit dem einen Zählvorgang. Das ließ sich auch auf dem Oszi begutachten. Zu sehen war ein dauerhaftes HIGH-Signal, wobei sich dazwischen immer wieder auch eine steigende und fallende Flanke mischte.
Also ich das gesehen hab, musste ich mir natürlich über ein neues Konzept Gedanken machen. Als Lösung erschien es mir geistreich den MEGA anstelle eines UNOs zu verwenden. Ich hab angenommen, dass die höhere Taktfrequenz des MEGA das OLED-Display schneller ansteuern würde. Das Ergebnis war aber das selbe wie zuvor!

Projekt-Ablauf: Schritt 3
Meine nächste Überlegung war der Einsatz von Interrupts. Ich habe also eine ISR dazu benutz, um die eingehenden Impulse vom DUE am MEGA zu zählen. Auch hier habe ich den Versuch erst einmal ohne Ansteuerung des OLEDs und mit Überprüfung meines Oszis gemacht. Das klappte auf anhieb.
Erst als ich dann das OLED angesteuert habe entstand eine Verzerrung des Empfang-Impulses. Ähnlich, aber nicht ganz gleich wie in Schritt 2 beschrieben verlängerte sich der HIGH-Anteil des Impulses um einiges.

Projekt-Ablauf: Schritt4
Nachdem mir jetzt noch mal dasselbe Problem entstanden ist, habe ich bei meiner Recherche bin ich auf die Bibliothek Adafuit_SSD1306 aufmerksam geworden. Mit der habe ich Schritt 3 wiederholt. Mit dem Ergebnis, dass ich nur zur Darstellung der Zählung mindestens 38 mSek benötige. Sofern noch andere Zeichen dazu kommen bis zu 48 mSek. Und auch hier kommt es zu einer Verzerrung des Empfangenen Impulses wie zuvor beschrieben.

Ich hatte aber auch die Idee das OLED-Display zu einem späteren Zeitpunkt (4 mal pro Sekunde) mit einen Timer zu refreshen. Das hat aber dazu geführt, dass die Darstellung der Zählung nicht mehr sauber ablief, sondern sprunghaft.
Es scheint mir so, dass der Mikrocontroller mit der Ausgabe des OLED-Display in etwa so wie bei der delay()-Funktion blockiert wird. Wobei ich anmerken muss, dass der Einsatz von Interrupts schon zu Unterbrechungen geführt hat. Diese waren aber sehr unregelmäßig und viel zu lang. Und bei der Funktion digitalRead() war es eine durchgängige Blockierung, also ohne zufälligen Wechsel von High auf Low und umgekehrt.
Zu guter Letzt sei erwähnt, dass ich versucht habe die Ansteuerung des OLED-Display an unterschiedlichen Programmzeilen auszuführen. Die letzte Sache, die mir dazu eingefallen ist, ist die Nutzung von SPI, anstatt wie bis jetzt I2C.
Eine weiter Überlegen wäre es ein LCD, anstatt eines OLED-Displays einzusetzen. Ich mache mir da aber nicht die große Hoffnung, dass dann das Problem mit der Verzögerung durch die Ansteuerung des Displays nicht entstehen wird.
Wie schon erwähnt vermute ich, dass das OLED-Display eine zu große „Trägheit“ besitzt und der Mikrocontroller dadurch „ausgebremst“ wird. Was mich aber verwundert ist, dass das OLED-Display eine Refresh-Rate von 200 Hz haben soll. Laut Datenblatt soll das OLED-Display einen 400 KHz schnellen I2C-Bus haben…
So sieht der Stand der Dinge momentan bei mir aus. Über jeden konstruktiven Tipp/Kritik würde ich mich sehr freuen. Und um die Frage vielleicht vor weg zu nehmen, es soll nach Möglichkeit das OLED-Display verwendet werden. Als Alternative hätte ich auch ein HMI-Display in meinem Bestand. :wink:

Ich freue mich auf eure Rückmeldung.

Gruß
Sebastian

sebastianhamburg2020:
Moin.

Moin.

sebastianhamburg2020:
... die höhere Taktfrequenz des MEGA ...

UNO und Mega2560 haben beide 16 MHz.

sebastianhamburg2020:
Ich freue mich auf eure Rückmeldung.

Schmeiß doch mal das Programm zur Takterzeugung und -erkennung mit Interrupt in die Runde.

sebastianhamburg2020:
D.h. dass sich der HIGH-Anteil des Impulses auf dem Oszi von den ursprünglichen HIGH-Anteil 500 uSek um einige hunderte Mikrosekunden zugenommen hat. Umso größer die Zahl die dargestellt werden sollte wurde, um so länger dauerte der Impuls auf einmal.

Also: Der Impuls ist IMMER mit selber Torzeit vom DUE gekommen?
Hast Du einen definierten Zustand?

Ich will Deine Schaltung sehen!
Schaltbild UND Foto vom Aufbau.

Moin @noiasca, @agmue, @my_xy_projekt,

danke für eine Anteilnahme an meinem Problem!

@noiasca
Ich werde auf jeden Fall die Tage das ganze mit einem LCD vergleichen.
Ich habe auch ein SPI-OLED-Display da und werde es vor dem LCD mit dem noch mal probieen. Das hate ich zwar schon, konnte es aber bis jetzt nicht zum Laufen bringen.
Genau wie du meinst “Versuch macht klug”. :wink:

@agmue
Du hast natürlch recht und ich hab heute en MEGA durch ein 2ten DUE erstezt. Leider ist das Problem immer noch da. ;(

@my_xy_projekt
Ich weiß jetzt nicht ganz, was ein Schaltungsaufbau-Foto und Schaltbild bringen soll. Es funktioniert ja alles tatdelos. Das OLED tut was es tun soll und auch die Zählung. Aber nicht, wenn beides zusammen läuft.

kann ich hier Bild nicht so einfach anfügen?

nicht im Quick Reply. Aber wenn du auf Reply gehst gibts ein
Attachments and other options

Ich habe auch ein SPI-OLED-Display

da würde ich nicht viel erwarten, so ein OLED überträgt einfach viele Daten, da soll ein 16x2 "schneller" sein.

UNO und Mega2560 haben beide 16 MHz.

Wobei das Problem eigentlich noch schlimmer ist....
Durch den breiteren Adressbus benötigt der Mega so manchen Takt mehr, als der UNO für die gleiche Operation.

Zur Verarbeitung habe ich die Funktion digitalRead() verwendet.

Das geht mit direkten Portzugriffen sicherlich schneller.
Wird das Problem aber auch nicht lösen.

Vorschlag:
Verwende die Fähigkeiten der eingebauten Timer.

als beim hoch Zählen, der Impuls des UNOs auf dem Ozsi zugenommen hat. D.h. dass sich der HIGH-Anteil des Impulses auf dem Oszi von den ursprünglichen HIGH-Anteil 500 uSek um einige hunderte Mikrosekunden zugenommen hat.

Das kann nicht sein. Ein Standart - Eingang kann das Signal nicht beeinflussen. Es gibt sicher Grenzfälle oder Fehlbeschaltungen wo dies der Fall ist aber normalerweise nicht. Ich nehme schon an daß du den UNO-Eingang richtig am DUE-Ausgang angeschlossen hast und die Massen verbunden hast.

Es war dann so, dass bei der Darstellung der Zentausender der HIGH-Anteil des Impulses fast der gesamten Impulsdau er von 5 mSek entsprach.

Das glaube ich nicht.
Das Taktsignal ist sicher immer das gleiche mit den gleichen Zeiten. Durch eine länger dauende Ausgabe des Ergebnisses dauert die Zeit zwischen 2 Abtastungen länger und darum erscheint die High Dauer länger weil Du einfach später schaust ob dieser LOW geworden ist.

Die Zählung der Impulse sollte via Interrupt erfolgen. Die anderen Programmteile dürfen dabei den Interrupr nicht blockieren bzw ausschalten. Ich weiß nicht was die Display-Bibliothek macht. Als Beispiel führe ich die WS2812- Ansteuerung an. Die schaltet wegen der Kritizität der Zeiten bei der Datenübertragung alle Interrupts ab.

Grüße Uwe

Grüße Uwe

Hier könnt ihr den erzeugen Impuls (CH1, gelb) des DUE sehen. Der Tastkopf befindet sich auf dem DUE. Das macht zwar keinen großen Unterschied, ich wollts nur erwähnt haben. Ich messe diesen Imupuls, indem ich "gleichzeitig" 2 Pins digitalWrite HIGH setzte und dann auf LOW.

Und auf CH2 seht ihr dem Empfangs-Impuls auf dem 2ten DUE (CH2, blau). Hier mache ich das so, dass der DUE ein HIGH-Signal erzeugt, sofern ein HIGH per digitalRead erkannt hat.

Wie ihr sehen könnt, sind beide Impulse von Zeitverhalten nahezu identisch.

Das OLED ist im Programm-Code auskommentiert. es findet als keine "Ansteuerung" statt.

Jetzt kann man die Zählung sehen. Die Zählung befindet sich zwischen 0 und 100 Impulsen. Hier wird also das OLED "Angesteuert".

Man sieht also, dass sich der HIGH-Anteil des Impuls des 2ten DUE automatisch durch die Ansteuerung des OLEDs verlängert hat. Hier habe ich die digitalRead()-Funktion eingesetzt und noch keine Interrupts.

Jetzt kann man die Zählung sehen. Die Zählung befindet sich zwischen 100 und 1.000 Impulsen. Hier wird also das OLED "Angesteuert".

Man sieht also, dass sich der HIGH-Anteil des Impuls des 2ten DUE automatisch durch die Ansteuerung des OLEDs verlängert hat. Hier habe ich die digitalRead()-Funktion eingesetzt und noch keine Interrupts.

DIE GESAMTLÄNGE DES IMPULSES BLEIBT IMMER GLEICH

Jetzt kann man die Zählung sehen. Die Zählung befindet sich zwischen 1.000 und 1.0000 Impulsen. Hier wird also das OLED "Angesteuert".

Man sieht also, dass sich der HIGH-Anteil des Impuls des 2ten DUE automatisch durch die Ansteuerung des OLEDs verlängert hat. Hier habe ich die digitalRead()-Funktion eingesetzt und noch keine Interrupts.

DIE GESAMTLÄNGE DES IMPULSES BLEIBT IMMER GLEICH

Jetzt kann man die Zählung sehen. Die Zählung befindet sich zwischen 100 und 1.000 Impulsen. Hier wird also das OLED "Angesteuert".

Man sieht also, dass sich der HIGH-Anteil des Impuls des 2ten DUE automatisch durch die Ansteuerung des OLEDs verlängert hat.

Hier habe ich mit Interrupts die Impuls zählen lassen.

Beim letzten Oszi-Plot hab ich Intterupts benutze und da könnt ihr sehen, wie krass der Empfangsimpuls durch die Zählung "verzerrt" wird. Um Gegensatz zu digitalRead findet bei Interrupts immer so eine Verzerung statt. Also kein Unterschied ob man Zahlen von 0-100, 100-1.000, 1.000-10.000er auf dem OLED ausgeben will.

Ausserdem seht ihr da nur ein Plot. Die Impulsänge fängt an sich permanent zu verändern. Ich hönnte euch noch 100 Plots hier senden und jedes mal würde das Signal von CH2 anders angezeigt werden.

ABER:
Es wird beim OLED die Zahlen immer gleich hoch gezählt. Egal ob ich digitaRead, oder Interrupts nutze. Das funktioniert also. Ob der 2te DUE die Impuls richtig zählt, kann ich nicht genau sagen.

Das Code in Codetags gehört, konntest Du schon mal.

Gruß Tommy

Programm-Code: Empfangs-DUE mit dem die Impulse gezählt und das OLED angesteuert wird, hier durch Interrupts

 // MEGA

// OLED 
#include <Arduino.h>
#include <U8x8lib.h>
#include <Wire.h>
U8X8_SSD1306_128X64_NONAME_HW_I2C u8x8(U8X8_PIN_NONE);  

// INTERRUPT
const byte PIN13          = 13;   // Setze den Pin für die LED auf 13
const byte INTERRUPT_PIN2 =  2;   // PIN2 für UNO, MEGA - hier Input von DUE-Impuls
volatile byte       state = HIGH; // Toggel-Variable
unsigned volatile int   i = 0;


// Voreinstellung
void setup() {
    pinMode(PIN13,                OUTPUT);  // Lege den Pin für die LED als Outputpin fest
    pinMode(INTERRUPT_PIN2, INPUT_PULLUP);  // Lege den Interruptpin als Inputpin mit Pullupwiderstand fest
    
    // OLED
    u8x8.begin();
    u8x8.setFont(u8x8_font_chroma48medium8_r); 
        
    // INTERRUPT-SERVICE-METHODE
    // Interrupt-Pin = 2, Funktion _toggel aufrufen, Funktion aufrufen, bei Flankenwechsel (LOW->HIGH u- HIGH->LOW)
    attachInterrupt(digitalPinToInterrupt(INTERRUPT_PIN2), _toggel, CHANGE);
}


// Hauptprogramm
void loop() {
    // Pin toggeln
    digitalWrite(PIN13, state);
    // OLED-Impulszählung-Ausgabe
    u8x8.setCursor(0,0);  //(X-Achse, Y-Achse)
    u8x8.print(i); 
}


// ISR-Methode
void _toggel() {
    // Invertiere den Status
    state = !state;
    i++;
}

Nur mal so als Idee:
Mal versucht mit einem Widerstand - so 2k - Wert unkritisch - den Pegel des PIN auf GND zu ziehen?

[edit] da noch nichts weiter kam:

  attachInterrupt (digitalPinToInterrupt (INTERRUPT_PIN2), _toggel, CHANGE);

warum CHANGE? Reicht Dir nicht eine Flanke?
Wenn Du schon CHANGE verwendest, wäre meine Idee zu debuggen mit einem kleinen Hilfsarray
volatile unsigned long millismerken[100]
und bei jeder ausgelösten ISR die millis in das array i.V. mit i++ zu schreiben.
HINWEIS: Dann drauf achten, das i nicht grösser wird.....

Schlussendlich die Werte aus dem Array in Zeiten von einem change zum nächsten umrechnen.
Usw.

Alternative wäre das digitalWrite (PIN13, state); mal aus dem loop() ins ISR nehmen.
Dann muss sich das Verhalten ändern.

Programm-Code: Empfangs-DUE mit dem die Impulse gezählt und das OLED angesteuert wird, mit der Funktion digitalRead()

 // MEGA

// OLED 
#include <Arduino.h>
#include <U8x8lib.h>
#include <Wire.h>
U8X8_SSD1306_128X64_NONAME_HW_I2C u8x8(U8X8_PIN_NONE);   

#define PIN13 13 // Input-Anschluss von DUE
#define PIN10 10 // Output-Anschluss für Oszi

byte         var   = 0; // Impuls-Abfrage 
unsigned int i     = 0; // Impuls-Zählung
byte         state = 0; // Impuls-toggel  


// Voreinstellungen
void setup() {
    pinMode(PIN13, INPUT);
    pinMode(PIN10, OUTPUT);
    // OLED
    u8x8.begin();
    u8x8.setFont(u8x8_font_chroma48medium8_r);     
    Serial.begin(9600); 
}


// Hauptprogramm
void loop() {
    // Impuls-Zählung
    var = digitalRead(PIN13);
    if(var == 1) {
        i++;
        digitalWrite(PIN10, HIGH);
        // OLED-Ausgabe MUSS!!!!! hier, da sonst die Impulse nicht korrekt
        // OLED-Ausgabe erzeugt eine Programmverzögerung von  
        //u8x8.setCursor(0,0);
        //u8x8.print(i);    
        //Serial.println(i);          
    }
    else {
        digitalWrite(PIN10, LOW);
    }
}

Wie jetzt? hast Du einen DUE und einen UNO oder zwei DUE? ( zum Glück schreibe ich nicht auf italienisch: un DUE e un UNO o due DUE).

Der blaue Kanal ist ein Signal nach der Verarbeitung des Progamms auf dem zweiten Controller?
Du schriebst aber daß das Primäre Signal (gelb) sich in der Taktverhältnis ändere und nicht ein anderes Signal.

Ja das Blaue signal ändert seine Zeiten weil die Verarbeitung im Sketch des zweiten Controllers je nach Stellen der Zahl länger braucht.
Ein Grafische Display ist da sicher nicht die richtige Wahl weil diese mehr Daten übertragen werden müssen als ein alfanumerisches.
Am schnellsten wird ein MAX7219 mit 8 Stelligen 7-Segmentanzeige sein. Der braucht nur 8 Byte Bit und kann mit 20Mhz angesteuert werden also weniger als 8µS.

Grüße Uwe

[EDIT] Byte- Bit korrigiert[/EDIT]

sebastianhamburg2020:

// Hauptprogramm

void loop() {
    // Impuls-Zählung
    var = digitalRead(PIN13);
    if(var == 1) {
        i++;
        digitalWrite(PIN10, HIGH);
        // OLED-Ausgabe MUSS!!! hier, da sonst die Impulse nicht korrekt
        // OLED-Ausgabe erzeugt eine Programmverzögerung von 
        //u8x8.setCursor(0,0);
        //u8x8.print(i);   
        //Serial.println(i);         
    }
    else {
        digitalWrite(PIN10, LOW);
    }
}

NEIN!
Ich will, das Du den Code aus

so verwendest, das Du dort in der ISR den OutputPIN setzt und nicht im loop().

Zudem schliesse ich mich Uwe an - Foto vom Aufbau um Missverständnisse auszuräumen?

[edit]
Was macht der Code?

// MEGA

// OLED
#include <Arduino.h>
#include <U8x8lib.h>
#include <Wire.h>
U8X8_SSD1306_128X64_NONAME_HW_I2C u8x8 (U8X8_PIN_NONE);

// INTERRUPT
const byte PIN13          = 13;   // Setze den Pin für die LED auf 13
const byte INTERRUPT_PIN2 =  2;   // PIN2 für UNO, MEGA - hier Input von DUE-Impuls
volatile byte       state = HIGH; // Toggel-Variable
unsigned volatile int   i = 0;

volatile unsigned long[100] = {0};

// Voreinstellung
void setup()
{
  pinMode (PIN13,                OUTPUT); // Lege den Pin für die LED als Outputpin fest
  pinMode (INTERRUPT_PIN2, INPUT_PULLUP); // Lege den Interruptpin als Inputpin mit Pullupwiderstand fest
  // OLED
  u8x8.begin();
  u8x8.setFont (u8x8_font_chroma48medium8_r);
  // INTERRUPT-SERVICE-METHODE
  // Interrupt-Pin = 2, Funktion _toggel aufrufen, Funktion aufrufen, bei Flankenwechsel (LOW->HIGH u- HIGH->LOW)
  attachInterrupt (digitalPinToInterrupt (INTERRUPT_PIN2), _toggel, CHANGE);
}


// Hauptprogramm
void loop()
{
  // OLED-Impulszählung-Ausgabe
  u8x8.setCursor (0, 0); //(X-Achse, Y-Achse)
  u8x8.print (i);
}


// ISR-Methode
void _toggel()
{
  // Invertiere den Status
  state = !state;
  i++;
  // Pin toggeln
  digitalWrite (PIN13, state);
}