Controlling LED using serial port

2019-09-06 20:28发布

问题:

As part of a simple Automation project, I was trying to control some LEDs through serial port. I cannot make the following code working

int pin =0;
int state = 0;

void setup() {
    Serial.begin(9600);     // opens serial port, sets data rate to 9600 bps
}

void loop() {
    // send data only when you receive data:
    if (Serial.available() > 0) {
        // read the incoming byte:
        if(Serial.read() == 'S' && Serial.read() == 'S') {
            // Command to set the pin
            pin  = Serial.read() - 65;
            state = Serial.read() - '0';
            Serial.print("Set State Command received");
            // Set the Pin
            pinMode(pin, OUTPUT);          
            digitalWrite(pin, state == 0? LOW:HIGH);
        }
    }
}

I am sending "SSN1" from my python program to the Arduino serial port for testing, and nothing happens (I have an LED connected on pin 13)

SS -  Set State Command
N  - (pin no) + 'A'  - Pin number 13
1  - State ( 0 = LOW, 1= HIGH)

回答1:

You want to wait until 4 serial bytes accumulate on the serial buffer.

void loop() {
    // polls the serial buffer
    while (Serial.available() < 4);
    if (Serial.read() == 'S' && Serial.read() == 'S') {
       char type = Serial.read();
       char pin = Serial.read() - 65;
       // do something with the results
    }
}

Note that you may want to implement some kind of padding (adding a fixed length of spaces, for example) between inputs, because the serial buffer may drop a byte or overflow, which can lead to unexpected results. Also, some people will complain about the while (Serial.available() < 4) command because computer scientists have been trained to think "polling = bad!", but in the case of an Arduino it makes no difference since it is only running a single task.

By the way, you can also use interrupts with Serial data, but that's out of the scope of this response.



回答2:

actually I have also battled to get something similar right. due to the problems experienced with serial communication (sometime the messages are slow and sent in pieces, the ACII codes are difficult to remember) I went for a different solution. Basically I added a header ">" and a tail "<"to the message sent to the serial and I featured the Arduino code to consider the message between >< as command. I have then used ATOI to convert string to integer. In the following code you will see that I have used the following numbers to get Arduino changing the status of pin2 and pin13. Here are the commands associated to this code:

1000< set pin 13 HIGH, 2000< set pin 13 LOW, 3000< set pin 2 HIGH, 4000< set pin 2 LOW

So, simply send out to the serial those numbers between >< and it should work. I have used the above also to set PWM speed simply manipulating the strings associated to the received messages. I have not included in this sample the PWM commands but only those related to pin 13 and pin 2. I thought that would be much simpler and safe to use numbers and string identifier to open and close the message. Load the sketch, open the serial monitor and send >1000<, you should see the internal led on pin 13 lighting up, and so on. let me know if you need any additional help.

char inData[10];
int index;
boolean started = false;
boolean ended = false;
String message = "I am ready!, Send your command....";

void setup(){
    Serial.begin(9600);
    Serial.println(message);
    pinMode (13, OUTPUT);
    pinMode (2, OUTPUT);
}

void loop()
{
    while(Serial.available() > 0)
    {
        char aChar = Serial.read();
        if(aChar == '>')
        {
            started = true;
            index = 0;
            inData[index] = '\0';
        }
        else if(aChar == '<')
        {
            ended = true;
        }
        else if(started)
        {
            inData[index] = aChar;
            index++;
            inData[index] = '\0';
        }
    }

    if(started && ended)
    {
        int inInt = atoi(inData);

        // set  pin 13 HIGH
        if (inInt < 1000)
        { 
            digitalWrite(13, HIGH);
        }
        //set pin 13 LOW
        else if (inInt < 2000)
        { 
            digitalWrite(13, LOW); 
        }
        //set  pin 2 HIGH
        else if (inInt < 3000)
        { 
            digitalWrite(2, HIGH);
        }
        //set il pin 2 LOW
        else if (inInt < 4000)
        { 
            digitalWrite(2, LOW);
        }

        started = false;
        ended = false;
        index = 0;
        inData[index] = '\0';
    }
}


回答3:

Look at this example code from Arduino's Physical Pixel Tutorial

const int ledPin = 13; // the pin that the LED is attached to
int incomingByte;      // a variable to read incoming serial data into

void setup() {
  // initialize serial communication:
  Serial.begin(9600);
  // initialize the LED pin as an output:
  pinMode(ledPin, OUTPUT);
}

void loop() {
  // see if there's incoming serial data:
  if (Serial.available() > 0) {
    // read the oldest byte in the serial buffer:
    incomingByte = Serial.read();
    // if it's a capital H (ASCII 72), turn on the LED:
    if (incomingByte == 'H') {
      digitalWrite(ledPin, HIGH);
    } 
    // if it's an L (ASCII 76) turn off the LED:
    if (incomingByte == 'L') {
      digitalWrite(ledPin, LOW);
    }
  }

Verify that you see SSN1 coming through on the serial monitor.



回答4:

I improved my code as it look like this

int pin =0;
int state = 0;

void setup() {
        Serial.begin(9600);     // opens serial port, sets data rate to 9600 bps
}

void loop() {

        // send data only when you receive data:
        if (Serial.available() > 3) { // I am using chunk of 4 characters/bytes as a command 
                // read the incoming byte:
                if(Serial.read() == 'S' && Serial.read() == 'S') {
                  // Command to set the pin
                  pin  = Serial.read() - 65;
                  state = Serial.read() - '0';
                  Serial.print("Set State Command received");
                  // Set the Pin
                  pinMode(pin, OUTPUT);          
                  digitalWrite(pin, state == 0? LOW:HIGH);
                }
                delay(50); 
        }
}

It works perfectly for me. Due to the high frequency of looping, Arduino was not able pickup the bytes for consecutive read. So we are waiting for 4 bytes to accumulate in the buffer to read those (Arduino's serial buffer is 64 bytes).



标签: arduino