Using Nextion displays with Arduino

Using Nextion displays with Arduino part 3

Complete demonstration code

The complete code for the demonstration is here and attached as 'Nextion_demonstration43.ino'

Setup and main loop

enum pages {page0, page1,noOfPages};
enum HMIData {spare, page, type, Nindex, data0, data1};     // 31/7/2022 'index' changed to 'Nindex' because 'index' conflicts with something used in an ESP8266 and ESP32

void setup() {
  //This is for the serial monitor. Remove the // if you need to use it.
  //Serial.begin(9600);
  
  //This is for serial port 1, which is the one used for the Nextion in this demonstration. You might need to change this depending on which serial port you are using for your display.
  Serial1.begin(9600);

  //For  demonstration
  HMI_startup_message();
}

void loop() {
  HMI_read();
  clock_run();
}

struct DCLOCK {
  int8_t Dhour;
  int8_t Dminute;
  int8_t Dsecond;
};
struct DCLOCK Dclock;


//This displays the clock
void HMI_display_clock() {
  char timestring[9];
  sprintf(timestring, "%02d:%02d:%02d", Dclock.Dhour, Dclock.Dminute, Dclock.Dsecond);
  Serial1.print(F("t1.txt=\""));
  Serial1.print(timestring);
  Serial1.print(F("\""));
  Serial1.print(F("\xFF\xFF\xFF"));         // Sends 0xff 0xff 0xff, which tell the Nextion that it has a complete string of data
}

//This displays the page number
void HMI_display_page(uint8_t page) {
  Serial1.print(F("t0.txt=\""));
  Serial1.print(F("This is page "));
  Serial1.print(page);
  Serial1.print(F("\""));
  Serial1.print(F("\xFF\xFF\xFF"));
}

void HMI_P1_display_slider(uint8_t slider_d1, uint8_t slider_d0) {
  uint16_t slider_val = (slider_d1 <<8 | slider_d0);
  
  //This displays byte 1 of the slider value in HEX
  Serial1.print(F("t2.txt=\""));
  Serial1.print(slider_d1, HEX);
  Serial1.print(F("\""));
  Serial1.print(F("\xFF\xFF\xFF"));
  
  //This displays byte 0 of the slider value in HEX
  Serial1.print(F("t3.txt=\""));
  Serial1.print(slider_d0, HEX);
  Serial1.print(F("\""));
  Serial1.print(F("\xFF\xFF\xFF"));
  
  //This displays the complete slider value in decimal
  Serial1.print(F("t4.txt=\""));
  Serial1.print(slider_val);
  Serial1.print(F("\""));
  Serial1.print(F("\xFF\xFF\xFF"));
}

void HMI_startup_message() {
  Serial1.print(F("t0.txt=\""));
  Serial1.print(F("Nextion demonstration by Perry Bebbington. For support go to https://forum.arduino.cc/index.php?board=7.0"));
  Serial1.print(F("\""));
  Serial1.print(F("\xFF\xFF\xFF"));
}

//HMI_read takes the data sent from the Nextion to the serial port and processes it depending on what has been sent
//There are 3 levels of nested switch statements corresponding to the page, the type of object and the index of the object.
void HMI_read() {
  #define read_data_size 10                       //Size of buffer use to receive data from Nextion 
  static uint8_t HMI_read_data[read_data_size];   //This is a temporary buffer to hold the data from the display. Space for 10 bytes although this demonstration only uses 6 bytes
  static uint8_t HMI_read_data_i;                 //This is a count of how many bytes have been received from the display.
  static uint8_t a5count;                         //0xa5 repeated 3 times is used as a start indicator, this is a count of how many times it has been received.
  uint8_t readtemp;                               //This is to hold the last received byte to ensure that it is only read from the receive buffer once.
  
  while (Serial1.available() > 0) {               //Read every byte in the receive buffer
    readtemp = Serial1.read();
    if (readtemp == 0xa5) {                       //Count the number of times 0xa5 has been received
      ++a5count;
      if (a5count > 2) {
        a5count = 0;
        HMI_read_data_i = 0;
      }
    }
    else {
      a5count = 0;
    }
    HMI_read_data[HMI_read_data_i] = readtemp;
    if (HMI_read_data_i == 5) {
      switch (HMI_read_data[page]) {               //The page the data has come from
/* ---------- Page 0 ----------*/
        case page0:
          switch (HMI_read_data[type]) {
            case 0:
              HMI_display_page(HMI_read_data[Nindex]); //Select a page
              break;
            case 1:                               //In this demonstration case 1 is a button for setting the clock
              switch (HMI_read_data[Nindex]) {     //HMI_read_data[index] is the index of the type of button, so 0 to 5 as there are 6 buttons for setting the clock. Each case is a different button.
                case 0:
                  ++Dclock.Dhour;
                  if (Dclock.Dhour > 23) {
                    Dclock.Dhour = 0;
                  }
                  break;
                case 1:
                  --Dclock.Dhour;
                  if (Dclock.Dhour < 0) {
                    Dclock.Dhour = 23;
                  }
                  break;
                case 2:
                  ++Dclock.Dminute;
                  if (Dclock.Dminute > 59) {
                    Dclock.Dminute = 0;
                  }
                  break;
                case 3:
                  --Dclock.Dminute;
                  if (Dclock.Dminute < 0) {
                    Dclock.Dminute = 59;
                  }
                  break;
                case 4:
                  ++Dclock.Dsecond;
                  if (Dclock.Dsecond > 59) {
                    Dclock.Dsecond = 0;
                  }
                  break;
                case 5:
                  --Dclock.Dsecond;
                  if (Dclock.Dsecond < 0) {
                    Dclock.Dsecond = 59;
                  }
                  break;
              }
              HMI_display_clock();
              break;
          }
          break;
/* ---------- Page 1 ----------*/        
        case 1:                               //Case 1 means the data has come from page 1
          switch (HMI_read_data[type]) {
            case 0:                           //Data from the page itself, this is the post initialisation request to update the page, which displays the page number
              HMI_display_page(HMI_read_data[Nindex]);
              break;
            case 1:                           //Data from the slider on page 1
              HMI_P1_display_slider(HMI_read_data[data1], HMI_read_data[data0]);      //HMI_read_data[data1] is byte 1 of the slider value, HMI_read_data[data0] is byte 0 of the slider value
              break;
          }
          break;
      }
    }
    ++HMI_read_data_i;
    if (HMI_read_data_i >= read_data_size) {
      HMI_read_data_i = read_data_size - 1;
    }
  }
}

void clock_run() {
  static unsigned long previousMillis;
  unsigned long currentMillis = millis();
  const unsigned long interval = 1000;
  if (currentMillis - previousMillis >= interval) {
    previousMillis += interval;
    ++Dclock.Dsecond;
    if (Dclock.Dsecond > 59) {
      Dclock.Dsecond = 0;
      ++Dclock.Dminute;
      if (Dclock.Dminute > 59) {
        Dclock.Dminute = 0;
        ++Dclock.Dhour;
        if (Dclock.Dhour > 23) {
          Dclock.Dhour = 0;
        }
      }
    }
    HMI_display_clock();
  }
}

Nextion_demonstration43.ino (8.5 KB)