m2tklib with u8glib on a Teensy 3.1

Great, let me know if there are further doubts.
BTW: I fixed the copy/paste error in the yes/no menu example.

Oliver

I made great progress thanks to your last help. I have one more problem I can't seem to figure out.

I start the program displaying data from sensors. I want the menu to become active when I push a push button. With debugging statements, I can see the button press is seen by M2tklib, but the menu never shows, it just keeps displaying the data screen. On the reverse, if I start the program displaying the menu, when I exit the menu system, I just get a blank screen when I should get sensor data. I'm sure I'm missing something simple....

// Menu
M2tk m2(&m2_null_element, m2_es_arduino_rotary_encoder, m2_eh_4bd, m2_gh_u8g_bf);

M2_EXTERN_VLIST(el_main);
M2_EXTERN_HLIST(el_resetA);
M2_EXTERN_HLIST(el_resetB);
M2_EXTERN_VLIST(el_tz);
M2_EXTERN_VLIST(el_layout);
M2_EXTERN_VLIST(el_units);

M2_ROOT(main_el_top, "f0", NULL, &el_main);
M2_ROOT(main_el_reset_tripmeterA, "f0", "Reset trip A", &el_resetA);
M2_ROOT(main_el_reset_tripmeterB, "f0", "Reset trip B", &el_resetB);
M2_ROOT(main_el_set_timezone, "f0", "Set time zone", &el_tz);
M2_ROOT(main_el_set_layout, "f0", "Set layout", &el_layout);
M2_ROOT(main_el_set_units, "f0", "Set units", &el_units);
M2_ROOT(main_el_exit, "f0", "Exit menu", &m2_null_element);

// Cancel button
void fn_cancel(m2_el_fnarg_p fnarg) {
    m2.setRoot(&el_main);    
}
M2_BUTTON(button_cancel, "f0", "cancel", fn_cancel);

// Main menu 
M2_LIST(main_list) = { 
  &main_el_reset_tripmeterA, 
  &main_el_reset_tripmeterB, 
  &main_el_set_timezone,
  &main_el_set_layout,
  &main_el_set_units,
  &main_el_exit
};
M2_VLIST(el_main, "f0", main_list);

// Trip meter mennu
void fn_yesA(m2_el_fnarg_p fnarg) {
  ResetTrip(0);
  m2.setRoot(&main_el_top);    
}
void fn_yesB(m2_el_fnarg_p fnarg) {
  ResetTrip(1); 
  m2.setRoot(&main_el_top);  
}

M2_BUTTON(button_yesA, "f0", "yes", fn_yesA );
M2_BUTTON(button_yesB, "f0", "yes", fn_yesB );
M2_LIST(list_resetA) = { &button_yesA, &button_cancel };
M2_HLIST(el_resetA, "f0", list_resetA);
M2_LIST(list_resetB) = { &button_yesB, &button_cancel };
M2_HLIST(el_resetB, "f0", list_resetB);
M2_LABEL(label_resetA, "f0", "Reset Trip A?");
M2_LABEL(label_resetB, "f0", "Reset Trip B?");

// Time zone menu
M2_LIST(list_tz) = { &button_cancel };
M2_VLIST(el_tz, "f0", list_tz);

// Layout menu
M2_LIST(list_layout) = { &button_cancel };
M2_VLIST(el_layout, "f0", list_layout);

// Units menu
M2_LIST(list_units) = { &button_cancel };
M2_VLIST(el_units, "f0", list_units);

void setup() {
  m2_SetU8g(u8g.getU8g(), m2_u8g_box_icon);
  m2.setFont(1, u8g_font_7x13r);
  m2.setFont(0, u8g_font_profont11);
  m2.setPin(M2_KEY_SELECT, SW1pin);
  m2.setPin(M2_KEY_ROT_ENC_A, Knob0A);
  m2.setPin(M2_KEY_ROT_ENC_B, Knob0B);
}

void loop() {
  m2.checkKey();

  if ( m2.getRoot() == &m2_null_element ) {
    updateDisplay(layoutVer);  // This does the u8g.firstPage() stuff inside the function

    switch (m2.getKey()) {
    case M2_KEY_NEXT:
      SetBrightness(BrightStep);
      break;
    case M2_KEY_PREV:
      SetBrightness(-BrightStep);
      break;
    case M2_KEY_SELECT:
      Serial.println("MENU: button pressed");
      m2.setRoot(&el_main);
      break;
    }
  } 
  else {
    if ( m2.handleKey() != 0 ) {
      u8g.firstPage();  
      do {
        m2.draw();
        m2.checkKey();
      } 
      while(u8g.nextPage());
    } 
  }
}

Hi

You did not post the full code. Actually i have not seen a bug in the code above, but the problem might be in "updateDisplay".
I also would like to upload this on my Uno to see what exactly goes wrong.

Oliver

The full code is 83,556 bytes in 17 tabs. Here is the updateDisplay() code:

void updateDisplay(int layoutVer) {
  u8g.firstPage();  
  do {
    utc = now();

    switch (layoutVer) {
    case 1:
      displaySpeed(53,42,9,u8g_font_fub25n);
      displaySpeedUnit(54,54,u8g_font_tpssr);
      displayAltitude(107,52,6,u8g_font_tpssr);
      displayHeading(58,11,4,u8g_font_helvR10r);
      displayLat(0,63,u8g_font_profont11);
      displayLon(69,63,u8g_font_profont11);
      displayTrip(98,26,6,1,valTripA,u8g_font_tpssr);
      displayTrip(98,39,6,2,valTripB,u8g_font_tpssr);
      displayTime((*tz).toLocal(utc),0,26,6,u8g_font_tpssr);
      displayDate((*tz).toLocal(utc),0,39,6,u8g_font_tpssr);
      displayTemp(0,11,8,u8g_font_helvB10r);
      displayVoltage(89,11,29,u8g_font_helvB10r);
      displaySDstatus(0,52,u8g_font_profont11);
      break;
    case 2:
      displaySpeed(53,42,9,u8g_font_fub25n);
      displaySpeedUnit(54,54,u8g_font_tpssr);
      displayAltitude(107,52,6,u8g_font_tpssr);
      displayHeading(58,11,4,u8g_font_helvR10r);
      displayTrip(98,26,6,1,valTripA,u8g_font_tpssr);
      displayTrip(98,39,6,2,valTripB,u8g_font_tpssr);
      displayTime((*tz).toLocal(utc),0,26,6,u8g_font_tpssr);
      displayDate((*tz).toLocal(utc),0,39,6,u8g_font_tpssr);
      displayTemp(0,11,8,u8g_font_helvB10r);
      displayVoltage(89,11,29,u8g_font_helvB10r);
      displaySDstatus(0,52,u8g_font_profont11);
      displayGPSstatus(55,63,u8g_font_profont11);
    }
  } 
  while(u8g.nextPage());
}

ok, i see, but i have not seen the problem in the code.
Best would be if i could see the problem on my board. Is it possible to cut down the code to one .ino file, but with the problem still appearing?

Oliver

olikraus:
ok, i see, but i have not seen the problem in the code.
Best would be if i could see the problem on my board. Is it possible to cut down the code to one .ino file, but with the problem still appearing?

Oliver

I'll see what I can do. If I can't get to it tomorrow, it may be a week before I can do it. Thank you for all your help!

OK, here is a stripped down set of code that still has the problem. There is a bit of Teensy specific code in it, SPI and ADC stuff, but for an UNO you can use the regular SPI.h and strip the ADC stuff out, I think.

Edit: Slimmed down the code some more.

// SPI library - Teensy 3.x specific
#include <spi4teensy3.h>
//#include <SPI.h>

// Display library
#include <U8glib.h>

// ADC library
#include <ADC.h>
#include <ADC_Module.h>
#include <RingBuffer.h>
#include <RingBufferDMA.h>

// Menu library
#include <M2tk.h>
#include <utility/m2ghu8g.h>

#define DEBUG

U8GLIB_NHD27OLED_GR u8g(10, 15);   // U8GLIB_NHD27OLED_GR(cs, a0 [, reset]) - Hardware SPI

// Analog pin definitions
const int TempPin = 16;        // 16=A2 on Teensy 3.1  // Pin for input from TMP36
const int VMpin = 14;          // 14=A0 on Teensy 3.1  // Pin for input from 0-30V after voltage divider - don't exceed 3.3V actual to pin

// Digital pin definitions
const int Knob0A = 3;          // Rotary Encoder 0 Pin A
const int Knob0B = 2;          // Rotary Encoder 0 Pin B
const int SW1pin = 20;            // Push button SW1

// Voltmeter
float VMout;

// ADC
ADC *adc = new ADC();

// Thermometer
float DegF;
bool tempErr = false;

// Menu
//M2tk m2(&m2_null_element, m2_es_arduino_rotary_encoder, m2_eh_4bd, m2_gh_u8g_bf);
M2_EXTERN_VLIST(el_main);
M2tk m2(&el_main, m2_es_arduino_rotary_encoder, m2_eh_4bd, m2_gh_u8g_bf);

M2_EXTERN_HLIST(el_resetA);
M2_EXTERN_HLIST(el_resetB);
M2_EXTERN_VLIST(el_tz);
M2_EXTERN_VLIST(el_layout);
M2_EXTERN_VLIST(el_units);

M2_ROOT(main_el_top, "f0", NULL, &el_main);
M2_ROOT(main_el_reset_tripmeterA, "f0", "Reset trip A", &el_resetA);
M2_ROOT(main_el_reset_tripmeterB, "f0", "Reset trip B", &el_resetB);
M2_ROOT(main_el_set_timezone, "f0", "Set time zone", &el_tz);
M2_ROOT(main_el_set_layout, "f0", "Set layout", &el_layout);
M2_ROOT(main_el_set_units, "f0", "Set units", &el_units);
M2_ROOT(main_el_exit, "f0", "Exit menu", &m2_null_element);

// Cancel button
void fn_cancel(m2_el_fnarg_p fnarg) {
  m2.setRoot(&el_main);    
}
M2_BUTTON(button_cancel, "f0", "cancel", fn_cancel);

// Main menu 
M2_LIST(main_list) = { 
  &main_el_reset_tripmeterA, 
  &main_el_reset_tripmeterB, 
  &main_el_set_timezone,
  &main_el_set_layout,
  &main_el_set_units,
  &main_el_exit
};
M2_VLIST(el_main, "f0", main_list);

// Trip meter mennu
void fn_yesA(m2_el_fnarg_p fnarg) {
  //ResetTrip(0);
  m2.setRoot(&el_main);    
}
void fn_yesB(m2_el_fnarg_p fnarg) {
  //ResetTrip(1); 
  m2.setRoot(&el_main);  
}

M2_BUTTON(button_yesA, "f0", "yes", fn_yesA );
M2_BUTTON(button_yesB, "f0", "yes", fn_yesB );
M2_LIST(list_resetA) = { 
  &button_yesA, &button_cancel };
M2_HLIST(el_resetA, "f0", list_resetA);
M2_LIST(list_resetB) = { 
  &button_yesB, &button_cancel };
M2_HLIST(el_resetB, "f0", list_resetB);
M2_LABEL(label_resetA, "f0", "Reset Trip A?");
M2_LABEL(label_resetB, "f0", "Reset Trip B?");

// Time zone menu
M2_LIST(list_tz) = { 
  &button_cancel };
M2_VLIST(el_tz, "f0", list_tz);

// Layout menu
M2_LIST(list_layout) = { 
  &button_cancel };
M2_VLIST(el_layout, "f0", list_layout);

// Units menu
M2_LIST(list_units) = { 
  &button_cancel };
M2_VLIST(el_units, "f0", list_units);

void setup() {

  Serial.begin(115200);
  Serial1.begin(19200); // GPS
#ifdef DEBUG
  delay(2000); // startup delay 
#endif

#ifdef DEBUG
  Serial.print(F("DEBUG: "));
  Serial.println(F("Begin setup"));
#endif

#ifdef DEBUG
  Serial.print(F("DEBUG: "));
  Serial.println(F("Display start"));
#endif
  // Start the display
  u8g.begin();
  //u8g.setRot180(); // Rotate screen 180 deg
  u8g.setColorIndex(15); // 15 = max intensity for GR display, 1 = on for BW
  u8g.setContrast(200);

#ifdef DEBUG
  Serial.print(F("DEBUG: "));
  Serial.println(F("Pin init"));
#endif
  pinMode(VMpin, INPUT);   // Input pin for voltmeter
  pinMode(TempPin, INPUT); // Input pin for thermometer

  //
  // ADC setup
  //
#ifdef DEBUG
  Serial.print(F("DEBUG: "));
  Serial.println(F("Start ADC stuff"));
#endif
  adc->setAveraging(16, ADC_0);
  adc->setAveraging(16, ADC_1);

  //
  // Menu
  //
#ifdef DEBUG
  Serial.print(F("DEBUG: "));
  Serial.println(F("Menu setup"));
#endif
  m2_SetU8g(u8g.getU8g(), m2_u8g_box_icon);
  m2.setFont(1, u8g_font_7x13r);
  m2.setFont(0, u8g_font_profont11);
  m2.setPin(M2_KEY_SELECT, SW1pin);
  m2.setPin(M2_KEY_ROT_ENC_A, Knob0A);
  m2.setPin(M2_KEY_ROT_ENC_B, Knob0B);


#ifdef DEBUG
  Serial.print(F("DEBUG: "));
  Serial.println(F("End setup"));
#endif

} // End setup()

// Main body where we actually do stuff
void loop() { 

  CalculateVoltage();
  CalculateTemp();
  m2.checkKey();

  if ( m2.getRoot() == &m2_null_element ) {
    u8g.firstPage();  
    do {
      displayTemp(0,11,8,u8g_font_helvB10r);
      displayVoltage(89,11,29,u8g_font_helvB10r);

      switch (m2.getKey()) {
      case M2_KEY_NEXT:
#ifdef DEBUG
        Serial.println("DISPLAY: Brightness up");
#endif
        //SetBrightness(BrightStep);
        break;
      case M2_KEY_PREV:
#ifdef DEBUG
        Serial.println("DISPLAY: Brightness down");
#endif
        //SetBrightness(-BrightStep);
        break;
      case M2_KEY_SELECT:
#ifdef DEBUG
        Serial.println("MENU: button pressed");
#endif
        m2.setRoot(&el_main);
        break;
      }
    }
    while(u8g.nextPage());
  } 
  else {
    if ( m2.handleKey() != 0 ) {
      u8g.firstPage();  
      do {
        m2.draw();
        m2.checkKey();
      } 
      while(u8g.nextPage());
    } 
  }
}


void displayVoltage(int posH, int posV, int inc, const unsigned char* font) {
  u8g.setFont(font); 
  u8g.setPrintPos(posH, posV); 
  u8g.print(VMout,1); // Print the voltage with one decimal place
  u8g.setPrintPos((posH + inc), posV); // Set the position for the following
  u8g.print("V"); // Print V next to the voltage reading
}

void displayTemp(int posH, int posV, int inc, const unsigned char* font) { 
  u8g.setFont(font); // Set the font
  if (tempErr == false) {
    if ( DegF < 100.0f && DegF >= 10.0f ) { // adjust the print position depending on number of digits
      u8g.setPrintPos((posH + inc), posV); 
    }
    else if ( DegF < 10.0f && DegF >= 0.0f ) {
      u8g.setPrintPos((posH + (inc * 2)), posV); 
    }
    else {
      u8g.setPrintPos(posH, posV); 
    }
    u8g.print(DegF,0); // Print the temperature with no decimal fraction
  } 
  else {
    u8g.setFont(u8g_font_tpssr);
    u8g.setPrintPos(posH, posV - 1);
    u8g.print("ERR");
  }
  u8g.setPrintPos((posH + (inc * 3) + 1), posV); 
  u8g.setFont(font);
  u8g.print("F"); // Print F next to the temp reading
}

void CalculateTemp() {
  // Read the voltage from the LM34 and calcuate the temperature based on the voltage
  float voltagein = adc->analogRead(TempPin, ADC_1); // Read the voltage using ADC_1 
  float tempVolt = voltagein / 310; // For 3.3v power 
  float DegC = (100 * tempVolt) - 50;  // TMP36 voltage = temp in C with a 50 deg offset
  tempErr = false;
  DegF = (DegC * 9.0 / 5.0) + 32.0; // Convert to Farenheit
#ifdef DEBUGTEMP
  Serial.print(F("TEMP: "));
  Serial.print(F("Temp: "));
  Serial.println(DegF);
#endif
}

void CalculateVoltage() {
  float VMsum = adc->analogRead(VMpin); // Read the voltage
  // Calculate the voltage
  float VMvoltage = VMsum / 310.0;  // For 3.3V system 
  // Send voltage for display - the number requires tweaking to suit your individual setup 
  // (voltage divider resistor value and variance, etc.)
  VMout = VMvoltage * 11.0312;
#ifdef DEBUGVOLT
  Serial.print(F("VOLT: "));
  Serial.print(F("Volt: "));
  Serial.println(VMout);
#endif
}

A little debugging shows that when in graphics mode, the M2_KEY_SELECT action is seen, however, the m2.setRoot(&el_main) does not take effect and the m2 root remains set to m2_null_element.

When in menu mode, and the menu option to exit back to graphics is selected, m2 root does change to m2_null_element but the low level graphics are not displayed.

Hi

I tracked down the problems.

  1. Problem: After "Exit Menu" nothing is displayed.
    This is a known problem. M2tk alters the foreground color, so you u8glib picture is not visible. You neet to reassign the foreground color:
  if ( m2.getRoot() == &m2_null_element ) {
    u8g.setDefaultForegroundColor();
    u8g.firstPage();
  1. Problem: Going back to menu does not work.
    Additionally to setRoot, you need to call two more functions:
      case M2_KEY_SELECT:
#ifdef DEBUG
        Serial.println("MENU: button pressed");
#endif
        m2.setRoot(&el_main);
        m2.handleKey();             // update internal menu
        m2.setKey(M2_KEY_REFRESH);  // force a refresh

Below you will find my test code.

Oliver

// SPI library - Teensy 3.x specific
//#include <spi4teensy3.h>
//#include <SPI.h>

// Display library
#include <U8glib.h>

// ADC library
//#include <ADC.h>
//#include <ADC_Module.h>
//#include <RingBuffer.h>
//#include <RingBufferDMA.h>

// Menu library
#include <M2tk.h>
#include <utility/m2ghu8g.h>

//#define DEBUG

//U8GLIB_NHD27OLED_GR u8g(10, 15);   // U8GLIB_NHD27OLED_GR(cs, a0 [, reset]) - Hardware SPI
U8GLIB_DOGM128 u8g(13, 11, 10, 9);		// SPI Com: SCK = 13, MOSI = 11, CS = 10, A0 = 9


// Analog pin definitions
const int TempPin = 16;        // 16=A2 on Teensy 3.1  // Pin for input from TMP36
const int VMpin = 14;          // 14=A0 on Teensy 3.1  // Pin for input from 0-30V after voltage divider - don't exceed 3.3V actual to pin

// Digital pin definitions
const int Knob0A = 7;          // Rotary Encoder 0 Pin A
const int Knob0B = 3;          // Rotary Encoder 0 Pin B
const int SW1pin = 2;            // Push button SW1

// Voltmeter
float VMout;

// ADC
//ADC *adc = new ADC();

// Thermometer
float DegF;
bool tempErr = false;

// Menu
//M2tk m2(&m2_null_element, m2_es_arduino_rotary_encoder, m2_eh_4bd, m2_gh_u8g_bf);
M2_EXTERN_VLIST(el_main);
M2tk m2(&el_main, m2_es_arduino_rotary_encoder, m2_eh_4bd, m2_gh_u8g_bf);

M2_EXTERN_HLIST(el_resetA);
M2_EXTERN_HLIST(el_resetB);
M2_EXTERN_VLIST(el_tz);
M2_EXTERN_VLIST(el_layout);
M2_EXTERN_VLIST(el_units);

M2_ROOT(main_el_top, "f0", NULL, &el_main);
M2_ROOT(main_el_reset_tripmeterA, "f0", "Reset trip A", &el_resetA);
M2_ROOT(main_el_reset_tripmeterB, "f0", "Reset trip B", &el_resetB);
M2_ROOT(main_el_set_timezone, "f0", "Set time zone", &el_tz);
M2_ROOT(main_el_set_layout, "f0", "Set layout", &el_layout);
M2_ROOT(main_el_set_units, "f0", "Set units", &el_units);
M2_ROOT(main_el_exit, "f0", "Exit menu", &m2_null_element);

// Cancel button
void fn_cancel(m2_el_fnarg_p fnarg) {
  m2.setRoot(&el_main);    
}
M2_BUTTON(button_cancel, "f0", "cancel", fn_cancel);

// Main menu 
M2_LIST(main_list) = { 
  &main_el_reset_tripmeterA, 
  &main_el_reset_tripmeterB, 
  &main_el_set_timezone,
  &main_el_set_layout,
  &main_el_set_units,
  &main_el_exit
};
M2_VLIST(el_main, "f0", main_list);

// Trip meter mennu
void fn_yesA(m2_el_fnarg_p fnarg) {
  //ResetTrip(0);
  m2.setRoot(&el_main);    
}
void fn_yesB(m2_el_fnarg_p fnarg) {
  //ResetTrip(1); 
  m2.setRoot(&el_main);  
}

M2_BUTTON(button_yesA, "f0", "yes", fn_yesA );
M2_BUTTON(button_yesB, "f0", "yes", fn_yesB );
M2_LIST(list_resetA) = { 
  &button_yesA, &button_cancel };
M2_HLIST(el_resetA, "f0", list_resetA);
M2_LIST(list_resetB) = { 
  &button_yesB, &button_cancel };
M2_HLIST(el_resetB, "f0", list_resetB);
M2_LABEL(label_resetA, "f0", "Reset Trip A?");
M2_LABEL(label_resetB, "f0", "Reset Trip B?");

// Time zone menu
M2_LIST(list_tz) = { 
  &button_cancel };
M2_VLIST(el_tz, "f0", list_tz);

// Layout menu
M2_LIST(list_layout) = { 
  &button_cancel };
M2_VLIST(el_layout, "f0", list_layout);

// Units menu
M2_LIST(list_units) = { 
  &button_cancel };
M2_VLIST(el_units, "f0", list_units);

void setup() {

  Serial.begin(115200);
  //Serial1.begin(19200); // GPS
#ifdef DEBUG
  delay(2000); // startup delay 
#endif

#ifdef DEBUG
  Serial.print(F("DEBUG: "));
  Serial.println(F("Begin setup"));
#endif

#ifdef DEBUG
  Serial.print(F("DEBUG: "));
  Serial.println(F("Display start"));
#endif
  // Start the display
  u8g.begin();
  //u8g.setRot180(); // Rotate screen 180 deg
  //u8g.setColorIndex(15); // 15 = max intensity for GR display, 1 = on for BW
  //u8g.setContrast(200);

#ifdef DEBUG
  Serial.print(F("DEBUG: "));
  Serial.println(F("Pin init"));
#endif
  pinMode(VMpin, INPUT);   // Input pin for voltmeter
  pinMode(TempPin, INPUT); // Input pin for thermometer

  //
  // ADC setup
  //
#ifdef DEBUG
  Serial.print(F("DEBUG: "));
  Serial.println(F("Start ADC stuff"));
#endif
  //adc->setAveraging(16, ADC_0);
  //adc->setAveraging(16, ADC_1);

  //
  // Menu
  //
#ifdef DEBUG
  Serial.print(F("DEBUG: "));
  Serial.println(F("Menu setup"));
#endif
  m2_SetU8g(u8g.getU8g(), m2_u8g_box_icon);
  m2.setFont(1, u8g_font_7x13r);
  m2.setFont(0, u8g_font_profont11);
  m2.setPin(M2_KEY_SELECT, SW1pin);
  m2.setPin(M2_KEY_NEXT, Knob0A);
  m2.setPin(M2_KEY_PREV, Knob0B);


#ifdef DEBUG
  Serial.print(F("DEBUG: "));
  Serial.println(F("End setup"));
#endif

} // End setup()

// Main body where we actually do stuff
void loop() { 

  CalculateVoltage();
  CalculateTemp();
  m2.checkKey();

  if ( m2.getRoot() == &m2_null_element ) {
    u8g.setDefaultForegroundColor();
    u8g.firstPage();  
    do {
      m2.checkKey();
      displayTemp(0,11,8,u8g_font_helvB10r);
      displayVoltage(89,11,29,u8g_font_helvB10r);

    }
    while(u8g.nextPage());
    
      switch (m2.getKey()) {
      case M2_KEY_NEXT:
#ifdef DEBUG
        Serial.println("DISPLAY: Brightness up");
#endif
        //SetBrightness(BrightStep);
        break;
      case M2_KEY_PREV:
#ifdef DEBUG
        Serial.println("DISPLAY: Brightness down");
#endif
        //SetBrightness(-BrightStep);
        break;
      case M2_KEY_SELECT:
#ifdef DEBUG
        Serial.println("MENU: button pressed");
#endif
        m2.setRoot(&el_main);
        m2.handleKey();             // update internal menu
        m2.setKey(M2_KEY_REFRESH);  // force a refresh
        
        break;
      }

    
  } 
  else {
    if ( m2.handleKey() != 0 ) {
      u8g.firstPage();  
      do {
        m2.draw();
        m2.checkKey();
      } 
      while(u8g.nextPage());
    } 
  }
}


void displayVoltage(int posH, int posV, int inc, const unsigned char* font) {
  u8g.setFont(font); 
  u8g.setPrintPos(posH, posV); 
  u8g.print(VMout,1); // Print the voltage with one decimal place
  u8g.setPrintPos((posH + inc), posV); // Set the position for the following
  u8g.print("V"); // Print V next to the voltage reading
}

void displayTemp(int posH, int posV, int inc, const unsigned char* font) { 
  u8g.setFont(font); // Set the font
  if (tempErr == false) {
    if ( DegF < 100.0f && DegF >= 10.0f ) { // adjust the print position depending on number of digits
      u8g.setPrintPos((posH + inc), posV); 
    }
    else if ( DegF < 10.0f && DegF >= 0.0f ) {
      u8g.setPrintPos((posH + (inc * 2)), posV); 
    }
    else {
      u8g.setPrintPos(posH, posV); 
    }
    u8g.print(DegF,0); // Print the temperature with no decimal fraction
  } 
  else {
    u8g.setFont(u8g_font_tpssr);
    u8g.setPrintPos(posH, posV - 1);
    u8g.print("ERR");
  }
  u8g.setPrintPos((posH + (inc * 3) + 1), posV); 
  u8g.setFont(font);
  u8g.print("F"); // Print F next to the temp reading
}

void CalculateTemp() {
  // Read the voltage from the LM34 and calcuate the temperature based on the voltage
  float voltagein = 1023; // Read the voltage using ADC_1 
  float tempVolt = voltagein / 310; // For 3.3v power 
  float DegC = (100 * tempVolt) - 50;  // TMP36 voltage = temp in C with a 50 deg offset
  tempErr = false;
  DegF = (DegC * 9.0 / 5.0) + 32.0; // Convert to Farenheit
#ifdef DEBUGTEMP
  Serial.print(F("TEMP: "));
  Serial.print(F("Temp: "));
  Serial.println(DegF);
#endif
}

void CalculateVoltage() {
  float VMsum = 888; // Read the voltage
  // Calculate the voltage
  float VMvoltage = VMsum / 310.0;  // For 3.3V system 
  // Send voltage for display - the number requires tweaking to suit your individual setup 
  // (voltage divider resistor value and variance, etc.)
  VMout = VMvoltage * 11.0312;
#ifdef DEBUGVOLT
  Serial.print(F("VOLT: "));
  Serial.print(F("Volt: "));
  Serial.println(VMout);
#endif
}

Oliver,

Thank you, thank you, thank you! You have solved the last issues I was facing! I really appreciate your software and your assistance in debugging. Is there some way I can repay you?

Eric

I am glad to read, that the problems are solved. There is no need for "repay".

Oliver

olikraus:
I am glad to read, that the problems are solved. There is no need for "repay".

Oliver

Do you have a Teensy 3.1 board? If not, can I send one to you?

Eric

Hi Eric

Thanks for the offer, but there is no need to send me a Teensy.

Is everything working? Do you have more questions on m2tklib?

Oliver

Everything is working at this point. I will need to implement a scroll list, but I think I can figure it out now from the tutorial.

One question I do have - is the button debounce interval configurable?

Eric

Hi Eric

in the file m2esarduino.c you can find these two definitions:

#define ROT_ENC_DEBOUNCE_VAL 3
#define ROT_ENC_EVENT_DIVISION 3

Try to reduce the values here for faster response of the rotary encoder.

Oliver

OK, I'm having an issue with a STRLIST. The vertical scroll bar is showing up below the strlist items. Here is what it looks like:

Here is the relevant code:

// Time zone menu
const char *selected = "";
const char *el_tzlist_tz(uint8_t idx, uint8_t msg) {
  const char *tzone = "";
  if  ( idx == 0 )
    tzone = "UTC";
  else if ( idx == 1 )
    tzone = "usET";
  else if ( idx == 2 )
    tzone = "usCT";
  else if ( idx == 3 )
    tzone = "usMT";
  else if ( idx == 4 )
    tzone = "usAZ";
  else if ( idx == 5 )
    tzone = "usPT";
  else if ( idx == 6 )
    tzone = "usAK";
  if (msg == M2_STRLIST_MSG_GET_STR) {
    /* nothing else todo, return the correct string */
  } else if ( msg == M2_STRLIST_MSG_SELECT ) {
    selected = tzone;
  }
  return tzone;
}
uint8_t el_tzlist_first = 0;
uint8_t el_tzlist_cnt = 7;

M2_STRLIST(el_tzlist, "l2w80", &el_tzlist_first, &el_tzlist_cnt, &el_tzlist_tz);
M2_SPACE(el_space, "w1h1");
M2_VSB(el_tzlist_vsb, "l2w5r1", &el_tzlist_first, &el_tzlist_cnt);
M2_LIST(list_tzlist_tz) = { &el_tzlist, &el_space, &el_tzlist_vsb };
M2_VLIST(el_tzlist_vlist, NULL, list_tzlist_tz);

M2_LABEL(el_label_tz,NULL, "Time zone: ");
M2_LABELPTR(el_labelptr_tz, NULL, &selected);
M2_LIST(list_label_tz) = { &el_label_tz, &el_labelptr_tz };
M2_VLIST(el_label_tz_vlist, NULL, list_label_tz);

M2_LIST(tzlist) = { &el_tzlist_vlist, &el_label_tz_vlist, &button_cancel };
M2_VLIST(el_tz_vlist, "f0", tzlist);
M2_ALIGN(top_el, "-1|1W64H64", &el_tz_vlist);

Also, I'd like to have the selected item (usPT in the example above) on the same line as "Time zone:".

Any pointers on how to resolve this are appreciated. I'm sure I'm missing something fairly simple...

Thanks!

I think you must use a HLIST instead of the VLIST for the first two container.

Oliver

M2_STRLIST(el_tzlist, "l2w80", &el_tzlist_first, &el_tzlist_cnt, &el_tzlist_tz);
M2_SPACE(el_space, "w1h1");
M2_VSB(el_tzlist_vsb, "l2w5r1", &el_tzlist_first, &el_tzlist_cnt);
M2_LIST(list_tzlist_tz) = { &el_tzlist, &el_space, &el_tzlist_vsb };
M2_HLIST(el_tzlist_vlist, NULL, list_tzlist_tz);    // changed to HLIST

M2_LABEL(el_label_tz,NULL, "Time zone: ");
M2_LABELPTR(el_labelptr_tz, NULL, &selected);
M2_LIST(list_label_tz) = { &el_label_tz, &el_labelptr_tz };
M2_HLIST(el_label_tz_vlist, NULL, list_label_tz);  // changed to HLIST

M2_LIST(tzlist) = { &el_tzlist_vlist, &el_label_tz_vlist, &button_cancel };
M2_VLIST(el_tz_vlist, "f0", tzlist);
M2_ALIGN(top_el, "-1|1W64H64", &el_tz_vlist);

That helped! Making progress:

Here's the updated code:

M2_STRLIST(el_tzlist, "l4w118", &el_tzlist_first, &el_tzlist_cnt, el_tzlist_tz);
M2_SPACE(el_space, "w1h1");
M2_VSB(el_tzlist_vsb, "l4w5r1", &el_tzlist_first, &el_tzlist_cnt);
M2_LIST(list_tzlist_tz) = { &el_tzlist, &el_space, &el_tzlist_vsb };
M2_HLIST(el_tzlist_vlist, NULL, list_tzlist_tz);
M2_ALIGN(top_el2, "-0|2", &el_tzlist);

M2_LABEL(el_label_tz,NULL, "Time zone: ");
M2_LABELPTR(el_labelptr_tz, NULL, &selected);
M2_LIST(list_label_tz) = { &el_label_tz, &el_labelptr_tz };
M2_HLIST(el_label_tz_vlist, NULL, list_label_tz);

M2_LIST(tzlist) = { &el_tzlist_vlist, &el_label_tz_vlist, &button_tz_use, &button_cancel };
M2_VLIST(el_tz_vlist, "f0", tzlist);
M2_ALIGN(top_el, "-1|1W64H64", &el_tz_vlist);

Now, I can't seem to get "Change?" and "cancel" on the same line.

I tried changing tzlist to a HLIST, but that really screwed up the display format.

As a side note, it doesn't appear that M2_ALIGN really does anything. I've tried changing that last entry to different formatting, to no avail.

I guess you need to put &button_tz_use and &button_cancel into another (third) HLIST. This HLIST has do be put into the VLIST, so finally the VLIST only contains three HLIST.

It looks, that your dialog box is larger than the screen. In such a case ALIGN can not do anything.

Oliver