Hello, I am new to Arduino and am trying to send data over the serial port using an external Java program. Right now I am trying to send 7 bytes of data to turn a string of 50 LEDs on and off randomly. This works great, but if I try to decrease the delay between writing the bytes to less than 1 second, the Arduino completely ignores all serial input and seemingly, won't read anything. I can see the RX LED is flashing on the board, but my string of LEDs stops updating. I tested this with other things as well such as sending and receiving text, but got the same result. Can data only be sent over the serial port once per second? I have posted both my Java code and Arduino code below.
Java Code:
SerialPort[] allComPorts = SerialPort.getCommPorts();
SerialPort port = allComPorts[0];
port.setBaudRate(115200);
port.openPort();
Thread outputSender = new Thread(new Runnable() {
@Override
public void run() {
byte[] line = new byte[7];
Random r = new Random();
while(true) {
r.nextBytes(line);
port.writeBytes(line, 7);
try {
Thread.sleep(1000); //If I decrease this to less than 1000, the Arduino will ignore all serial input
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
outputSender.start();
The FastLED show() function disables interrupts while it executes. Serial data that comes in while interrupts are disabled will be ignored or corrupted.
Hi, thanks for the response! Even if the data happens to come over during the exact instant the show() function is called. Why is serial communication being blocked indefinitely if I try to write to it more than once per second? In my code, show() should only be called in the loop if the there are at least 7 bytes available to read, but the code just completely stops executing if I write more than once per second.
There appears to be no synchronization here, you are assuming a perfect frame.
Typically with serial, the sketch takes the serial buffer one character at a time after some special character is received: /n, /r being common.
Then assemble character by character into a 7 byte buffer or array.
Something like this from an old GPS code:
c = UART_UartGetChar(); // Get received character or null
if (c)
{
if(c == '$') // $ start of NMEA sentences
{
for(k=0; k<5; k++) // need 5 characters for sentence type
{
LED_Write( ~LED_Read() ); // flicker LED for activity
do {
c = UART_UartGetChar();
}
while (! (c));
nmea[k] = c; // G + P + R + M + C
// sprintf(buffer + k, "%c", c) ; // only for debug
}
Thanks for the response! Yes, I am assuming that there will only be 7 bytes available in the buffer at any given time. Ideally how the code would work is that 7 bytes would get sent over the serial port every 40 - 50 milliseconds. I know that the rest of the code in the loop can execute much faster than that. So the serial buffer should be emptyed before the next batch of data is sent. The arduino board can definitely write to the serial monitor more than once per second. My problem is if I try to send any data over the serial port faster than 1 second intervals, all serial communication appears to completely stop on the board.
You may try to synchronize your Java Application and MEGA's Receive Sketch
as per post #4 (@mrburnette) by doing the following things assuming that the execution time of FastLED.show() method is less than 100 ms during which interrupt logic of MEGA remain OFF as per post #2 (@groundFungus).
MEGA's receive sketch will begin accumulating the incoming ASCII coded bytes when '$' is detected and the reception will end after detecting '\n' or 7-bytes data whatever occurs at the earlier.
1. I have no experience with Java; so, I am unable to add the above features in your Java Application.
2. I am adjusting your MEGA's receive sketch to accommodate the above features.
#include <FastLED.h>
#define NUM_LEDS 50
#define DATA_PIN 6
CRGB leds[NUM_LEDS];
char frame[8];
void setup()
{
delay(3000);
Serial.begin(115200);
FastLED.addLeds<WS2812B, DATA_PIN, RGB>(leds, NUM_LEDS);
FastLED.setBrightness(50);
}
void loop()
{
byte n = Serial.available();
if (n != 0)
{
char y = Serial.read();
if (y == '$')
{
byte m = Serial.readBytesUntil('\n', frame, 7); //'\n' is not saved in the frame
frame[m] = '\0'; //insert null-byte
for (int part = 0, count = 0; part < 7 && count < 50; part++)
{
for (int cbit = 0; cbit < 8 && count < 50; cbit++)
{
int value = frame[part] & (1 << cbit);
if (value == 1)
{
leds[count] = CRGB::Blue;
}
else
{
leds[count] = CRGB::Black;
}
count++;
}
memset(frame, 0, 7); //array is cleared.
}
FastLED.show();
}
}
}
Thank you for all of the replies. I actually found the solution! I think what was happening is that when I opened the serial port in my Java application, it caused the board to reboot. I needed to add delay in my Java program to account for the restart time. Once I did that I was able to write as often as I wanted.
On one of my Arduinos I have fitted a switch so I can turn off the auto reset circuit, so that this is not a problem. But I have to turn it back on in order to download code to it.
The other way round this is not to close your serial port until you are finished with it.so keep it open until you detect the Arduino is no longer there.