Struggling with C

Thread Starter

Torbek

Joined Apr 19, 2019
60
Hey folks, struggling a bit to get my head around C.

So I have a program to use the millis command to make an LED flash say 20mS on every second. What I would love to do, is produce a beacon so that the light flashes two or three times for X milliseconds every second, or whenever.
I just can't see how to change the delay from say, one second, to 50ms betweenflashes then back to one second again.

Can someone help please?

*Ignore the 2nd LED for now, just want the ability to alternately change "off duration" for now without significantly changing the code.

Code:
const int LEDpin = 1;
const int LEDpin1 = 2;
const long onDuration = 60;// 
const long onDuration1 = 1500;// 
const long offDuration = 1000;//
const long offDuration1 = 25;//
int LEDState =HIGH;// initial state of LED
int LEDState1 =HIGH;// initial state of LED
long rememberTime=0;// this is used by the code
long rememberTime1=0;// this is used by the code
void setup() {
  pinMode(LEDpin,OUTPUT);// define LEDpin as output
  digitalWrite(LEDpin,LEDState);// set initial state
  pinMode(LEDpin1,OUTPUT);// define LEDpin as output
  digitalWrite(LEDpin1,LEDState1);// set initial state
}
void loop() {
  // Robojax LED blink with millis()
 if( LEDState ==HIGH )
 {
    if( (millis()- rememberTime) >= onDuration){   
    LEDState = LOW;// change the state of LED
    rememberTime=millis();// remember Current millis() time
    }
 }
 else
 {   
    if( (millis()- rememberTime) >= offDuration){     
    LEDState =HIGH;// change the state of LED
    rememberTime=millis();// remember Current millis() time
    }
 }

 digitalWrite(LEDpin,LEDState);// turn the LED ON or OFF
}
 

ApacheKid

Joined Jan 12, 2015
1,269
Hey folks, struggling a bit to get my head around C.

So I have a program to use the millis command to make an LED flash say 20mS on every second. What I would love to do, is produce a beacon so that the light flashes two or three times for X milliseconds every second, or whenever.
I just can't see how to change the delay from say, one second, to 50ms betweenflashes then back to one second again.

Can someone help please?

*Ignore the 2nd LED for now, just want the ability to alternately change "off duration" for now without significantly changing the code.

Code:
const int LEDpin = 1;
const int LEDpin1 = 2;
const long onDuration = 60;//
const long onDuration1 = 1500;//
const long offDuration = 1000;//
const long offDuration1 = 25;//
int LEDState =HIGH;// initial state of LED
int LEDState1 =HIGH;// initial state of LED
long rememberTime=0;// this is used by the code
long rememberTime1=0;// this is used by the code
void setup() {
  pinMode(LEDpin,OUTPUT);// define LEDpin as output
  digitalWrite(LEDpin,LEDState);// set initial state
  pinMode(LEDpin1,OUTPUT);// define LEDpin as output
  digitalWrite(LEDpin1,LEDState1);// set initial state
}
void loop() {
  // Robojax LED blink with millis()
if( LEDState ==HIGH )
{
    if( (millis()- rememberTime) >= onDuration){
    LEDState = LOW;// change the state of LED
    rememberTime=millis();// remember Current millis() time
    }
}
else
{
    if( (millis()- rememberTime) >= offDuration){
    LEDState =HIGH;// change the state of LED
    rememberTime=millis();// remember Current millis() time
    }
}

digitalWrite(LEDpin,LEDState);// turn the LED ON or OFF
}
This sounds like an ideal role for a hardware timer, I'm sure others can elaborate on that. But in principle you'd start a timer for an interval X. Then when it expires it calls into your code where you can reschedule the timer again for an interval Y, followed by doing the code for whatever you need.

Basically the timer expires, a handler runs which reschedules the timer while also doing the work it needs to do. If you incorporate a state variable too, things get neater because your callback becomes a `switch` statement with a `case` for each scenario.

In pseudo code:
Code:
void handle_timer_expiry()
{

   switch (state)
   {
   case A:
      {
      // Insert call to start timer for X mS.
      // Insert code to do what you want when in state A.
      state = B;
      return;
      }
   case B:
      {
      // Insert call to start timer for Y mS.
      // Insert code to do what you want when in state B.
      state = A;
      return;
      }
   }
}
That simple state machine will "oscillate" with intervals of X and Y over and over. You can add more states too to get your desired behavior.

The presence of the `if` statements and other steps in your code is a dead giveaway that a state machine is needed. If you try to do what you want with that kind of logic you will eventually lose your mind! The beauty of the state machine and timer approach is that you can code for each state very clearly, the code in each state does not care about the past, does not ask questions about "what happened before" and so on.

I'm a novice so to speak with the MCU's themselves so will let others cover that.
 
Last edited:

BobTPH

Joined Jun 5, 2013
7,557
That is because the way the program was originally written does not lend itself well to that kind of modification.

Did you write this, or is it a sample you got somewhere?

You could change it by adding more states, like first_blink_on, first_blink_off, second…. But that is not the way I would do it.

ApacheKid suggests a solution that would be good if the micro needed to do other things, but I suspect is beyond your current understanding.

Here is the simple way I would do it tobkeep it simple for you.

Write two functions led_on and led_off that take one param which is the time in milliseconds.

Then the loop function simply calls a sequence of on and offs to do the blinking.
 

WBahn

Joined Mar 31, 2012
29,172
How about something like this:

Code:
const int duration[] = { 100, 50, 200, 650 };
const int led_state[] = { HI, LOW, HI, LO };

int state = 0;
 
void loop()
{
   if (millis() > timeout)
   {
      LEDstate = led_state[state]
      timeout += duration[state];
      state = (state+1) & 0x04;
   }
}
Now you can tailor any sequence you want. Using a number of states that is an integer power of two makes the last line efficient, but you can make it arbitrary by doing the following:

Code:
const int duration[] = { 100, 50, 200, 650 };
const int led_state[] = { HI, LOW, HI, LO };

int state = 0;
 
void loop()
{
   if (millis() > timeout)
   {
      LEDstate = led_state[state]
      timeout += duration[state];
      state = (state+1) % ( sizeof(duration) / sizeof(*duration) );
   }
}
If the divisor in the last line turns out to be an integer power of two, some compilers will convert it to the first form.
 

BobaMosfet

Joined Jul 1, 2009
2,082
This will help:

Title: Standard C [Quick Ref]
Author(s): P.J.Plauger, Jim Brodie
ISBN: 1-55615-158-6

and these:

Title: C: A Reference Manual, 4th Ed.
Author: Samuel P. Harbison & Guy L. Steel, Jr.
ISBN: 0-13-326224-3

Title: Algorithms in C, 3rd Ed. [Parts 1-4, Fundamentals, Data Structures, Sorting, Searching]
Author: Robert Sedgewick
ISBN: 0-201-31452-5
 

MrChips

Joined Oct 2, 2009
29,246
When creating a program in any programming language the last thing you want to be doing is writing code.
You need to write out a plan. We do this either using plain language or with use of a flow chart.

Here is a high perspective plan of what is required:

1) Turn an LED on for x ms.
2) Do step (1) n times.
3) Repeat step (2) every y ms.

Now we can focus on what is required for each of the three steps.
 
Top