-1

I got an Arduino UNO today, and I am just writing a basic blink program. I have 3 LEDS on the arduino. Those LEDS are connected to Pin 1, 2, and 3.

Now I can control those LED by writing octal values 0 to 7 to the /dev/ttyUSB0.

The code I have written so far is:

# pragma GCC optimize ("Ofast")

# define LED1 1
# define LED2 2
# define LED3 3

char buf[4] ;
unsigned char inp, len ;

void setup() {
    pinMode(LED1, OUTPUT) ;
    pinMode(LED2, OUTPUT) ;
    pinMode(LED3, OUTPUT) ;
    
    Serial.begin(9600) ;
}

void loop() {
    len = Serial.readBytes(buf, 3) ;
            
    if (len) {
        buf[3] = '\0' ;
        inp = atoi(buf) ;

        // Illuminate LEDs
        digitalWrite(LED1, 1 & inp ? HIGH : LOW) ;
        digitalWrite(LED2, 2 & inp ? HIGH : LOW) ;
        digitalWrite(LED3, 4 & inp ? HIGH : LOW) ;
    }
}

So when I write:

  • 0 turns off all the LEDS
  • 1 turns on LED on pin 1
  • 2 turns on LED on pin 2
  • 3 turns on LED on pin 1 and 2
  • 4 turns on LED on pin 3
  • 5 turns on LED on pin 1 and 3
  • 6 turns on LED on pin 2 and 3
  • 7 turns on all the LEDS.

The problem is that, when I write 7 for example, it takes up to 1 second to turn on the LEDS. If I write 0, it takes another second to turn off the LEDS.

Is there way to control the LEDS in close to real-time?

2

When sending multiple bytes which together form a single message it is best to use a delimiter character and read the data until there. That way you don't run into timeouts and you can be sure, that the received data represents a full message.

In the cases where the LEDs need 1s to react you are most likely sending less than 3 bytes, which causes the Serial.readBytes() function to time out after the default 1s. I guess you are currently always sending only 1 byte (though you are trying to read 3 byte in your code).

To use a delimiter character there are multiple ways. The easiest fix would be using Serial.readStringUntil('\n'). The newline character (which I used as a parameter here) is a common delimiter character. You would then need to aways send the newline character at the end of a full message.

Just setting the timeout very low is not a very good solution. With a low baudrate as 9600 that can easily mean, that the message is chopped up into multiple parts, because the transmission takes longer than the timeout.


Besides that: I don't really understand, why you need to receive 3 bytes for turning on or off 3 LEDs. One byte (even, when you are just using single digits) has a big enough data space for more than these 3 LEDs. Also you are not really using octal numbers. atoi() is expecting a string representation of a decimal number. There is nothing octal in your code. And then you are using the first 3 bits of the resulting number for controlling the LEDs.

All in all this seems quite complicated for a very basic task. Maybe there is some reason for that, which you didn't write about.

1

You're calling Serial.readBytes() when there may or may not be 3 bytes available. If there aren't 3, the call waits for them to arrive or for a timeout. That's the delay you are seeing.

If you really want 3 bytes at a time, check whether there are 3 before you try to read them:

if( Serial.available >= 3 )
   len = Serial.readBytes(buf, 3);

When the if fails - because there aren't three bytes available - you won't waste any time waiting for them.

0

On the Arduino UNO pins 0 and 1 are used for serial communications. That might not make a difference here, but it's probably a good idea to avoid them unless really needed.

1
  • This should be a comment
    – Sim Son
    Apr 17 at 13:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.