Assymetrical Blink controlled via Serial Comm

Hello all,

I have finally swallowed my newbie pride and realized that I need help beyond smashing code together and praying to the arduino gods that the results will work.

What I am trying to do is use serial communication to tell the arduino the rate at which I want an LED to blink on and off indefinitely. The only catch is that I want to be able to control the timing for both LED states independently (e.g. LED pin set to HIGH for 500 millis then LOW for 200 millis).

An example sketch that achieves a close result to what I am looking for is the ArduinoPC2 sketch by Robin2 found here.

The only differences between the ArduinoPC2 sketch and what I am trying to do is that it was written to control 2 LEDs and a servo motor and the FlashLED function appears to be simplified beyond what I am able to break down.

The second example code that achieves almost exactly what I am trying to without serial communication is found here written by UKHeliBob.

Below is my attempt to merge the codes to do my bidding (the squeamish may wish to avert their eyes for this part :fearful: ):

const byte ledPin =  2;
unsigned long previousMillis = 0;
const byte states[] = {HIGH, LOW};
unsigned long intervals[] = {200, 500};
unsigned long previntervals[] = {0, 0};
byte state;

const byte buffSize = 40;
char inputBuffer[buffSize];
const char startMarker = '<';
const char endMarker = '>';
byte bytesRecvd = 0;
boolean readInProgress = false;
boolean newDataFromPC = false;

char messageFromPC[buffSize] = {0};
int newintervals = 0;

unsigned long curMillis;

unsigned long prevReplyToPCmillis = 0;
unsigned long replyToPCinterval = 1000;

//=============

void setup()
{
  Serial.begin(9600);
  pinMode(ledPin, OUTPUT);
  Serial.println("<Arduino is ready>");
}

//=============

void loop() {
  curMillis = millis();
  getDataFromPC();
  updateFlashInterval();
  replyToPC();
  flashLED();
}


//=============

void getDataFromPC() {                     // receive data from PC and save it into inputBuffer
    
  if(Serial.available() > 0) {

    char x = Serial.read();                // the order of these IF clauses is significant
      
    if (x == endMarker) {
      readInProgress = false;
      newDataFromPC = true;
      inputBuffer[bytesRecvd] = 0;
      parseData();
    }
    
    if(readInProgress) {
      inputBuffer[bytesRecvd] = x;
      bytesRecvd ++;
      if (bytesRecvd == buffSize) {
        bytesRecvd = buffSize - 1;
      }
    }

    if (x == startMarker) { 
      bytesRecvd = 0; 
      readInProgress = true;
    }
  }
}

//=============
 
void parseData() {                         // split the data into its parts
    
  char * strtokIndx;                       // this is used by strtok() as an index
  
  strtokIndx = strtok(inputBuffer,",");    // get the first part - the string
  strcpy(messageFromPC, strtokIndx);       // copy it to messageFromPC
  
  strtokIndx = strtok(NULL, ",");          // this continues where the previous call left off
  newintervals = atoi(strtokIndx);                   // convert this part to an integer

}

//=============

void replyToPC() {

  if (newDataFromPC) {
    newDataFromPC = false;
    Serial.print("<Msg ");
    Serial.print(messageFromPC);
    Serial.print(" time ");
    Serial.print(newintervals);
    Serial.println(">");
  }
}
  
//=============

void updateFlashInterval() {               // this illustrates using different inputs to call different functions
 
  if (strcmp(messageFromPC, "l") == 0) {
     updateintervals();
  }
}

//=============

void updateintervals() {

  if (newintervals > 100) {
    intervals[0] = newintervals;
  }
}


//=============
void flashLED()
{
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= intervals[state % 2])
  {
    previousMillis = currentMillis;
    digitalWrite(ledPin, states[state++ % 2]);
  }
}

Obviously, as the above code does not achieve the result I’m looking for, I must not be using the correct syntax (or language in some cases ;p). Ideally, I’d love to get the arduino to respond to serial communication formatted like <200,500> and be able to respond by setting the times for the HIGH and LOW LED states as such (i.e. LOW = 200 millis, HIGH = 500 millis; in whatever order is simplest to code). Hopefully that makes sense?

Are any of you fine, learned folk willing to help a newbie understand how to make the code above function like I want?

For reference, my actual circuit looks like:

Yvarg:
Obviously, as the above code does not achieve the result I'm looking for

And it would be much easier to help you debug it if you would fill us in on what exactly it does that is different from what you are looking for.

It would also help if you gave us an example of what exactly you’re sending over Serial as well as what it did when you sent it.

It looks like it’s expecting messages of the form <1,100> which would set the off-time to 100 milliseconds.

Your Fing diagram shows the LED connected to pin 0, which is one of the serial communication pins. It won’t work with that LED there. But your code shows pin 2. Which pin did you connect it to?
If you like using F
ing, please get used to using the “schematic view”. It’s infinitely superior to the breadboard view.

I like the way you censor that word. :slight_smile:

I would have left the word “using” out of the next to last sentence though to maintain the ambiguous context.

OP: If you don’t understand what we’re talking about, there is a general distaste for the particular program you used to make that diagram due to the particularly poor job it does and the fact that it is often hard to figure out what it going on in those figures. It is preferred around here to just draw it out on paper and post a picture. But I am with @MorganS, if you’re going to use that program, at least take the time to make the schematic match what you actually have.

Delta_G:
And it would be much easier to help you debug it if you would fill us in on what exactly it does that is different from what you are looking for.

Sorry about that! Currently, the code sets the LED to flash with the unsigned long intervals declared in the beginning of the code (LOW for 200, HIGH for 500). However, what I’m having difficulty with is getting it to update those intervals by sending new values through the Serial Monitor. Is that a little more clear?

MorganS:
It would also help if you gave us an example of what exactly you’re sending over Serial as well as what it did when you sent it.

It looks like it’s expecting messages of the form <1,100> which would set the off-time to 100 milliseconds.

Your Fing diagram shows the LED connected to pin 0, which is one of the serial communication pins. It won’t work with that LED there. But your code shows pin 2. Which pin did you connect it to?
If you like using F
ing, please get used to using the “schematic view”. It’s infinitely superior to the breadboard view.

Fair enough, I definitely should have included examples from the Serial Monitor as well. I have tried a number of messages such as <1,1000> or <1,500,1000>. Really just anything that should give me a different value than the starting millis for each state. The arduino responds with “<Msg 1 time 1000>” or “<Msg 1 time 500>” but the LED blink time does not update.

Regarding the arduino image, I DO have the resistor connected to digital pin 2, NOT 0. Honestly, I just grabbed the first image from a google search that had a resistor wired in the same manner and assumed my stating that the LED’s resistor is actually in pin 2 would have sufficed. I’ve gone back and edited my first post to include my own screen shot of the schematic showing exactly how I have it set up to avoid any further confusion. :slight_smile:

For the record, I wasn’t aware of the distaste for the unmentionable program. When working with schematics I USUALLY am using the trial version of Eagle. But I will hand it to the lesser program for the ease it provides of slapping together quick layout views of simple projects.

You're using strtok(); you need to call it a few times to parse a text that contains multiple commas. Find an example on the web the is able to parse text with multiple commas and work it out from there.

E.g. C library function - strtok()

I'm looking at your function updateFlashInterval()

I don't understand when the messageFromPC string will be just lower case L?

Also a general debugging tip - put a Serial.print() statement or two in every function, something like

Serial.println("Function updateFlashInterval start");
...
Serial.println("Function updateFlashInterval end");

you can see where in the sketch the problem occurs.

To get an asymmetric blink pattern you need to change the interval every time you turn the LED on or off.
Get that bit working first and then worry about all the PC control serial crap to specify these two intervals.

This might help Tutorial State_Machine

One thing I noticed is that once you read a value the program continually updates the interval because messageFromPC us still “l”. I added a print statement here:

void updateFlashInterval() {               // this illustrates using different inputs to call different functions

  if (strcmp(messageFromPC, "l") == 0) {
    Serial.println("got l");
    updateintervals();
  }
}

and entered in the serial monitor:

<l, 900>

The serial monitor displayed:

<Arduino is ready>
got l
<Msg l time 900>
got l
got l
got l
got l
got l
got l
got l
got l
got l
got l
got l
got l
got l
got l

and on forever.

Clearing the message buffer after replying made it act as expected. (You could probably use your newDataFromPC flag instead).

void replyToPC() {

  if (newDataFromPC) {
    newDataFromPC = false;
    Serial.print("<Msg ");
    Serial.print(messageFromPC);
    Serial.print(" time ");
    Serial.print(newintervals);
    Serial.println(">");

    *messageFromPC = '\0';
    
  }
}

This simple sketch using the Serial Monitor might help you get started:

// To set ON/OFF times, type in top of serial monitor:
// Example: 500 mS ON, 2000 mS OFF (lower case letters, no spaces)
// o500[ENTER], f2000[ENTER] or o500f2000[ENTER]


unsigned long iStart; // interval start
unsigned long onTime = 100;
unsigned long offTime = 200;
const byte ledPin = 13; // led pin
void setup()
{
  Serial.begin(115200); //set serial monitor to match, no line ending
  pinMode(ledPin,OUTPUT);
  prntIt();
}
void loop()
{
  unsigned long iEnd = onTime + offTime; // interval end
  digitalWrite(ledPin,millis() - iStart < onTime);
  if(millis() - iStart > iEnd)
    iStart += iEnd;
  while (Serial.available() > 0) {
    char inChar = Serial.read();
    if(inChar == 'o')
      onTime = Serial.parseInt();
    else if(inChar == 'f')
      offTime = Serial.parseInt();
    else
    {  
       Serial.println("invalid input");
       while(Serial.available() > 0)
         Serial.read();
    }
    iStart = millis();
    prntIt();
  }  
}
void prntIt()
{
  Serial.print("On Time = ");
  Serial.print(onTime);
  Serial.print("  Off Time = ");
  Serial.print(offTime);
  Serial.println("\n");
}

Thank you to all who took the time to look over my problem!

edgemoron:
This simple sketch using the Serial Monitor might help you get started:

// To set ON/OFF times, type in top of serial monitor:

// Example: 500 mS ON, 2000 mS OFF (lower case letters, no spaces)
// o500[ENTER], f2000[ENTER] or o500f2000[ENTER]

unsigned long iStart; // interval start
unsigned long onTime = 100;
unsigned long offTime = 200;
const byte ledPin = 13; // led pin
void setup()
{
  Serial.begin(115200); //set serial monitor to match, no line ending
  pinMode(ledPin,OUTPUT);
  prntIt();
}
void loop()
{
  unsigned long iEnd = onTime + offTime; // interval end
  digitalWrite(ledPin,millis() - iStart < onTime);
  if(millis() - iStart > iEnd)
    iStart += iEnd;
  while (Serial.available() > 0) {
    char inChar = Serial.read();
    if(inChar == ‘o’)
      onTime = Serial.parseInt();
    else if(inChar == ‘f’)
      offTime = Serial.parseInt();
    else
    { 
      Serial.println(“invalid input”);
      while(Serial.available() > 0)
        Serial.read();
    }
    iStart = millis();
    prntIt();
  } 
}
void prntIt()
{
  Serial.print(“On Time = “);
  Serial.print(onTime);
  Serial.print(”  Off Time = “);
  Serial.print(offTime);
  Serial.println(”\n”);
}

Yes, this code accomplishes almost exactly what I have been trying to do! Thanks, this will make for an excellent starting point for my project. :slight_smile:

GypsumFantastic:
I’m looking at your function updateFlashInterval()

I don’t understand when the messageFromPC string will be just lower case L?

Also a general debugging tip - put a Serial.print() statement or two in every function, something like

Serial.println(“Function updateFlashInterval start”);

Serial.println(“Function updateFlashInterval end”);

you can see where in the sketch the problem occurs.

For what it’s worth, the lower case L was just remnants of a previous experiment with the code, I wasn’t even worrying about how the message back from the arduino to the PC was displaying until the arduino functioned correctly. However, that Serial.println debugging tip is a great idea! I will definitely be giving that a shot in the future.