comparator ISR requires delays for project but the internet says absolutely not

i am sending chars via binary code flashes of a laser from one arduino to the other, there has to be an air-gap for the project to work. One arduino has a keyboard + laser, and the other has a screen + receiver. Now the keyboard uses a normal attachInterrupt to keep a buffer of input vals. The amount of time it takes to write to the screen on the receiver side seems to be making the receiver miss chars if I type too fast, so I wrote a comparator interrupt for the laser receiver (see change in light flash on A0 go into ANALOG_COMP_vect). However I am hitting a wall because the light flashing for the binary of each char is a time dependent action (has to measure with a square wave period to determine whether each bit is 0 or 1) and needs a delay to keep in sync. But delays do not work within the ISR...and the internet is generally opposed to the concept of using delays in an ISR so does anyone have suggestions of how I should be thinking about this differently? thanks!

skrinsky:
does anyone have suggestions of how I should be thinking about this differently? thanks!

Think about reading the three stickies that lead off this topic.

Non-blocking timing tutorials:
Several things at a time.
Beginner's guide to millis().
Blink without delay().

The ISR tells the main program (via shared variables) that something has happened, then the main program takes appropriate action.

If the MCU is a ESP32 the RMT API would work well for your application.

On an ESP32 'millis()' is not stopped when an interrupt occurs.

So all of those use millis() and unless I am missing something millis() is also frozen upon entering an ISR? If I print millis() and then do some stuff in the ISR and then print it again it appears to be the same number.

And @Idahowalker I am using an uno :confused: that looks cool though

skrinsky:
So all of those use millis() and unless I am missing something millis() is also frozen upon entering an ISR? If I print millis() and then do some stuff in the ISR and then print it again it appears to be the same number.

And @Idahowalker I am using an uno :confused: that looks cool though

You don't print something in an ISR functions. All interrupts are disabled.
Paul

So all of those use millis() and unless I am missing something millis() is also frozen upon entering an ISR? If I print millis() and then do some stuff in the ISR and then print it again it appears to be the same number.

Interrupts are disabled while an ISR is running. The millis() function depends on interrupts do it cannot update while the ISR is running. You can record the value of millis() in the ISR and you can compare the current value of millis() to a previously recorded value of millis() in an ISR.

Okay so let me explain the typing fast scenario- I write “hi” very quickly, the keyboard gets it in the buffer, flashes the binary code for the ‘h’ and then the receiver sees this, and then goes to print it to a tft screen. While it is printing to the screen, the ‘i’ begins to flash. It misses part of the ‘i’, so it turns into like a ‘?’ char, oh no disaster! I write a comparator ISR with the hope of interrupting amidst the screen writing, going to “see the ‘i’” and then returning to the place in the code where we are writing to the tft screen. “Seeing the ‘i’” or seeing any char is a time dependent action, and has to be because of the nature of flashing lights for binary code. This is how the program “sees” a char
delay(PERIOD*1.5);
for(int i = 0; i < 8; i++)
{
ret = ret | get_ldr2() << i;

delay(PERIOD);

}
return ret;
I’m not sure how setting millis in the interrupt could help, because when it returns out of the interrupt in the specific scenario in which the interrupt is necessary, the program is somewhere in the writing to tft screen part of the code. And will have missed the flashes (PERIOD is defined as 15 so they are fast).

I don't know that hardware you are using or what your commnication protocol is.

But I had to do some similar type of for decoding of a signal for a WWVB clock.

Here is what I did.
I set a pin to interrupt on any change. This will generate an interrupt on the pin rising up or falling down.
In the ISR, it keeps track of some state, but it basically looks at the amount of time since the last transition and can decide how to decode the bits into a full message.
It processes the bits as they come in to buffer up a message and sets a flag when a new message has arrived that the foreground can look at.

You can use either millis() or micros() to determine the amount of time since the last interrupt depending on the resolution that you need.

This keeps the ISR very fast and short, and the foreground simple since it simply has to check for a flag to see if there is a fully decoded byte/message/packet to process.

--- bill

How about connecting your laser TX and RX to the appropriate pins on a processor UART and send / receive data just like you do with the Serial object?

gfvalvo:
How about connecting your laser TX and RX to the appropriate pins on a processor UART and send / receive data just like you do with the Serial object?

With the OP's delay of 15mS between bits, that would be 66.67 baud. Assuming the data rate cannot reliably be increased much above that, you would need a software serial library that could handle very low baud rates.

david_2018:
With the OP's delay of 15mS between bits, that would be 66.67 baud. Assuming the data rate cannot reliably be increased much above that, you would need a software serial library that could handle very low baud rates.

OP provided no reason why it must run so slow. Surely the laser / receiver hardware can run at least as fast as the slowest UART rate available.

So the reason for not using uart is that the send and receive must be air-gapped (the most crucial part of the design of this device is that there are no physicial electronic components touching between the two arduinos.) As far as what i can understand with uart you need a shared ground. Am I incorrect?

Bill’s post is giving me some ideas to play with i’ll check back in. If there is something i am missing with uart that would solve all the woes though?

skrinsky:
As far as what i can understand with uart you need a shared ground. Am I incorrect?

You are incorrect.

You would need a common ground if you connected the two UART electrically. But, you’re “connecting” them optically.

So, you just need a common ground between Arduino #1 and the laser TX. Then, you need a common ground between the optical RX and Arduino #2. But, you need those for what you’re currently doing anyway. You don’t need a common ground between Arduino #1 and Arduino #2.

Oh cool okay thanks for the clarification. One more question for using uart, the laser is written with a digitalpin so it shouldn't be a problem but the receiver is read with an analog pin which was why i had to write the comparator...but that makes it record a change on d7. I could write the rx pin to mirror d7, but is there a better way to use the rx pin with the receiver?

david_2018:
With the OP's delay of 15mS between bits, that would be 66.67 baud. Assuming the data rate cannot reliably be increased much above that, you would need a software serial library that could handle very low baud rates.

If my calculations are correct, SoftwareSerial can't go much below 184 baud before the 16-bit math used to calculate the bit times overflows.

It looks like Serial can go down to 31 baud so that might be a solution if you don't need it for debugging.

skrinsky:
but is there a better way to use the rx pin with the receiver?

I'd use an external hardware comparator to turn the optical RX output into a clean digital signal.

Ok thanks everyone for the help, appreciate it immensely!

Oh no i am back with one more question. One arduino has two receivers because there are two different information sources but only one rx pin. The two information sources come from lasers connected to two seperate arduinos so they cannot be combined…would you need to multiplex the rx pin/can you even do that?