[Partially solved] ISR from SoftwareSerial port

Hi! I work with Nextion display, carrying the own microcontroller. Pressing the touch screen buttons, display sends on the serial port (which I hung on SoftwareSerial, pins 2 and 3, because UNO has only one built-in port) to boards lines. But if there are delays in loop, pressing not processed. How can I implement interrupt processing touchscreen response? I would be very grateful for the help.
Example:

#include "Nextion.h"

/*
 * Declare a button object [page id:0,component id:1, component name: "b0"]. 
 */
NexButton b0 = NexButton(0, 1, "b0");

char buffer[100] = {0};

/*
 * Register a button object to the touch event list.  
 */
NexTouch *nex_listen_list[] = 
{
    &b0,
    NULL
};

/*
 * Button component pop callback function. 
 * In this example,the button's text value will plus one every time when it is released. 
 */
void b0PopCallback(void *ptr)
{
    uint16_t len;
    uint16_t number;
    NexButton *btn = (NexButton *)ptr;
    memset(buffer, 0, sizeof(buffer));

    /* Get the text value of button component [the value is string type]. */
    btn->getText(buffer, sizeof(buffer));
    
    number = atoi(buffer);
    number += 1;

    memset(buffer, 0, sizeof(buffer));
    itoa(number, buffer, 10);

    /* Set the text value of button component [the value is string type]. */
    btn->setText(buffer);
}

void setup(void)
{    
    /* Set the baudrate which is for debug and communicate with Nextion screen. */
    nexInit();

    /* Register the pop event callback function of the current button component. */
    b0.attachPop(b0PopCallback, &b0);
}

void loop(void)
{   
    /*
     * When a pop or push event occured every time,
     * the corresponding component[right page id and component id] in touch event list will be asked.
     */
    nexLoop(nex_listen_list);
    delay(500);
}

Example of solving the problem for hardware Serial:

Get rid of the delay()s in loop().

Have a look at how millis() is used to manage timing without blocking in several things at a time

Also you may find the examples in Serial Input Basics - simple reliable ways to receive data without blocking.

...R

I can't remove the delay, because it arises from the survey of the temperature sensors

Maratk1n:
I can't remove the delay, because it arises from the survey of the temperature sensors

Nonsense.

Robin2:
Have a look at how millis() is used to manage timing without blocking in several things at a time

Maratk1n:
I can't remove the delay, because it arises from the survey of the temperature sensors

You may think you can't - but I reckon you could - by using the techniques in the examples I linked to.

Try ...

...R

I'm probably stupid. But how do I use it? As soon as the interrupt on software port, I need to run

nexLoop(nex_listen_list);

But now it just turns into a loop where the delays occur. Therefore, the data is lost

As soon as the interrupt on software port

Why? Serial data arrives slowly. Receiving ONE byte is generally NOT sufficient reason to need to do something RIGHT NOW!

You CAN poll the serial buffer, to see if there is data to process. Generally, this will cause the data to be recognized and handled soon enough, unless you have a lot of blocking code. If you do, CTRL-A, CTRL-X and start over.

PaulS:
Why? Serial data arrives slowly. Receiving ONE byte is generally NOT sufficient reason to need to do something RIGHT NOW!

For example, we have aircraft operated by bluetooth. HC-05 module is connected to pins 2 and 3 (SoftwareSerial). It is advisable to make an interrupt to the device did not crash

For example, we have aircraft operated by bluetooth.

So, the Arduino sends data TO the aircraft. Why does that require immediate handling of data that comes to the Arduino.

It is advisable to make an interrupt to the device did not crash

Who advised that? It is NOT necessary to interfere with the serial interrupts in order to handle incoming serial data as quickly as possible. SoftwareSerial uses interrupts differently, to send and receive serial data. It is most definitely NOT advisable to interfere with the timing of SoftwareSerial interrupts.

Maratk1n:
I'm probably stupid.

I doubt if you are stupid, but there is no evidence so far that you have taken notice of any of the advice you have been given.

...R

PaulS:
So, the Arduino sends data TO the aircraft.

Really? I thought that the Arduino first receives data from the remote control. Then sends on aircraft.
Typically, the port checks carried out in loop. But if in the loop are held long and difficult work, before polling the port will take time

But if in the loop are held long and difficult work, before polling the port will take time

So, do not write long or difficult work in loop(). The loop() function should iterate often.

But if in the loop are held long and difficult work, before polling the port will take time

Yes, but "polling the port" is really "polling the input buffer", which has room for 64 characters. Calling Serial.read() removes one character from that buffer, which makes room for one more new character. Each received character causes an interrupt. That interrupt puts the new character into the input buffer, but only if there is room. The 65th character will be lost.

So you can only lose data if you take longer than 64 character "times". At 9600, each character takes ~1ms, so you must "poll the input buffer" every 64ms. If your loop functions take longer than that, you probably need to restructure your sketch. Do not use delay. :stuck_out_tongue:

However, some libraries will "block" for longer than that, because they are waiting on some device. SD logging is the notable example, but most libraries offer blocking and non-blocking functions.

For example, the Nextion may have a method that waits (blocks) for a button to be pressed. But it almost certainly has a method that simply checks (non-blocking) for a button press. If the button is not pressed, it returns a false immediately. Call the non-blocking method from loop, frequently.

Are you sure your other processing takes more than 64ms? Can it be broken up into smaller steps?

Cheers,
/dev

/dev:
Do not use delay. :stuck_out_tongue:

The problem is that I do not use delay :frowning:
A short example of my program:

#include "Nextion.h"
#include "HX711.h"
/*
 * Declare a button object [page id:0,component id:1, component name: "b0"]. 
 */
NexButton b0 = NexButton(0, 1, "b0");
NexText t0 = NexText(0, 2, "t0");

char buffer[100] = {0};
int t = 0;
int weight;

/*
 * Register a button object to the touch event list.  
 */
NexTouch *nex_listen_list[] = 
{
    &b0,
    NULL
};

/*
 * Button component pop callback function. 
 * In this example,the button's text value will plus one every time when it is released. 
 */
void b0PopCallback(void *ptr)
{
    uint16_t len;
    uint16_t number;
    NexButton *btn = (NexButton *)ptr;
    memset(buffer, 0, sizeof(buffer));

    /* Get the text value of button component [the value is string type]. */
    btn->getText(buffer, sizeof(buffer));
    
    number = atoi(buffer);
    number += 1;

    memset(buffer, 0, sizeof(buffer));
    itoa(number, buffer, 10);

    /* Set the text value of button component [the value is string type]. */
    btn->setText(buffer);
}

void setup(void)
{    
    /* Set the baudrate which is for debug and communicate with Nextion screen. */
    nexInit();

    /* Register the pop event callback function of the current button component. */
    b0.attachPop(b0PopCallback, &b0);
}

void loop(void)
{   
    /*
     * When a pop or push event occured every time,
     * the corresponding component[right page id and component id] in touch event list will be asked.
     */
    nexLoop(nex_listen_list);

    weight = Get_Weight(); //get weight
    memset(buffer, 0, sizeof(buffer)); //clear buffer
    itoa(weight, buffer, 10); //write weight in buffer
    t0.setText(buffer);
}

So, Get_Weight() performed 13 times per second. Without it works fine. From this I concluded that the button does not work, because nexLoop(nex_listen_list) is done at the wrong time.

I also tried to put a crutch:

void loop(void)
{   
    /*
     * When a pop or push event occured every time,
     * the corresponding component[right page id and component id] in touch event list will be asked.
     */
    nexLoop(nex_listen_list);

    if (t == 10000)
    {
        weight = Get_Weight(); //get weight
        memset(buffer, 0, sizeof(buffer)); //clear buffer
        itoa(weight, buffer, 10); //write weight in buffer
        t0.setText(buffer);
        t = 0;
    }
    t++;
}

It helped at first, but the code grows, so decided to take on interrupts

So, Get_Weight() performed 13 times per second. Without it works fine.

But, you did not share that code, so we can not see why it is only called 13 times per second.

PaulS:
But, you did not share that code, so we can not see why it is only called 13 times per second.

I agree, I misled you, I'm sorry.
But I write that

Maratk1n:
I can't remove the delay, because it arises from the survey of the temperature sensors

Delays occur due to poll the temperature sensors (DS18B20), strain gauge transducer (HX711)

Delays occur due to poll the temperature sensors (DS18B20),

There are ways to read the Dallas Temperature sensors without using delays.

strain gauge transducer (HX711)

What process are you using to read this device?

PaulS:
What process are you using to read this device?

I use Get_Weight() from library:

HX711.h

#ifndef __HX711__H__
#define __HX711__H__

#include <Arduino.h>

#define HX711_SCK A1
#define HX711_DT A0

extern void Init_Hx711();
extern unsigned long HX711_Read(void);
extern unsigned int Get_Weight();
extern void Get_Maopi();

#endif

HX711.cpp

#include "HX711.h"

long HX711_Buffer = 0;
long Weight_Maopi = 0, Weight_Shiwu = 0;

void Init_Hx711()
{
	pinMode(HX711_SCK, OUTPUT);	
	pinMode(HX711_DT, INPUT);
}


void Get_Maopi()
{
	HX711_Buffer = HX711_Read();
	Weight_Maopi = HX711_Buffer/100;		
} 

unsigned int Get_Weight()
{
	HX711_Buffer = HX711_Read();
	HX711_Buffer = HX711_Buffer/100;

	Weight_Shiwu = HX711_Buffer;
	Weight_Shiwu = Weight_Shiwu - Weight_Maopi;		
	Weight_Shiwu = - (unsigned int)((float)Weight_Shiwu/9.45); 	
	return Weight_Shiwu;
}

//****************************************************
//Read HX711
//****************************************************
unsigned long HX711_Read(void)
{
	unsigned long count; 
	unsigned char i;
	bool Flag = 0;

	digitalWrite(HX711_DT, HIGH);
	delayMicroseconds(1);

	digitalWrite(HX711_SCK, LOW);
	delayMicroseconds(1);

  	count=0; 
  	while(digitalRead(HX711_DT)); 
  	for(i=0;i<24;i++)
	{ 
	  	digitalWrite(HX711_SCK, HIGH); 
		delayMicroseconds(1);
	  	count=count<<1; 
		digitalWrite(HX711_SCK, LOW); 
		delayMicroseconds(1);
	  	if(digitalRead(HX711_DT))
			count++; 
	} 
 	digitalWrite(HX711_SCK, HIGH); 
	count ^= 0x800000;
	delayMicroseconds(1);
	digitalWrite(HX711_SCK, LOW); 
	delayMicroseconds(1);
	
	return(count);
}

@Maratk1n, are you saying that the Get_Weight() function is very slow and is blocking other actions?

If so, maybe there is a solution, but I can't see how we could have inferred that that is the problem from your Original Post.

I think you need a different function to read the HX711 - one that starts a reading but does not wait for the answer and periodically checks to see if the answer is ready.

Maybe the library already has functions that facilitate that?

...R

I would not write here, not trying to sort out the problem on their own. There is one library, but it is still slower (link). The problem is not only this, but also in getting the temperature.
I think that the interruption could solve the problem.I found a solution for hardware port (Serial, link).
Here I would like to ask for help from the interrupt for the software port.
Other solutions to the problem, in addition to interrupt port, I do not see, unfortunately :roll_eyes: