Morse Code Transceiver - problems with interrupts?

I’m developing a Morse code transceiver using the Uno R3 and some additional support modules (IR transmitter with a 38KHz NE555 astable circuit, IR receiver module & a 16x2 LCD I2C module). I’ve also been able to get it to work on a Mega 2560 with a few pin changes where the LCD I2C module connections.

I’m piggybacking a 1mS timer0 interrupt for Morse code transmission, and attaching an interrupt for Morse code reception.

I can verify the Morse code transmission & reception is working fine via the serial monitor, but when I enable the (I2C) lcd.print(x) lines of code, the program appears to hang.

I have been able to use a standard 16x2 LCD module without the I2C interface, but I’d prefer to use the I2C interface to minimize connections.

As far as I can tell, calling the I2C lcd.print(x) somehow disrupts the interrupts, and I haven’t been able to figure out how or where this occurs.

Below is an attachment of the program as it currently stands.

Any help would be appreciated and thanks in advance!

interrupt2.ino (12.9 KB)

I2C is using interruptions as well as Serial, so you can't invoke them in you ISR (through lcd.print() or Serial.print()) as interruptions are disabled in the context of the ISR (an interrupt will not be interrupted). (Serial might appear to kinda work if you don't fill up the output buffer but really the printing will be handled once you've left the ISR (EDIT: not true). I2C won't though.)

You need to keep the ISR as short as possible - think in micro-seconds. Set a flag to make note that something needs to happen (using a volatile bool for example), and deal with the slow process of driving the display in the main loop by checking that flag.

J-M-L - thanks for the quick response!

Yup, shortly after I made this post, I moved the lcd.print() codes out of the ISR into loop() and set a flag to indicate the LCD needs updating .. which works fine. My bad.

Now I just need to get the LCD to scroll correctly ...

The current LCD is a 16 x 2 type with an I2C interface - the intent is to use line 1 to display the transmitted Morse characters and line 2 to display the received Morse characters.

Yes, there is the lcd.autoScroll() function, but it scrolls the ENTIRE display instead of just the selected line at the cursor location. I need to crack open the LCD driver chip techsheets to see how the LCD handles it, but for now I'm using code to do that - which causes the LCD line to flicker during updates (because I update all 16 characters of line 2 on each character update).

Also discovered that tone(pin, frequency, duration) has a frequency limitation of 32,767Hz (need 38,000Hz for the IR emitter), so working on configuring timer 2 for that snippet of code.

J-M-L:
(Serial might appear to kinda work if you don't fill up the output buffer

Since V1.5.6 (2014) Serial output will work, even if interrupts are disabled and the output buffer fills up. If the output buffer is full, the library will poll the serial output interrupt flag and send a character from the buffer whenever the hardware is ready. Everything else stops until the last character in your Serial.print() gets into the output buffer. This will likely cause the millis() timer to lose time, especially a very slow baud rates like 9600.

johnwasser:
Since V1.5.6 (2014) Serial output will work, even if interrupts are disabled and the output buffer fills up.

Cool - I never realized this was the case! thanks.

I found where it is in source code - indeed!

// If the output buffer is full, there's nothing for it other than to 
  // wait for the interrupt handler to empty it a bit
  while (i == _tx_buffer_tail) {
    if (bit_is_clear(SREG, SREG_I)) {
      // Interrupts are disabled, so we'll have to poll the data
      // register empty flag ourselves. If it is set, pretend an
      // interrupt has happened and call the handler to free up
      // space for us.
      if(bit_is_set(*_ucsra, UDRE0))
	_tx_udr_empty_irq();
    } else {
      // nop, the interrupt handler will free up space for us
    }
  }

bruceh58:
I need to crack open the LCD driver chip techsheets to see how the LCD handles it, but for now I'm using code to do that - which causes the LCD line to flicker during updates (because I update all 16 characters of line 2 on each character update).

if you use fdebrabander's Arduino-LiquidCrystal-I2C-library, there are noDisplay() and display() methods that you can use to prevent the flickering:

call noDisplay();
do your magic to scroll one line
call display();

that should make the new line appear in one go