lcd.begin vs. Serial.print !?!?

Guten Tag

Ich arbeite gerade an einem Program für eine Miniatur-Hochregallagersteuerung - das Programm ist soweit auch ok und arbeitet die Befehle für die Ansteuerung der X/Y-Achsen-Schrittmotoren schön ab ... soweit so gut.
Jetzt wollte ich jedoch aus Gründen der Übersichtlichkeit die aktuelle Position meiner Be-und Entladeeinheit vom Seriellen Monitor auf ein LCD-Display umlagern ( Typ: YwRobot Arduino LCM1602 IIC V1 - 4*20 ), was jedoch den Sketch nicht ganz zu passen scheint.

Ich habe im Setup-Teil eine Funktion eigebaut, das die Be-und Entladeeinheit auf die Ausgangsposition gefahren werden soll und sobald dies erreicht ist via Serial.print ein "OK" zurückgibt.
Füge ich jetzt jedoch das Display hinzu und initialisiere es mit lcd.begin so kommt folgendes Schema zu stande:

  1. Aufruf des Seriellen Monitors: Hintergrundbeleuchtung geht aus obwohl das net im Code is --> LCD-Display wird aktualisiert - es kommt jedoch keine "OK"-Meldung via Serial.print
  2. Aufruf : Hintergrundbeleuchtung bleibt an --> LCD-Display wird nicht aktualisiert - dafür bekomm ich die "OK"-Meldungen
  3. Aufruf: wieder wie 1. usw.

Kann da beim besten Willen keine Logig sehen warum abwechselnd der Serielle Monitor und dann das LCD-Display funktioniert ... hoffe aber jemand hier, denn mir gehen die Ideen aus.

Zum Sketch: Mainsketch:

// Importieren der Bibiotheken für Ethernet + I²C
#include <SPI.h>
#include <Ethernet.h>
#include "TimerOne.h"
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

// ========================================================================================================
// ========================================================================================================

// Network-Einstellungen
  // MAC-Adresse (Arduino-Aufkleber oder selbst erfinden)
  byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };  
  // IP-Adresse unter der der Arduino im Netz als Server fungieren soll
  byte ip[] = { 192, 168, 1, 200 }; 
  // Sub-Net-Einstellung
  byte subnet[] = { 255, 255, 255, 0 };
  // Gateway-Einstellungen
  // byte gateway[] = { 192, 168, 1, 1};
  // Port der für die Ethernet-Kommunikation genutzt wird
  EthernetServer server(5555);

// I2C-Display
  LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);

// i/O-Ports
  // Motor 1
  int M1_S = 2;
  int M1_IO = 3;
  int M1_LR = 4;
  int M1_HV = 5;
  // Motor 2
  int M2_S = 6;
  int M2_IO = 7;
  int M2_LR = 8;
  int M2_HV = 9;
  // Motor 3
  int M3_IO = 14;
  int M3_LR = 15;
  int M3_HV = 16;
  // Allgemein
  int MA_R = 17;
  // Endschalter
  int X_Start = 22;
  int X_End = 23;
  int Y_Start = 24;
  int Y_End = 25;
  int Z_Start = 26;
  int Z_End = 27;

  
// Variablen
  // Ethernetübertragung
  #define SOP '<'
  #define EOP '>'
  boolean Etherstarted = false;
  boolean Etherended = false;
  char EtherData[80];
  byte Etherindex;
  // USB-Übertragung
  boolean USBstarted = false;
  boolean USBended = false;
  char USBData[80];
  byte USBindex;

  // Motorvariablen
  boolean StatusM1 = false;
  boolean RichtungM1 = false;
  boolean ModusM1 = false;
  boolean StatusM2 = false;
  boolean RichtungM2 = false;
  boolean ModusM2 = false;
  boolean StatusM3 = false;
  boolean RichtungM3 = false;
  int ISTPositionX = 0;
  int ISTPositionY = 0;
  int ISTPositionZ = 0;
  int SOLLPositionX = 0;
  int SOLLPositionY = 0;
  int SOLLPositionZ = 0;
  
  // Timer für X/Y/Z-Parallellauf
  int timerX1 = 5000; // 1ms = 1000
  // Freigabe für Z-Achse
  boolean Z_sperre = false;
  // Be-/Entladeeinheit beladen?
  boolean Ladung = false;

// ********************************************************************************************************


void setup()
{
  // Netzwerk-Kommunikationen starten
    // Ethernet initialisieren
    Ethernet.begin(mac, ip, subnet); //gateway
    server.begin();
    
    // Serielle Schnittstelle initialisieren
    Serial.begin(115200);
    
    // I2C-Display initialisieren
   lcd.begin(20,4);
////    lcd.noBacklight();
////    delay(100);
    lcd.backlight();
    lcd.setCursor(2,0);
    lcd.print("Automatisiertes");
    lcd.setCursor(2,1);
    lcd.print("Hochregal-Lager");
    lcd.setCursor(4,4);
    lcd.print("Version 0.6");
    delay(1000);
    
//        // LCD-Display vorbereiten
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.write("IST-Wert  X = ");
    lcd.setCursor(0,1);
    lcd.write("SOLL-Wert X = ");
    lcd.setCursor(0,2);
    lcd.write("IST-Wert  Y = ");
    lcd.setCursor(0,3);
    lcd.write("SOLL-Wert Y = ");
    
  // Interupt inizialisieren
  Timer1.initialize(timerX1);
  Timer1.attachInterrupt(XY_Controll);
  
  // I/O-Ports initialisieren
    // LED initialisieren
    pinMode(M1_S, OUTPUT);
    pinMode(M1_IO, OUTPUT);
    pinMode(M1_LR, OUTPUT);
    pinMode(M1_HV, OUTPUT);
    pinMode(MA_R, OUTPUT);
    pinMode(M2_S, OUTPUT);
    pinMode(M2_IO, OUTPUT);
    pinMode(M2_LR, OUTPUT);
    pinMode(M2_HV, OUTPUT);
    pinMode(M3_IO, OUTPUT);
    pinMode(M3_LR, OUTPUT);
    pinMode(X_Start, INPUT);
    pinMode(X_End, INPUT);
    pinMode(Y_Start, INPUT);
    pinMode(Y_End, INPUT);
    pinMode(Z_Start, INPUT);
    pinMode(Z_End, INPUT);
    
    digitalWrite(MA_R, HIGH);
    digitalWrite(M1_LR, HIGH);
    digitalWrite(M1_HV, HIGH);
    digitalWrite(M2_LR, HIGH);
    digitalWrite(M2_HV, HIGH);
    digitalWrite(M3_LR, HIGH);
    
    // Be-/Entladeeinheit auf Null-Punkt fahren
    Safetyfirst();
    

}
// ********************************************************************************************************


void loop()
{
   // Abfrage auf Ethernet-Kommunikation
   EthernetInput();
   // Abfrage auf USB-Kommunikation
   USBInput();
   // Steuerung abarbeiten
   intelligentControll();
}

Wenn auch die Tabs mit den ganzen Unterfunktionen sinnvoll wären müsste ich das Prog mal zusammen hochladen ... is doch mittlerweile etwas größer :grin:

Gruß Ben

EDIT: Ich habe eben nochmal den funktionierenden Beispiel-Sketch für das Display gesucht und in diesem einen Serial.print-Befehl eingebaut ... da funktioniert es ohne Probleme das beides gleichzeitig ausgeführt wird ... ich werd jetzt mal versuchen, ob ich in meinem Sketch den Fehler nach der "Eins nach dem anderen Auskommentieren und sehen obs jetzt geht"-Methode eingrenzen kann.

EDIT 2:
Es ist nicht "lcd.begin vs. Serial.print" sondern Timer1 vs. lcd.begin & Serial.print.
Sobald ich die Initialisierung des Timer1 auskommentiere geht lcd.begin und serial.print ohne Probleme.
Frage is jetzt nur was macht der Timer1 das dieser Konflikt entsteht und insbesondere wie behebe ich das, den der Timer1 steuert den Takt meiner Schrittmotoren ...

Auf was für einem Controller soll das Programm laufen?

Lasse Dir mal am Ende der setup-Funktion den freien RAM-Speicher ausgeben/anzeigen!

Falls es um einen Controller mit 2 KB RAM geht, würde ich darauf tippen, dass bei dem ganzen Plumpatsch an verwendeten Libraries dem Controller der RAM ausgeht, sprich, dass Dein Sketch mehr RAM-Speicher verbrauchen würde als der Controller überhaupt eingebaut hat.

Der Sketch läuft auf einem Arduino Mega 2560 R3

Der Sketch den ich zum auslesen des Restrams gefunden habe

void free_dump() {

      uint8_t *heapptr;
      uint8_t *stackptr;

      stackptr = (uint8_t *)malloc(4);   // use stackptr temporarily
      heapptr = stackptr;                // save value of heap pointer
      free(stackptr);                    // free up the memory again (sets stackptr to 0)
      stackptr =  (uint8_t *)(SP);       // save value of stack pointer


      // print("HP: ");
      Serial.print(PSTR("HP: "));
      Serial.println((int) heapptr, HEX);

      // print("SP: ");
      Serial.print(PSTR("SP: "));
      Serial.println((int) stackptr, HEX);

      // print("Free: ");
      Serial.print(PSTR("Free: "));
      Serial.println((int) stackptr - (int) heapptr, HEX);
      Serial.println();
}

gibt mir folgendes raus:
QyQ9CA
QyQ21DA
1810

damit anfangen kann ich aber zugegeben nichts :blush:

Gruß Ben

Scorch:
damit anfangen kann ich aber zugegeben nichts :blush:

Eine Funktion zu verwenden, die selbst nochmal 4 Bytes RAM zusätzlich anfordert, wenn bereits der Verdacht des RAM-Speichermangels besteht, läßt das Programm noch mehr durchdrehen als sonst schon.

Nimm die Funktion:

int freeRam () {
  extern int __heap_start, *__brkval; 
  int v; 
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); 
}

und rufe diese auf mit:

Serial.println(freeRam () );

Und zwar möglichst auch mal in einer Programmversion mit weniger Plumpatsch, die gerade noch läuft.

Jo da haste natürlich recht ... nicht dran gedacht.

komplett auskommentierter Timer1: 6177
komplett auskommentiertes LCD: 6549

beide aktiv (in dem einen Zustand wo er den Seriellen Monitor nutzt): 6172
beide aktiv (in dem Zustand wo das Display aktualisiert wird via lcd.print): 6232

Fürchte der Timer1 is auch nicht wirklich das Problem, sondern das ich in der void die ich durch diesen Aufrufe die lcd.print-Befehle nutze ... Kommentiere ich nur das aus klapps nämlich.
Am Ram scheint es jedoch nicht zu liegen, denn der is innerhalb der timer-void bei rund 6100 ob Auskommentiert oder nicht.
Vermute deswegen mal das die Libraries nicht dazu gedacht sind ineinander genutzt zu werden.

Hab die Aktualisierung der Werte jetzt mal in die Main-Loop gepackt und es klappt sowohl der Serielle Monitor als auch das Dislpay!!!

THX jurs

Gruß Ben

Scorch:
Am Ram scheint es jedoch nicht zu liegen

Stimmt, denn Du scheinst einen MEGA und keinen UNO oder vergleichbares zu verwenden.
RAM ist genug vorhanden.

Hallo,

wie wird in dem funktionierenden Beispiel das Display initialisiert? Es scheint verschiedene I2C-Adapter mit etwas anderen Initialisierungen zu geben.

Das Beispielprogramm hatte ich von:
arduino-info - LCD-Blue-I2C (2. Skript von oben)
Da es funktioniert hat, hab ich die ganzen Befehle 1 zu 1 übernommen. Andere Beispiel haben nicht funktioniert, deswegen gehe ich eigentlich mal davon aus das es das richtige Skript sein sollte (auch da es unter genau meinem Display-Typ eingestellt wurde)

Gruß Ben

Scorch:
EDIT 2:
Es ist nicht "lcd.begin vs. Serial.print" sondern Timer1 vs. lcd.begin & Serial.print.
Sobald ich die Initialisierung des Timer1 auskommentiere geht lcd.begin und serial.print ohne Probleme.
Frage is jetzt nur was macht der Timer1 das dieser Konflikt entsteht und insbesondere wie behebe ich das, den der Timer1 steuert den Takt meiner Schrittmotoren ...

Such mal nach Timer1 und I2C. Wenn ich das richtig verstehe, dan ist Timer1 auch für das Timing des I2C-Buses zuständig.