Start a new topic

Slow Loop, Arduino and Nextion

Hi all

I am writing a code to control my marine tank pumps and monitor the external water levels,

the code is working fine this is not a how too or cant work it out question,

The interface is via digital pins (level sensors) and digital outputs (Relays)

The Arduino Mega is interfaced with a Nextion EN 7", again this all works well and I can see the button presses coming in via the serial. THe hole package works

no with the issue, the code is part complete say 10-20%, thus the extra bytes and input/outputs not assigned as yet but the code is slow to cycle, about 1 second each loop (I changed an output to cycle each loop to test it)

as the code is very slow to cycle, it is missing the incoming bits from the Nextion (approx. 1 out of 10 presses change the state of the output), thus the Arduino is not acting on them. its only reading them if I happen to press the button when the code is in the right spot.


the sendCommands change the indications on the Nextion for the Pump and Level indicators.

is my formatting that wrong its slowing it down, can I somehow take some of the code out of the loop, have I completed the code "long hand" is there a better way, the rest of the code is repeats of the attached thus looking for help prior to writing it

Ben, thanks in advance******************

//****Code****

#include <Arduino.h>
#include "Nextion.h"
#include "NexTouch.h"

#include <dht.h>

dht DHT;
//***** Temp Sen Pin *****
#define DHT11_PIN 5
// parameters  page #, component .id, component .objname

//***** Control Buttons *****
NexDSButton pump1btn = NexDSButton(0,2,"bt0");
NexDSButton pump2btn = NexDSButton(0,3,"bt1");
NexDSButton uvbtn = NexDSButton(0,4,"bt2");
NexDSButton chillbtn = NexDSButton(0,5,"bt3");
NexDSButton skimbtn = NexDSButton(0,12,"bt4");
NexDSButton drainbtn = NexDSButton(0,6,"bt5");
NexDSButton fillatobtn = NexDSButton(0,7,"bt6");
NexDSButton fillsaltbtn = NexDSButton(0,8,"bt7");
NexDSButton fullautobtn = NexDSButton(0,9,"bt8");
NexDSButton feedbtn = NexDSButton(0,10,"bt9");
NexDSButton waterchgbtn = NexDSButton(0,11,"bt10");

 uint32_t digitalstate0, digitalstate1, digitalstate2, digitalstate3, digitalstate4,
 digitalstate5, digitalstate6, digitalstate7, digitalstate8, digitalstate9, digitalstate10  = 0;

 
 //***** Relay Outputs 13-6 - 8 total *****
 int pump1Pin = 13;
 int pump2Pin = 12;
 int uvPin = 11;
 int chillPin = 10;
 int skimPin = 9;
 int drainPin = 8;
 int atoPin = 7;
 int saltPin = 6;

//***** tank inputs *****

int salthigh = 22;
int saltlow = 24;
int atohigh = 26;
int atolow = 28;
int topoff = 30;
int sumpchg = 32;
int sumphigh = 34;
int sumplow = 36;
int sumplvl = 38;
int socks = 40;

//***** Internal code bits *****
byte alarm;
byte pump1;
byte pump1sw;
byte pump2;
byte pump2sw;
byte uv;
byte uvsw;
byte chill;
byte chillsw;
byte skim;
byte skimsw;
byte drain;
byte drainsw;
byte ato;
byte atosw;
byte salt;
byte saltsw;
byte fullauto;
byte fullautosw;
byte waterchange;
byte waterchangesw;
byte feedtank;
byte feedtanksw;
byte sumpwchg;
byte sumpfull;
byte sumpempty;
byte sump;
byte temphigh;
byte templow;
byte saltfull;
byte saltempty;
byte atofull;
byte atoempty;
byte topfull;
byte topempty;
byte socksblk;


NexTouch *nex_listen_list[] = {
  &pump1btn, &pump2btn, &uvbtn, &chillbtn, &skimbtn, &drainbtn,
  &fillatobtn, &fillsaltbtn, &fullautobtn, &feedbtn, &waterchgbtn,
  NULL
};
//*****converts button to bits *****

 void pump1btnReleaseCallback(void *ptr) {
  digitalstate0 = 1-digitalstate0;
  if(digitalstate0==1) {
  pump1sw=LOW;
  } else {
  pump1sw=HIGH;
  }
 }
  void pump2btnReleaseCallback(void *ptr) {
  digitalstate1 = 1-digitalstate1;
  if(digitalstate1==1) {
  pump2sw=HIGH;
  } else {
  pump2sw=LOW;
  }
 }
  void uvbtnReleaseCallback(void *ptr) {
  digitalstate2 = 1-digitalstate2;
  if(digitalstate2==1) {
  uvsw=HIGH;
  } else {
  uvsw=LOW;
  }
 }  void chillbtnReleaseCallback(void *ptr) {
  digitalstate3 = 1-digitalstate3;
  if(digitalstate3==1) {
  chillsw=HIGH;
  } else {
  chillsw=LOW;
  }
 }  void skimbtnReleaseCallback(void *ptr) {
  digitalstate4 = 1-digitalstate4;
  if(digitalstate4==1) {
  skimsw=HIGH;
  } else {
  skimsw=LOW;
  }
 }  void drainbtnReleaseCallback(void *ptr) {
  digitalstate5 = 1-digitalstate5;
  if(digitalstate5==1) {
  drainsw=HIGH;
  } else {
  drainsw=LOW;
  }
 }  void fillatobtnReleaseCallback(void *ptr) {
  digitalstate6 = 1-digitalstate6;
  if(digitalstate6==1) {
  atosw=HIGH;
  } else {
  atosw=LOW;
  }
 }  void fillsaltbtnReleaseCallback(void *ptr) {
  digitalstate7 = 1-digitalstate7;
  if(digitalstate7==1) {
  saltsw=HIGH;
  } else {
  saltsw=LOW;
  }
  //***** NON critcal bits are set HIGH when not used, fail safe *****
 }  void fullautobtnReleaseCallback(void *ptr) {
  digitalstate8 = 1-digitalstate8;
  if(digitalstate8==1) {
  fullautosw=LOW;
  } else {
  fullautosw=HIGH;
  }

  //***** NON critical bits are set HIGH when not used, or after power back on -  fail safe *****

 }  void feedbtnReleaseCallback(void *ptr) {
  digitalstate9 = 1-digitalstate9;
  if(digitalstate9==1) {
  feedtanksw=LOW;
  } else {
  feedtanksw=HIGH;
  }

//***** NON critical bits are set HIGH when not used, or after power back on -  fail safe *****

 }  void waterchgbtnReleaseCallback(void *ptr) {
  digitalstate10 = 1-digitalstate10;
  if(digitalstate10==1) {
  waterchangesw=LOW;
  } else {
  waterchangesw=HIGH;
  }
 }

char buffer[100] = {0};
void setup(void) {

//***** Output bits *****


 
  pinMode(pump1Pin,OUTPUT);
  pinMode(pump2Pin,OUTPUT);
  pinMode(uvPin,OUTPUT);
  pinMode(chillPin,OUTPUT);
  pinMode(skimPin,OUTPUT);
  pinMode(drainPin,OUTPUT);
  pinMode(atoPin,OUTPUT);
  pinMode(saltPin,OUTPUT);

  //***** input bits*****

 
  pinMode(salthigh,INPUT);
  pinMode(saltlow,INPUT);
  pinMode(atohigh,INPUT);
  pinMode(atolow,INPUT);
  pinMode(topoff,INPUT);
  pinMode(sumpchg,INPUT);
  pinMode(sumphigh,INPUT);
  pinMode(sumplow,INPUT);
  pinMode(sumplvl,INPUT);
  pinMode(socks,INPUT);

digitalWrite(salthigh, HIGH);
digitalWrite(saltlow, HIGH); 
digitalWrite(atohigh, HIGH); 
digitalWrite(atolow, HIGH); 
digitalWrite(topoff, HIGH); 
digitalWrite(sumpchg, HIGH); 
digitalWrite(sumphigh, HIGH); 
digitalWrite(sumplow, HIGH); 
digitalWrite(sumplvl, HIGH); 
digitalWrite(socks, HIGH); 

digitalWrite(pump1Pin, HIGH);
digitalWrite(pump2Pin, HIGH); 
digitalWrite(uvPin, HIGH); 
digitalWrite(chillPin, HIGH); 
digitalWrite(skimPin, HIGH); 
digitalWrite(drainPin, LOW); 
digitalWrite(atoPin, LOW); 
digitalWrite(saltPin, LOW); 

//***** NON critical bits are set LOW when not used, or after power back on -  fail safe *****

  nexInit();

  /*
  *  &pump1btn, &pump2btn, &uvbtn, &chillbtn, &skimbtn, &drainbtn,
  &fillatobtn, &fillsaltbtn, &fullautobtn, &feedbtn, &waterchgbtn,
  */
pump1btn.attachPop(pump1btnReleaseCallback, &pump1btn);
pump2btn.attachPop(pump2btnReleaseCallback, &pump2);
uvbtn.attachPop(uvbtnReleaseCallback, &uvbtn);
chillbtn.attachPop(chillbtnReleaseCallback, &chillbtn);
drainbtn.attachPop(drainbtnReleaseCallback, &drainbtn);
fillatobtn.attachPop(fillatobtnReleaseCallback, &fillatobtn);
fillsaltbtn.attachPop(fillsaltbtnReleaseCallback, &fillsaltbtn);
fullautobtn.attachPop(fullautobtnReleaseCallback, &fullautobtn);
feedbtn.attachPop(feedbtnReleaseCallback, &feedbtn);
waterchgbtn.attachPop(waterchgbtnReleaseCallback, &waterchgbtn);


  Serial.begin(9600);
  dbSerialPrintln("setup done");
}
void serialFlush(){
  while(Serial.available() > 0) {
  }
}
 void loop() {

//Get Pins data

//*****salt tank *****
saltfull = digitalRead(salthigh);
saltempty = digitalRead(saltlow);
//*****sump main*****
sump = digitalRead(sumplvl);
sumpwchg = digitalRead(sumpchg);
sumpfull = digitalRead(sumphigh);
sumpempty = digitalRead(sumplow);
//*****ato tank*****
atofull = digitalRead(atohigh);
atoempty = digitalRead(atolow);
//*****Top off tank*****
topfull = digitalRead(topoff);
//*****SOCKS******
socksblk = digitalRead(socks);


//*****SOCKS*****

if (socksblk==LOW){
sendCommand("bt50.pic0=36");
sendCommand("bt50.pic1=36");
 } else{
sendCommand("bt50.pic0=35");
sendCommand("bt50.pic1=35");
 }
//*****SUMP MAIN LEVEL indicators*****

if (sump==LOW){
sendCommand("bt68.pic0=22");
sendCommand("bt68.pic1=22");
 } else{
sendCommand("bt68.pic0=21");
sendCommand("bt68.pic1=21");
 }

if (sumpwchg==LOW){
sendCommand("bt103.pic0=46");
sendCommand("bt103.pic1=46");
 } else{
sendCommand("bt103.pic0=47");
sendCommand("bt103.pic1=47");
 } 
 
if (sumpfull==LOW){
sendCommand("bt102.pic0=44");
sendCommand("bt102.pic1=44");
 } else{
sendCommand("bt102.pic0=47");
sendCommand("bt102.pic1=47");
 } 

if (sumpempty==LOW){
sendCommand("bt101.pic0=43");
sendCommand("bt101.pic1=43");
 } else{
sendCommand("bt101.pic0=47");
sendCommand("bt101.pic1=47");
 }
sendCommand("bt100.pic0=45");
sendCommand("bt100.pic1=45");

//*****ATO TOP OFF TANK LEVEL indicators*****
if (topfull==LOW){

sendCommand("bt41.pic0=44");
sendCommand("bt41.pic1=44");
 } else{
sendCommand("bt41.pic0=47");
sendCommand("bt41.pic1=47");
 } 

sendCommand("bt40.pic0=45");
sendCommand("bt40.pic1=45");

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

//*****ATO TANK LEVEL indicators*****
if (atofull==LOW){

sendCommand("bt32.pic0=44");
sendCommand("bt32.pic1=44");
 } else{
sendCommand("bt32.pic0=47");
sendCommand("bt32.pic1=47");
 } 

if (atoempty==LOW){

sendCommand("bt31.pic0=43");
sendCommand("bt31.pic1=43");

 } else{
sendCommand("bt31.pic0=47");
sendCommand("bt31.pic1=47");
 }
sendCommand("bt30.pic0=45");
sendCommand("bt30.pic1=45");

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

//*****SALT TANK LEVEL indicators*****
if (saltfull==LOW){

sendCommand("bt22.pic0=44");
sendCommand("bt22.pic1=44");
 } else{
sendCommand("bt22.pic0=47");
sendCommand("bt22.pic1=47");
 } 

if (saltempty==LOW){

sendCommand("bt21.pic0=43");
sendCommand("bt21.pic1=43");

 } else{
sendCommand("bt21.pic0=47");
sendCommand("bt21.pic1=47");
 }
sendCommand("bt20.pic0=45");
sendCommand("bt20.pic1=45");

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

//Waterchange button only

  if (waterchange==HIGH) {
 
sendCommand("bt10.pic0=41");
sendCommand("bt10.pic1=41");
 } else{
sendCommand("bt10.pic0=40");
sendCommand("bt10.pic1=40");
 } 
 //PUMP1 OUTPUT ********************************************************

  if (pump1sw==LOW && waterchange==LOW) {
 
sendCommand("bt60.pic0=27");
sendCommand("bt60.pic1=27");
sendCommand("bt0.pic0=28");
sendCommand("bt0.pic1=28");

  digitalWrite(pump1Pin, HIGH);
  } else{
sendCommand("bt60.pic0=24");
sendCommand("bt60.pic1=24");
sendCommand("bt0.pic0=29");
sendCommand("bt0.pic1=29");
digitalWrite(pump1Pin, LOW);
  }
 //PUMP2 OUTPUT ********************************************************

  if (pump2sw==LOW && waterchange==LOW) {
 
sendCommand("bt61.pic0=27");
sendCommand("bt61.pic1=27");
sendCommand("bt1.pic0=30");
sendCommand("bt1.pic1=30");

  digitalWrite(pump2Pin, HIGH);
  } else{
sendCommand("bt61.pic0=24");
sendCommand("bt61.pic1=24");
sendCommand("bt1.pic0=31");
sendCommand("bt1.pic1=31");
digitalWrite(pump2Pin, LOW);
  }
  nexLoop(nex_listen_list);
 }




Baud rate.


Count characters being sent

- plus 3 bytes for every use of send command

Add into this your debug usage

 as debug is consecutive and not concurrent


If ~ 10% of baudrate -> most is as it should be.

A char/byte takes 10 bits to transmit

 - 8 for data, 1 for parity, 1 for stopbit.

So since there is little by way of send only on conditions of change

at 9600 baud you are limited to roughly 960 chars/bytes per second.


RX/TX have more errors at higher baudrates

 - you maybe able to test incrementally higher rates allowing higher byte counts.


Higher Nextion valid rates are 19200, 38400, 57600 and 115200.

Once you have debugged certain sections, and are confident,

   then there is room to send less debug to Serial Monitor.


Higher baudrates for serial Monitor also include 230400 and 250000.

Also decreasing sent byte count is possible by sending only if value changes


When confident your function is working reliably, use shadow values


if old_byte != new_byte then {

  sendCommand()

  old_byte = new_byte 

}


requires slightly more sram usage, but decreases your byte counts.

Balance for your needs

How can I speed up the Nextion to a higher rate to try that. There should be no more send commands. Just a bunch of code now. All the sendcommands are finished. So a higher rate might work

Four places:

   - Nextion device and Arduino nexSerial in nexInit() need to match (1 and 2)

   - Arduino Serial monitor and dbSerial in nexInit() need to match (3 and 4)


1) Nextion HMI file page0 Preinitialization Event

    bauds=57600  // set to new default baudrate


2) nexInit() in NexHardware.cpp

    nexSerial.begin(57600) // set baudrate needed to connect to Nextion


3) when connecting in Serial Monitor - select 57600


4) nexInit() in NexHardware.cpp

    dbSerialBegin(57600) // set baudrate Serial Monitor needs to use


   

Thanks again Patrick. Just got home to try. Please assist. Where to I type number one. 1) Nextion HMI file page0 Preinitialization Event bauds=57600 // set to new default baudrate I can't see any window that is Preinitialization. Checked the internet. The only way I can see is to try connect Nextion Via the Arduino to the PC ? To change it. ? Or is there another way. I have p0. Ah. Here we go. Window just appeared after running de bugger. Cheers.

A general observation, but why does your main loop need to be checking these items with each cycle? i.e. saltful or salthigh? Can you not drop most of those calls into a timed function. i.e. every few seconds, or even longer, check the sensors, then respond?  That way, your main loop can run more freely and watch for messages from the Nextion, then react?   I use Blynk for my projects which forces you to think about ensuring the main loop cycles without delays or code that will bog it down too much.  All of my function calls in the main loop are timer based and trigger only when needed. 

Thanks Dave. Would love too but still don't know how. I have upped the baud rate to 115200. That has helped. If you could assist and take one out for me and show me how to set up a timed loop that's more than great. My coding is still long hand C++. Not up with the new ways and library's as yet. I have still got to include the temp sensors that will need to be on a 5 second loop. I only have ever used 1 X void loop() in all my codes to date. Never anything else. Sounds exciting. In the two-three year gap between projects arduino has come along way.

Ben,

Have a look at the following example.  You can set 2 different trigger times to execute doFunciton1 & doFunction2.   You can set the trigger time for each, and do this numerous times.   This allows your loop to run with limited delays.  Just ensure you are efficient in your functions.  


 

unsigned long prevTempMillis = 0;
unsigned long refreshTempInterval = 60000;
unsigned long prevLEDResetMillis = 0;
unsigned long ledResetInterval = 3615000;  //361500  = 1hr + 15 seconds  
 
 
void setup()
{
  Serial.begin(115200);
}



 
void loop()
{
  unsigned long currentMillis = millis();
 
 
  if (currentMillis - prevTempMillis >= refreshTempInterval) 
  {
    prevTempMillis = currentMillis; // save the last time we checked
    yield();

    doFunction1();
  }
 
 
  if (currentMillis - prevLEDResetMillis >= ledResetInterval)
  {
    prevLEDResetMillis = currentMillis; // save the last time we checked
    yield();
	doFunction2();
  }
}


void doFunction1()
{
  //do stuff here
}


void doFunction2()
{
  //do stuff here
}

 

Thanks Dave


will do,


have put the main scope in the void loop


will put the water sensors in the doFunction1() set at 5 seconds

and the

temp and other sensors in the doFunction2() set at 60 seconds


BUT


when I compile the code I get the


exit status 1
'doFunction1' was not declared in this scope


do I need to add declaration above the void loop()  in the void setup() or above that


if so, what,


 

unsigned long prevTempMillis = 0;
unsigned long refreshTempInterval = 60000;
unsigned long prevLEDResetMillis = 0;
unsigned long ledResetInterval = 3615000;  //361500  = 1hr + 15 seconds  
 
 
void setup()
{
  Serial.begin(115200);
}



 
void loop()
{
  unsigned long currentMillis = millis();
 
 
  if (currentMillis - prevTempMillis >= refreshTempInterval) 
  {
    prevTempMillis = currentMillis; // save the last time we checked
    yield();

    doFunction1(); // GETTING ERROR HERE
  }
 
 
  if (currentMillis - prevLEDResetMillis >= ledResetInterval)
  {
    prevLEDResetMillis = currentMillis; // save the last time we checked
    yield();
	doFunction2(); // GETTING ERROR HERE
  }
}


void doFunction1()
{
  //do stuff here
}


void doFunction2()
{
  //do stuff here
}

 



@Ben


It's just a C++ compiler thing.


Functions should at least be declared before you use them. However if you're going to declare them you might as well define them as well. So in order for your sketches to be complaint, just remember to place them above wherever their first call is, usually above setup().

If I remember correctly, such rigid compliance can be got round in Arduino .ino if you #include "Arduino.h" at the top of your sketch.

More reading here http://www.studytonight.com/cpp/functions-in-cpp

agreed with the above, sorry should of re worded my question, how do I declare the "doFunction1"


I know how to declare pins and input/outputs, byte, int, const, but how and where do I pre declare a loop name "doFunction1" and "doFunction2"

#include "Arduino.h" id at the top of my sketch


 

#include <Arduino.h>
#include "Nextion.h"
#include "NexTouch.h"

 


Mine compiles fine in IDE 1.6.11..  Either way, you should be able to just move the functions between Setup() and loop() and it should work.

 

#include <Arduino.h>
#include "Nextion.h"
#include "NexTouch.h"

# other includes and variables here

void doFunction1() {

your function code here (it's definition)

}

void doFunction2() {

your function code here (it's definition)

}

void setup() {

setup routine here

}

void loop() {

main loop code here

}

 

Login or Signup to post a comment