Problem mit eigener Funktion in LCDML2

Hallo!

Für mein Projekt - eine Steuerung für einen Pilzzuchtkasten - verwende ich die sehr großartige LCDML2.

Leider habe ich ein Problem, wenn ich (per Rotary Encoder) ein Untermenü aufrufe, welches den eingebauten Lüfter für eine vorgegebene Zeit manuell starten (bzw. falls er gerade läuft, stoppen) soll. Das tut es zwar, und während dessen laufen soweit ich das erkennen kann auch die weiteren Funktionen (Temperatur-, Luftfeuchtigkeits-, CO2-Sensoren, Logging, serielle Ausgabe, ... ) normal und der Lüfter stoppt auch nach Ablauf des Countdown. Allerdings hängt sich der Mega in diesem Moment auf. Manchmal startet er auch einfach neu. Da es keine Fehlermeldung gibt, bin ich ziemlich ratlos.
Hier ist der Code der entsprechenden Funktion. Wenn ich das Programm nur mit Menüfunktionen, also ohne die anderen Loop-Funktionen laufen lasse, funktioniert alles einfandfrei. In Loop sind ansonsten die oben genannten Funktionen, die meisten davon in einer 5000 ms - Schleife.

// *********************************************************************
void mFunc_fan_manOnOff()
// *********************************************************************
{       
//      mFunc_fan_state =1;            // habe ich als Statusvariable ausprobiert, um nicht mit dem dem automatischen Lüfteranlauf
                                                   // in die Quere zu kommen, hat aber leider nichts gebracht
uint32_t fan_remaintime;      
        char fan_countdown[21];

        if(LCDML.FUNC_setup())                      // ****** SETUP *********
        {
          // setup
          // is called only if it is started
      
          // starts a trigger event for the loop function every 100 milliseconds
          LCDML.FUNC_setLoopInterval(100);

        if(fan_state == 0){
            fan_state = 1;
            fan_starttime_temp=millis();
          }
        else{
            fan_state = 0;
            LCDML.FUNC_goBackToMenu();
          }
          
           digitalWrite(fan_pinA, fan_state);
           digitalWrite(fan_pinB, fan_state);
           
           LCDML.FUNC_disableScreensaver();
        }
        
        if(LCDML.FUNC_loop())                         // ****** LOOP *********
        {
            // loop
            // is called when it is triggered
            // - with LCDML_DISP_triggerMenu( milliseconds )
            // - with every button status change
            
            fan_remaintime = (fan_starttime_temp+fan_duration_manuell-millis())/1000.0;
        
            sprintf(fan_countdown, "remaining: %d s  ", fan_remaintime); 
            
            if( millis() - fan_starttime_temp >= fan_duration_manuell ){
              fan_state = 0;
              LCDML.FUNC_goBackToMenu();
            }

            lcd.setCursor(0, 0);
            lcd.print(F("CO2: ")); 
            lcd.setCursor(13, 0);
            lcd.print(CO2_av);
            lcd.print(F(" ppm"));
            lcd.setCursor(0, 2);
            lcd.print(fan_countdown);
            
            lcd.setCursor(0, 2);
                   
            if(LCDML.BT_checkAny()) {
//              LCDML.FUNC_goBackToMenu();
            }
            
            digitalWrite(fan_pinA, fan_state);
            digitalWrite(fan_pinB, fan_state);
          }
          
          if(LCDML.FUNC_close())      // ****** STABLE END *********
          {
            //LCDML.FUNC_goBackToMenu();
            // loop end
            // you can here reset some global vars or delete it

          }
        }

Bitte Links zu Bibliothek und Hardware.
Grüße Uwe

uwefed:
Bitte Links zu Bibliothek und Hardware.
Grüße Uwe

Hi! Hab oben die Links eingefügt.

Wie steuerst Du das LOG Shield an?
Der Arduino MEGA hat die SPI Schnittstelle an anderen Pins als 11-13. Laut Bilder fehlen die Pins an der ISP-Schnittstelle über die der Arduino Mega mit der SD Karte sprechen könnte.
Grüße Uwe

statte deinen Sketch mit Serial.print / Debug Ausgaben aus und verfolge wo dein Programm aussteigt.
Wenn du den Fehler einkreisen konntest, gib dir alles an Variablen aus, was in den nächsten Schritten benötigt wird.

Teil-Programme machen selten Sinn, weil öfter das Problem doch in ganz anderen Bereichen liegt als vom TO vermutet.

das könnte knapp werden:
char fan_countdown[21];

wenn ich das sehe:
sprintf(fan_countdown, "remaining: %d s ", fan_remaintime);

15 Zeichen Fixtext + 10 Zeichen für etwas was bis zu 4294967295 sein kann + \0 ist mehr als 21

Hi

Kann das
LCDML.FUNC_goBackToMenu();
so im Sketch frei verwendet werden, oder ist Das der Menü-Struktur vorenthalten?
Wenn Letzteres, könnte ich mir vorstellen, daß auf dem Stack nicht die richtige Rücksprung-Adresse gefunden wird, weil diese Funktion nicht sauber verlassen wurde?!?

MfG

uwefed:
Wie steuerst Du das LOG Shield an?
Der Arduino MEGA hat die SPI Schnittstelle an anderen Pins als 11-13. Laut Bilder fehlen die Pins an der ISP-Schnittstelle über die der Arduino Mega mit der SD Karte sprechen könnte.
Grüße Uwe

Ja, das stimmt. War etwas hakelig, da auch noch die Library angepasst werden muss. Aber ich hab das Logging Shield auf chipSelect(10,11,12,13), so wie es der Downloadlink von Velleman verlangt. Das läuft auch.

noiasca:
statte deinen Sketch mit Serial.print / Debug Ausgaben aus und verfolge wo dein Programm aussteigt.
Wenn du den Fehler einkreisen konntest, gib dir alles an Variablen aus, was in den nächsten Schritten benötigt wird.

Teil-Programme machen selten Sinn, weil öfter das Problem doch in ganz anderen Bereichen liegt als vom TO vermutet.

Stimmt, so mache ich das normalerweise auch. Hier ist es halt sehr umfangreich, es ist mein erster Kontakt mit der LCDML. Vorher habe ich mich nur in einem einzigen Tab bewegt ... Aber ich werde es mal so versuchen.

das könnte knapp werden:
char fan_countdown[21];

wenn ich das sehe:
sprintf(fan_countdown, "remaining: %d s ", fan_remaintime);

15 Zeichen Fixtext + 10 Zeichen für etwas was bis zu 4294967295 sein kann + \0 ist mehr als 21

Das habe ich von hier, wobei ich den Gebrauch von sprintf() auch noch nicht wirklich verstanden habe (wie an den Leerzeichen nach dem 's' zu erkennen ist...). Dass dies den Fehler verursachen könnte kann ich nicht ausschließen. Allerdings ist die Funktion an sich ja wie gesagt in Ordnung, wenn nichts anderes läuft.

postmaster-ino:
Hi

Kann das
LCDML.FUNC_goBackToMenu();
so im Sketch frei verwendet werden, oder ist Das der Menü-Struktur vorenthalten?
Wenn Letzteres, könnte ich mir vorstellen, daß auf dem Stack nicht die richtige Rücksprung-Adresse gefunden wird, weil diese Funktion nicht sauber verlassen wurde?!?

MfG

Du meinst allgemein? Oder ein bestimmtes?

Ich habe einfach das passende Beispiel (I2C 20x4) aus der Library genommen, und daraus die mFunc_timer_info() umgebastelt:

// *********************************************************************
uint8_t g_func_timer_info = 0;  // time counter (global variable)
unsigned long g_timer_1 = 0;    // timer variable (global variable)
void mFunc_timer_info(uint8_t param)
// *********************************************************************
{
  if(LCDML.FUNC_setup())          // ****** SETUP *********
  {
    lcd.print(F("20 sec wait")); // print some content on first row
    g_func_timer_info = 20;       // reset and set timer
    LCDML.FUNC_setLoopInterval(100);  // starts a trigger event for the loop function every 100 milliseconds

    LCDML.TIMER_msReset(g_timer_1);
  }


  if(LCDML.FUNC_loop())           // ****** LOOP *********
  {
    // loop function, can be run in a loop when LCDML_DISP_triggerMenu(xx) is set
    // the quit button works in every DISP function without any checks; it starts the loop_end function

    // reset screensaver timer
    LCDML.SCREEN_resetTimer();

    // this function is called every 100 milliseconds

    // this method checks every 1000 milliseconds if it is called
    if(LCDML.TIMER_ms(g_timer_1, 1000)) {
      g_func_timer_info--;                // increment the value every second
      lcd.setCursor(0, 0);                // set cursor pos
      lcd.print(F("  "));
      lcd.setCursor(0, 0);                // set cursor pos
      lcd.print(g_func_timer_info);       // print the time counter value
    }

    // this function can only be ended when quit button is pressed or the time is over
    // check if the function ends normally
    if (g_func_timer_info <= 0)
    {
      // leave this function
      LCDML.FUNC_goBackToMenu();
    }
  }

  if(LCDML.FUNC_close())      // ****** STABLE END *********
  {
    // you can here reset some global vars or do nothing
  }
}

Moin,

Das einzige was mir aufgefallen ist, ist das bei deiner Funktion der Übergabeparameter nicht definiert ist. Es kann sein das dies zu Problemen führen kann.

// deins:
void mFunc_fan_manOnOff()

// sollte eigentlich so sein:
void mFunc_fan_manOnOff(uint8_t param)

Ich habe die Funktion gerade getestet (ohne Hardware). Der Zähler läuft runter und das Menü wird wieder angezeigt.

Jomelo:
Moin,

Das einzige was mir aufgefallen ist, ist das bei deiner Funktion der Übergabeparameter nicht definiert ist. Es kann sein das dies zu Problemen führen kann.

// deins:

void mFunc_fan_manOnOff()

// sollte eigentlich so sein:
void mFunc_fan_manOnOff(uint8_t param)




Ich habe die Funktion gerade getestet (ohne Hardware). Der Zähler läuft runter und das Menü wird wieder angezeigt.

Hey,
vielen Dank! Es scheint, als könnte das die Ursache gewesen sein! Ich mache noch ein paar Tests mit unterschiedlichen Konstellationen, aber es sieht sehr gut aus!

Auch danke für die Library, die Beschäftigung damit bringt mich gerade in einigen Punkten wirklich weiter!

Das klingt sehr gut.

Mir stellt sich gerade nur die Frage wieso der Compiler hier keine Fehlermeldung schmeißt. Das ist mir im Moment ein Rätsel.

Hi

Vll. ist's nur eine Warnung?
Die muß explizit aktiviert werden (warum auch immer Das nicht die Standardeinstellung ist).

mfG

postmaster-ino:
Hi

Vll. ist's nur eine Warnung?
Die muß explizit aktiviert werden (warum auch immer Das nicht die Standardeinstellung ist).

mfG

Hmm, ich habe sie mal angeschaltet, kann aber wenig damit anfangen.

_LCDML.ino:683:3: note: in expansion of macro 'LCDML_add'
LCDML_add (1 , LCDML_0_1 , 1 , "Fan on/off" , mFunc_fan_manOnOff); // this menu function can be found on "LCDML_display_menuFunction" tab

ist das einzige speziell zu dieser Funktion.

Zu Übergabeparametern bekomme ich alle möglichen

warning: unused parameter 'param' [-Wunused-parameter]
void mFunc_goToRootMenu(uint8_t param)

Moin,
das sind nicht direkt Warnings sondern nur Hinweise den Code zu optimieren. Das was ich zu vor meinte ist hiermit nicht gemeint. Mach dir da keinen Kopf drum. :wink: