Hi. Recently I have been trying to do a project where I send data from my computer to my Arduino to update led's. It works fine on 9600 baud except for the fact that it's around 30x too slow. So I try turning the baud rate up on the Arduino and in my java application. It is faster, however there is significant corruption. When echoing back the commands I send to the Arduino random character are missing, some are repeated multiple times, some are switched. I know it isn't an issue of the serial buffer on the arduino overflowing as I have a basic handshake type system implemented, I'm pretty sure it isn't the ardunio as I've tried on a nano and an uno. I've configured the baud rates in the device manager to match. Nothing works. I still get corrupted data. One thing I have noticed is the corruption is better on some higher baud rates and worse on lower baud rates. For example a lower baud rate might be unusably corrupt where as a higher one will maybe only mess up a character or 2 out of a hundred.
at this point I'm kind of lost as to what I should do. I've looked everywhere online trying to fix this to no avail. Any help at all would be greatly appreciated!
Sure sounds like a software problem to me.
I have never had any trouble communicating between my Arduinos and my PC at 500,000 baud. IIRC I also used that speed back in the day when I was using JRuby and JSSC.
I assume you are trying to communicate using the regular USB connection between the PC and the Arduino.
Without seeing your programs it is impossible to suggest a solution.
...R
Sorry in advance for the bad code. I'm new to c/c++ so I'm still learning conventions. Anyways this the code I've been running on the Arduino's. All of the serial code is inside of the main loop. Also due to the character limit I had to remove some unnecessary code that did animations and such. None of it was being run when I had the problems.
#include <FastLED.h>
#define LED_PIN 8
#define NUM_LEDS 60
#define BRIGHTNESS 50
#define LED_TYPE WS2811
#define COLOR_ORDER GRB
CRGB leds[NUM_LEDS];
#define UPDATES_PER_SECOND 300
// This example shows several ways to set up and use 'palettes' of colors
// with FastLED.
//
// These compact palettes provide an easy way to re-colorize your
// animation on the fly, quickly, easily, and with low overhead.
//
// USING palettes is MUCH simpler in practice than in theory, so first just
// run this sketch, and watch the pretty lights as you then read through
// the code. Although this sketch has eight (or more) different color schemes,
// the entire sketch compiles down to about 6.5K on AVR.
//
// FastLED provides a few pre-configured color palettes, and makes it
// extremely easy to make up your own color schemes with palettes.
//
// Some notes on the more abstract 'theory and practice' of
// FastLED compact palettes are at the bottom of this file.
CRGBPalette16 currentPalette;
TBlendType currentBlending;
extern CRGBPalette16 myRedWhiteBluePalette;
extern const TProgmemPalette16 myRedWhiteBluePalette_p PROGMEM;
//communication
bool connectionEstablished = false;
//SyncVariables
bool Sync = true;
CRGBPalette16 serialPalette;
float brigntness = 0.1;
int bpm = 128;
void setup() {
delay(3000); // power-up safety delay
Serial.begin(19200);
Serial.setTimeout(7);
FastLED.addLeds<LED_TYPE, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection(TypicalLEDStrip);
FastLED.setBrightness(BRIGHTNESS);
currentPalette = RainbowColors_p;
currentBlending = LINEARBLEND;
}
//this is used to get the iterations of the loop. This is needed because we only want to update the leds every 16 cycles
uint8_t loopCount = 0;
char inputBuffer[16];
unsigned long deltaTime = 0;
void loop()
{
loopCount++;
deltaTime = millis();
//ChangePalettePeriodically();
//if data has been sent parse it
if (Serial.available() > 0) {
Serial.readBytesUntil('>', inputBuffer, 15);
parseinput(inputBuffer);
}
static uint8_t startIndex = 0;
if (loopCount % 64 == 0) {
startIndex = startIndex + 3; /* motion speed */
FillLEDsFromPaletteColors(startIndex);
FastLED.show();
FastLED.delay(positive((1000 / UPDATES_PER_SECOND) - (millis() - deltaTime)));
}
//calculates the amount of time all of the code took to run and takes that into account with the delay
deltaTime = millis() - deltaTime;
//Serial.println(deltaTime);
}
int positive(const int &input){
if (input < 0) {
return 0;
}
}
void parseinput(const char *input) {
if (memcmp(input, "hex", 3) == 0) {
char index[3];
//this meathod directly modifys the input c string
getStringBetweenDelimiters(input, ":", ";", index);
//stores a pointer so that it can iterate over the hex in the string
char *p;
p = strstr(input, ";") + 1;
currentPalette[atoi(index)] = CRGB(
//p is just a pointer and * gets the value of that memory address. So we add to the pointer to iterate over the array
HextoByte(*p, *(p+1)), HextoByte(*(p+2), *(p+3)), HextoByte(*(p+4), *(p+5))
);
}
Serial.println(1);
}
int getStringBetweenDelimiters(const char* string, const char* leftDelimiter, const char* rightDelimiter, char* out)
{
// find the left delimiter and use it as the beginning of the substring
const char* beginning = strstr(string, leftDelimiter);
if (beginning == NULL)
return 1; // left delimiter not found
// find the right delimiter
const char* end = strstr(string, rightDelimiter);
if (end == NULL)
return 2; // right delimiter not found
// offset the beginning by the length of the left delimiter, so beginning points _after_ the left delimiter
beginning += strlen(leftDelimiter);
// get the length of the substring
ptrdiff_t segmentLength = end - beginning;
// allocate memory and copy the substring there
//*out = malloc(segmentLength + 1);
strncpy(out, beginning, segmentLength);
(out)[segmentLength] = 0;
return 0; // success!
}
/*
//will parse out all characters found from a starting index to a ending character to an int
int parseIntTillEndChar(const char *input, int startingindex, const char endchar) {
//this creates a char pointer which is just a number that references memory
const char *p;
//p is now pointing to inputs memory address
p = input;
//we add to the memory address to get to the first index of the string
p += startingindex;
//creates another string to hold the number
char intbuffer[4];
//stores the index for iterating over string
uint8_t index = 0;
//checks for null terminator, the specified end character, or if the index got to high
while (*p || *p != endchar || index > 2) {
intbuffer[index] = *p;
index++;
}
//parses the result to a int and returns it;
return atoi(intbuffer);
}
*/
uint8_t HextoByte(char& x16, char& x1) {
uint8_t decimal = HexLetterToNumber(x1) + 16 * HexLetterToNumber(x16);
return decimal;
}
uint8_t HexLetterToNumber(char& x) {
switch (x)
{
case('a'):
return 10;
break;
case('b'):
return 11;
break;
case('c'):
return 12;
break;
case('d'):
return 13;
break;
case('e'):
return 14;
break;
case('f'):
return 15;
default:
return int(x) - 48;
break;
}
}
void FillLEDsFromPaletteColors(uint8_t colorIndex)
{
uint8_t brightness = 30;
for (int i = 0; i < NUM_LEDS; i++) {
leds[i] = ColorFromPalette(currentPalette, colorIndex, brightness, currentBlending);
colorIndex += 4;
}
}
Here is the serial class on the java side.
package ledServer;
import java.io.IOException;
import java.util.Scanner;
import com.fazecast.jSerialComm.*;
public class SerialCom {
private final String DEFAULT_PORT_NAME = "Arduino";
private String devicePortName;
private SerialPort arduinoPort = null;
private Scanner sc;
public SerialCom() {
devicePortName = DEFAULT_PORT_NAME;
initConnection();
}
public SerialCom(String DeviceName) {
devicePortName = DeviceName;
initConnection();
}
// used to attempt to connect after connection is lost or when initial
// connection fails
public void Reconnect() {
arduinoPort = null;
initConnection();
}
private void initConnection() {
// gets the amount of ports currently plugged in
int portCount = SerialPort.getCommPorts().length;
SerialPort serialPorts[] = new SerialPort[portCount];
serialPorts = SerialPort.getCommPorts();
for (int i = 0; i < portCount; i++) {
String portName = serialPorts[i].getDescriptivePortName();
System.out.println(serialPorts[i].getSystemPortName() + ": " + portName + ": " + i);
if (portName.contains(devicePortName)) {
arduinoPort = serialPorts[i];
arduinoPort.openPort();
System.out.println("connected to: " + portName + "[" + i + "]");
break;
}
}
if (arduinoPort != null) {
arduinoPort.setComPortParameters(19200, 8, 1, 0); // default connection settings for Arduino
arduinoPort.setComPortTimeouts(SerialPort.TIMEOUT_SCANNER, 0, 0); // block until bytes can be written
sc = new Scanner(arduinoPort.getInputStream());
} else {
System.out.println("Could Not find arduino");
}
}
public void sendData(String data) throws InterruptedException {
try {
//System.out.println(data);
arduinoPort.getOutputStream().write(data.getBytes());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//sc.next line freezes all code until the Arduino has confirmed it has received the message
System.out.println(sc.nextLine());
}
public String ReciveData() {
return sc.nextLine();
}
}
I am not familiar with the FastLED library but I think I read in some Threads that it disable interrupts and active interrupts are essential for Serial communication.
I suggest you do some tests at different baud rates without the FastLED library.
...R
Interesting I guess I never really even considered that. I'll look into that, thank you!