Arduino Forum

Using Arduino => Project Guidance => Topic started by: Robin2 on Mar 04, 2014, 01:28 pm

Title: Demonstration code for several things at the same time
Post by: Robin2 on Mar 04, 2014, 01:28 pm
NOTE for newcomers. The demo is entirely contained in this Post and Reply #1. There is no need to read further unless you are interested. ...added 25Sep2014

There have been a few occasions recently where newcomers seemed to have difficulty applying the "blink without delay" and "state" concepts to a sketch that is intended to manage a number of concurrent actions.

Its very time consuming to respond with suitable code examples - particularly as every case is a little different.

I have prepared the attached example sketch in the hope that it will be a suitable model. I have tested it on an Uno and a Mega. I have called it "SeveralThingsAtTheSameTime.ino". (It seems to be too long to show the code directly in this post)

My sketch uses the concept in "blink without delay" to cause three LEDs to blink at different intervals, a fourth LED is controlled by a button and a servo sweeps back and forth at two different speeds. The idea is to demonstrate how different processes can be accommodated in the same general framework.

It also uses the "state machine" concept to manage the various activities and enable the different functions to determine what to do.

I have deliberately designed the sketch as a series of short functions. Short pieces of code are much easier to understand and debug and it will be an easy matter for a user to delete functions that they don't need or to duplicate and modify functions if they need more of the same (for example to flash 5 LEDS at different intervals).

There is a case for saying there is too much in the sketch but I concluded that the larger number of activities is a better demonstration of the capabilities of this approach.

Comments are welcome.

...R

Edit ... the attached sketch has been revised to take account of comments below about improving the timekeeping ...R
Title: Re: Demonstration code for several things at the same time
Post by: Robin2 on Mar 04, 2014, 10:20 pm
Code: [Select]

// SeveralThingsAtTheSameTimeRev1.ino

// An expansion of the BlinkWithoutDelay concept to illustrate how a script
//  can appear to do several things at the same time

// this sketch does the following
//    it blinks the onboard LED (as in the blinkWithoutDelay sketch)
//    it blinks two external LEDs (LedA and LedB) that are connected to pins 12 and 11.
//    it turns another Led (buttonLed connected to pin 10) on or off whenever a button
//       connected to pin 7 is pressed
//    it sweeps a servo (connected to pin 5) back and forth at different speeds

//  One leg of each LED should be connected to the relevant pin and the other leg should be connected to a
//   resistor of 470 ohms or more and the other end of the resistor to the Arduino GND.
//   If the LED doesn't light its probably connected the wrong way round.

//  On my Uno and Mega the "button" is just a piece of wire inserted into pin 7.
//   Touching the end of the wire with a moist finger is sufficient to cause the switching action
//   Of course a proper press-on-release-off button switch could also be used!

//  The Arduino is not capable of supplying enough 5v power to operate a servo
//    The servo should have it's own power supply and the power supply Ground should
//      be connected to the Arduino Ground.

// The sketch is written to illustrate a few different programming features.
//    The use of many functions with short pieces of code.
//       Short pieces of code are much easier to follow and debug
//    The use of variables to record the state of something (e.g. onBoardLedState) as a means to
//       enable the different functions to determine what to do.
//    The use of millis() to manage the timing of activities
//    The definition of all numbers used by the program at the top of the sketch where
//       they can easily be found if they need to be changed

//=======

// -----LIBRARIES

#include <Servo.h>

// ----CONSTANTS (won't change)

const int onBoardLedPin =  13;      // the pin numbers for the LEDs
const int led_A_Pin = 12;
const int led_B_Pin = 11;
const int buttonLed_Pin = 10;

const int buttonPin = 7; // the pin number for the button

const int servoPin = 5; // the pin number for the servo signal

const int onBoardLedInterval = 500; // number of millisecs between blinks
const int led_A_Interval = 2500;
const int led_B_Interval = 4500;

const int blinkDuration = 500; // number of millisecs that Led's are on - all three leds use this

const int buttonInterval = 300; // number of millisecs between button readings

const int servoMinDegrees = 20; // the limits to servo movement
const int servoMaxDegrees = 150;


//------- VARIABLES (will change)

byte onBoardLedState = LOW;             // used to record whether the LEDs are on or off
byte led_A_State = LOW;           //   LOW = off
byte led_B_State = LOW;
byte buttonLed_State = LOW;

Servo myservo;  // create servo object to control a servo

int servoPosition = 90;     // the current angle of the servo - starting at 90.
int servoSlowInterval = 80; // millisecs between servo moves
int servoFastInterval = 10;
int servoInterval = servoSlowInterval; // initial millisecs between servo moves
int servoDegrees = 2;       // amount servo moves at each step
                           //    will be changed to negative value for movement in the other direction

unsigned long currentMillis = 0;    // stores the value of millis() in each iteration of loop()
unsigned long previousOnBoardLedMillis = 0;   // will store last time the LED was updated
unsigned long previousLed_A_Millis = 0;
unsigned long previousLed_B_Millis = 0;

unsigned long previousButtonMillis = 0; // time when button press last checked

unsigned long previousServoMillis = 0; // the time when the servo was last moved

//========

void setup() {

 Serial.begin(9600);
 Serial.println("Starting SeveralThingsAtTheSameTimeRev1.ino");  // so we know what sketch is running
 
     // set the Led pins as output:
 pinMode(onBoardLedPin, OUTPUT);
 pinMode(led_A_Pin, OUTPUT);
 pinMode(led_B_Pin, OUTPUT);
 pinMode(buttonLed_Pin, OUTPUT);
 
     // set the button pin as input with a pullup resistor to ensure it defaults to HIGH
 pinMode(buttonPin, INPUT_PULLUP);
 
 myservo.write(servoPosition); // sets the initial position
 myservo.attach(servoPin);

}

//=======

void loop() {

     // Notice that none of the action happens in loop() apart from reading millis()
     //   it just calls the functions that have the action code

 currentMillis = millis();   // capture the latest value of millis()
                             //   this is equivalent to noting the time from a clock
                             //   use the same time for all LED flashes to keep them synchronized
 
 readButton();               // call the functions that do the work
 updateOnBoardLedState();
 updateLed_A_State();
 updateLed_B_State();
 switchLeds();
 servoSweep();

}

//========

void updateOnBoardLedState() {

 if (onBoardLedState == LOW) {
         // if the Led is off, we must wait for the interval to expire before turning it on
   if (currentMillis - previousOnBoardLedMillis >= onBoardLedInterval) {
         // time is up, so change the state to HIGH
      onBoardLedState = HIGH;
         // and save the time when we made the change
      previousOnBoardLedMillis += onBoardLedInterval;
         // NOTE: The previous line could alternatively be
         //              previousOnBoardLedMillis = currentMillis
         //        which is the style used in the BlinkWithoutDelay example sketch
         //        Adding on the interval is a better way to ensure that succesive periods are identical

   }
 }
 else {  // i.e. if onBoardLedState is HIGH
 
         // if the Led is on, we must wait for the duration to expire before turning it off
   if (currentMillis - previousOnBoardLedMillis >= blinkDuration) {
         // time is up, so change the state to LOW
      onBoardLedState = LOW;
         // and save the time when we made the change
      previousOnBoardLedMillis += blinkDuration;
   }
 }
}

//=======

void updateLed_A_State() {

 if (led_A_State == LOW) {
   if (currentMillis - previousLed_A_Millis >= led_A_Interval) {
      led_A_State = HIGH;
      previousLed_A_Millis += led_A_Interval;
   }
 }
 else {
   if (currentMillis - previousLed_A_Millis >= blinkDuration) {
      led_A_State = LOW;
      previousLed_A_Millis += blinkDuration;
   }
 }    
}

//=======

void updateLed_B_State() {

 if (led_B_State == LOW) {
   if (currentMillis - previousLed_B_Millis >= led_B_Interval) {
      led_B_State = HIGH;
      previousLed_B_Millis += led_B_Interval;
   }
 }
 else {
   if (currentMillis - previousLed_B_Millis >= blinkDuration) {
      led_B_State = LOW;
      previousLed_B_Millis += blinkDuration;
   }
 }    
}

//========

void switchLeds() {
     // this is the code that actually switches the LEDs on and off

 digitalWrite(onBoardLedPin, onBoardLedState);
 digitalWrite(led_A_Pin, led_A_State);
 digitalWrite(led_B_Pin, led_B_State);
 digitalWrite(buttonLed_Pin, buttonLed_State);
}

//=======

void readButton() {

     // this only reads the button state after the button interval has elapsed
     //  this avoids multiple flashes if the button bounces
     // every time the button is pressed it changes buttonLed_State causing the Led to go on or off
     // Notice that there is no need to synchronize this use of millis() with the flashing Leds
 
 if (millis() - previousButtonMillis >= buttonInterval) {

   if (digitalRead(buttonPin) == LOW) {
     buttonLed_State = ! buttonLed_State; // this changes it to LOW if it was HIGH
                                          //   and to HIGH if it was LOW
     previousButtonMillis += buttonInterval;
   }
 }

}

//========

void servoSweep() {

     // this is similar to the servo sweep example except that it uses millis() rather than delay()

     // nothing happens unless the interval has expired
     // the value of currentMillis was set in loop()
 
 if (currentMillis - previousServoMillis >= servoInterval) {
       // its time for another move
   previousServoMillis += servoInterval;
   
   servoPosition = servoPosition + servoDegrees; // servoDegrees might be negative

   if (servoPosition <= servoMinDegrees) {
         // when the servo gets to its minimum position change the interval to change the speed
      if (servoInterval == servoSlowInterval) {
        servoInterval = servoFastInterval;
      }
      else {
       servoInterval = servoSlowInterval;
      }
   }
   if ((servoPosition >= servoMaxDegrees) || (servoPosition <= servoMinDegrees))  {
         // if the servo is at either extreme change the sign of the degrees to make it move the other way
     servoDegrees = - servoDegrees; // reverse direction
         // and update the position to ensure it is within range
     servoPosition = servoPosition + servoDegrees;
   }
       // make the servo move to the next position
   myservo.write(servoPosition);
       // and record the time when the move happened
 }
}

//=====END
Title: Re: Demonstration code for several things at the same time
Post by: Pady on Mar 04, 2014, 10:23 pm
Darn good idea :-)
Title: Re: Demonstration code for several things at the same time
Post by: Jiggy-Ninja on Mar 10, 2014, 12:34 am
I prefer using switch statements for may state variables rather than ifs, even if there's only two states something can be in. I find it easier to follow than trying to match an else with the right if to find out what's going on, especially if they're nested.

So instead of:
Code: [Select]
void updateLed_A_State() {

  if (led_A_State == LOW) {
    if (currentMillis - previousLed_A_Millis >= led_A_Interval) {
       led_A_State = HIGH;
       previousLed_A_Millis = currentMillis;
    }
  }
  else {
    if (currentMillis - previousLed_A_Millis >= blinkDuration) {
       led_A_State = LOW;
       previousLed_A_Millis = currentMillis;
    }
  }   
}

I prefer:
Code: [Select]
void updateLed_A_State()
{
  switch( led_A_State )
  {
    case LOW:
      if (currentMillis - previousLed_A_Millis >= led_A_Interval)
      {
        led_A_State = HIGH;
        previousLed_A_Millis = currentMillis;
      }
   
    case HIGH:
      if (currentMillis - previousLed_A_Millis >= blinkDuration)
      {
        led_A_State = LOW;
        previousLed_A_Millis = currentMillis;
      }
    default:
      ;
  }
}

I also prefer a different bracketing style to yours, but that's neither here nor there.
Title: Re: Demonstration code for several things at the same time
Post by: Paul__B on Mar 10, 2014, 01:25 am

I also prefer a different bracketing style to yours, but that's neither here nor there.


Ah, but if you use "Auto Format", it arranges things in a certain way for you.
Title: Re: Demonstration code for several things at the same time
Post by: Robin2 on Mar 10, 2014, 08:11 am
I debated using switch statements (even just using them in one function to illustrate how they are an alternative to if statements). In the end I decided that it would just add to the learning burden for new users. It would be an unusual program that could avoid if statements but switch statements are always optional - even if convenient when you know them.


I like my bracketing system. The formatting was done manually in Gedit. If I have not been consistent everywhere I apologize.

...R
Title: Re: Demonstration code for several things at the same time
Post by: Coding Badly on Mar 10, 2014, 09:12 am
Code: [Select]
...
    if (currentMillis - previousOnBoardLedMillis >= onBoardLedInterval) {
...
       previousOnBoardLedMillis = currentMillis;
    }


The average interval will be slightly to significantly more than onBoardLedInterval.  For most uses (like blinking an LED) the longer interval is insignificant.  For some uses the longer interval is a failure.

Code: [Select]
       previousOnBoardLedMillis += onBoardLedInterval;

...produces a bit more code but keeps the average interval at exactly onBoardLedInterval.
Title: Re: Demonstration code for several things at the same time
Post by: Robin2 on Mar 10, 2014, 11:52 am
@CodingBadly, I'm interested but I don't understand exactly what you mean by "The average interval will be slightly to significantly more than onBoardLedInterval"

My plan was/is to use a single instant in time (as captured in currentMillis) as the reference point for the flashing of all of the leds so that their timing can't drift apart.

I can't figure out what effect your code would have.

...R
Title: Re: Demonstration code for several things at the same time
Post by: 3dprinter on Mar 10, 2014, 12:23 pm
Nice long example (not all examples can be 1<10 lines).

I wondered what the difference was between the attached file in the first and reply#1 with the code inline. My editor only shows comments lines are shorter  :smiley-mr-green:

I would do it slightly different (which means neither better nor worse)  ^_^

I do not quite get the educational value of having update_LED_state() and switchLEDs() as seperate functions - it means you have to carry LED-desired-state as global variables, when they could be nicely encapsulated. Place most variables as static inside the function where they are exclusivly used - this way you can not inadvertently modify a timer variable elsewhere.

CodingBadly's comment is that if your loop takes - say - 5 millisec to execute (because of some not-yet-written heavy calculation code), then the LEDs will blink at the interval+5ms. By adding "interval" to the  "timer" (not the measured millis() value) you get it to run at the "interval" rate. For a "real" project it may be desirable to include the loop overhead/jitter, for some you want a steady rate.
Title: Re: Demonstration code for several things at the same time
Post by: PeterH on Mar 10, 2014, 01:28 pm

Code: [Select]
       previousOnBoardLedMillis += onBoardLedInterval;

...produces a bit more code but keeps the average interval at exactly onBoardLedInterval.


That is my preferred approach too.

When your things are each implemented in separate self-contained functions s in the original example, I also like to define the state data as local static variables rather than globals. Reducing the scope is beneficial in its own right but in particular this makes copy/paste much safer, and that's something that I would expect novice coders to be doing a lot when starting from examples like this. For example:

Code: [Select]

void blinkLed()
{
static const int LED_PIN = 13;
static const unsigned long BLINK_INTERVAL = 500; // duration of each blink phase
static unsigned long lastBlinkTime = 0;

if(millis() - lastBlinkTime >= BLINK_INTERVAL)
{
digitalWrite(LED_PIN, !digitalRead(LED_PIN));
lastBlinkTime += BLINK_INTERVAL
}
}
Title: Re: Demonstration code for several things at the same time
Post by: Robin2 on Mar 10, 2014, 06:20 pm


That is my preferred approach too.



I'm hoping you or @GodingBadly will explain why.

I did consider static local variables but personally I prefer the simplicity and visibility of globals when I'm working with such a small memory space. (I wouldn't do that with PC code). Also I was trying to limit the amount of new stuff that a newbie has to take in.

I understand what you say about copy/paste, but I guess I'm old fashioned enough to prefer users to understand what's going on.

There is an opportunity for someone to use my code as a starting point for a separate lesson on the use of static local variables :)

And thanks very much for all the comments.

...R
Title: Re: Demonstration code for several things at the same time
Post by: Coding Badly on Mar 10, 2014, 06:57 pm

Two hints...
1. You assume the delta is always 1.  It is not.
2. You assume the time to execute loop is <= 1 millisecond.  In your example that may be true but that will not be true for every application.

Assume millis returns values evenly divisible by seven (0, 7, 14, etcetera) and work through the code by hand.
Title: Re: Demonstration code for several things at the same time
Post by: el_supremo on Mar 10, 2014, 07:16 pm
@jiggy-ninja:
I also prefer the switch statement but you need break statements in there to make it equivalent to the original code. I would write it like this:
Code: [Select]

void updateLed_A_State()
{
  switch( led_A_State )
  {
    case LOW:
      if (currentMillis - previousLed_A_Millis >= led_A_Interval)
      {
        led_A_State = HIGH;
        previousLed_A_Millis = currentMillis;
      }
      break;
     
    case HIGH:
      if (currentMillis - previousLed_A_Millis >= blinkDuration)
      {
        led_A_State = LOW;
        previousLed_A_Millis = currentMillis;
      }
      break;
     
    default:
      break;
  }
}


Pete
Title: Re: Demonstration code for several things at the same time
Post by: Robin2 on Mar 10, 2014, 08:24 pm

I wondered what the difference was between the attached file in the first and reply#1 with the code inline. My editor only shows comments lines are shorter  :smiley-mr-green:



Sorry, I meant to mention this earlier ...

You are quite right, I was just trying to save enough bytes to get within the upload limit. I actually haven't tested the visible version :(

...R
Title: Re: Demonstration code for several things at the same time
Post by: Jiggy-Ninja on Mar 10, 2014, 09:17 pm

@jiggy-ninja:
I also prefer the switch statement but you need break statements in there to make it equivalent to the original code. I would write it like this:

Pete

>.<    Doh!

And that, ladies and gentlemen, is one argument against using switches.
Title: Re: Demonstration code for several things at the same time
Post by: el_supremo on Mar 10, 2014, 11:10 pm
Hey, no, don't give up on switches!
'if' statements can go haywire too if you forget an 'else'! :)

Pete
Title: Re: Demonstration code for several things at the same time
Post by: Robin2 on Mar 10, 2014, 11:55 pm
@CodingBadly and @PeterH,

I think I now see the point you are making. I wrote a couple of spreadsheets to experiment with numbers.

I then set out to modify my sketch but I've run into a very strange problem. All of the functions work fine your way ( += interval) EXCEPT the servo function. After a short period it goes haywire, yet it works perfectly using " = currentMillis".

I think the problem may be due to the much shorter interval (or may be showing up sooner because of the shorter interval). And I think the problem arises because at some stage prevMillis exceeds currentMillis so that currentMillis - prevMillis gives a "negative" number or, since it is an unsigned long, a very large positive number which always satisfies the if statement.

I've had enough for today. I will experiment more tomorrow.

I suspect that the error associated with doing it the "wrong" way (i.e. "= currentMillis") depends on the ratio between the interval between successive values of millis() and the size of interval for the blinks (or whatever). If the blink interval is relatively large the error may not matter. I haven't explored this with my spreadsheet yet.

...R
Title: Re: Demonstration code for several things at the same time
Post by: PeterH on Mar 11, 2014, 12:16 am

I suspect that the error associated with doing it the "wrong" way (i.e. "= currentMillis") depends on the ratio between the interval between successive values of millis() and the size of interval for the blinks (or whatever). If the blink interval is relatively large the error may not matter. I haven't explored this with my spreadsheet yet.


The basic problem is that the code may not evaluate the condition at the precise instant that the interval has elapsed. Suppose for the sake of argument that you were trying to take some action every 100ms and your loop took 5ms to execute. The original code would take up to 5ms to notice that the interval had elapsed. Since the next interval is calculated based on the value of millis() at the point where we notice the interval elapsed, this means the next interval will be delayed by up to 5ms too. In effect, any latency noticing that the condition is true will cause all subsequent processing to slip.

The preferred approach always schedules the next event based on when the current event became due, not when the code noticed that it had occurred. This avoids slippage when there is any latency noticing the event.
Title: Re: Demonstration code for several things at the same time
Post by: Robin2 on Mar 11, 2014, 08:34 am
I eventually figured out the problem while lying in bed.

The problem arises in the servo function because I change the interval after every sweep. As initially written "prevMillis = currentMillis" is at the bottom of the function after the interval has been changed. And when the revised version "prevMillis += interval" is used at the same location it erroneously adds the revised interval. When there is a switch from a short to a long interval that means the prevMillis is actually greater than the next version of currentMillis which gives a "negative" answer to the subtraction (actually a large +ve number) which always evaluates to true.

The solution to that problem is to move "prevMillis += interval" to a position before the interval is changed.

HOWEVER .... (and I'm delighted that this problem gave me time to look at the bigger picture)

FIRST ... @CodingBadly said in Reply #11 that I was assuming that delta (the difference between successive values of millis()) was 1. Of course, as he suspected, I hadn't thought about that at all. BUT ... millis() does in fact increment by 1.

SECOND ... (though, I had forgotten) The code in "BlinkWithouDelay" uses "previousMillis = currentMillis; "

MY CONCLUSION ... is that this is a discussion about angels on the head of a pin. So, in the absence of evidence of a real problem I will not post an updated version of my demo sketch. The present version works and is consistent with BlinkWithoutDelay.

I am wondering if I might write a short accompanying essay that covers the points raised here (this one, the use of Switch and the maintaining State in static local variables).

As always, comments are welcome.

...R
Title: Re: Demonstration code for several things at the same time
Post by: Coding Badly on Mar 11, 2014, 08:45 am
BUT ... millis() does in fact increment by 1.


There you go again making assumptions.  This time you assume I made a mistake (and failed to test your assumption).

What about when the processor is running at 8 MHz?  What about when the fractional part reaches a whole number?
Title: Re: Demonstration code for several things at the same time
Post by: Coding Badly on Mar 11, 2014, 08:48 am
MY CONCLUSION ... is that this is a discussion about angels on the head of a pin.


Uh huh.  Except, of course, when a drifting clock is undesirable.
Title: Re: Demonstration code for several things at the same time
Post by: Robin2 on Mar 11, 2014, 09:18 am

BUT ... millis() does in fact increment by 1.


There you go again making assumptions.  This time you assume I made a mistake (and failed to test your assumption).

What about when the processor is running at 8 MHz?  What about when the fractional part reaches a whole number?




I made no assumptions, certainly not about your coding ability. I wrote a short sketch to test millis() on my Uno. I have another 328 which I could (maybe already have) set up for 8MHz but I haven't tested that. I also have some Attiny 45's that I could set up for 1MHz. Most beginners for whom my demo may be useful are likely to be using an Uno at 16MHz.

If you know what different increments of millis() are possible in different circumstances I would appreciate it if you would tell me, rather than teasing with questions.

As regards the drifting clock - I started this to produce a more extensive example of "BlinkWithoutDelay" - nothing more. I expect that someone who needs better performance will also know how to get it, or will start a new Thread about it. I don't see any need to complicate matters for newbies. It would be another thing entirely if my code did not do what it claims (and I believe it does).

None of this means that I have not been interested in your comments - I will certainly bear them in mind for my own projects.

...R
Title: Re: Demonstration code for several things at the same time
Post by: PeterH on Mar 11, 2014, 03:57 pm

MY CONCLUSION ... is that this is a discussion about angels on the head of a pin. So, in the absence of evidence of a real problem I will not post an updated version of my demo sketch. The present version works and is consistent with BlinkWithoutDelay.


I disagree completely - your conclusion is wrong. The technique used in your example is flawed and is vulnerable to slip. The classic 'blink without delay' makes the same mistake (as well as others). It is quite a common mistake, and the fact that it's taking so long to explain it to you demonstrates that it's quite a subtle problem - but it is still a problem.

The problem is that the timing will be subject to cumulative slip when there is any latency between the timed condition becoming true, and the code to detect that executing. As soon as that latency exceeds 1ms, the time of the next scheduled event will be wrong, and so on for all subsequent events. The timing will have slipped by a small amount. It will keep doing this every time there is any latency. There may be some situations where that doesn't matter, and it's even possible to design a sketch that relies on that behaviour, but as a general approach for making something happen at regular intervals this is a problem.

Fortunately the solution is easy: schedule the next event based on when the current event was due, not when it was detected.
Title: Re: Demonstration code for several things at the same time
Post by: Coding Badly on Mar 11, 2014, 06:23 pm
If you know what different increments of millis() are possible in different circumstances I would appreciate it if you would tell me, rather than teasing with questions.


Uno running at 16 MHz...

Code: [Select]

void setup()
{
  Serial.begin( 115200 );
  Serial.println( F( "Five seconds to lift off..." ) );
}

static unsigned long Mark;
static unsigned long Previous;
static unsigned short Histogram[256];

void loop()
{
  unsigned long Current;
  unsigned long Delta;
 
  Current = millis();

  Delta = Current - Previous;

  if ( Delta != 0 )
  {
    Previous = Current;

    if ( Delta < 256 )
    {
      ++Histogram[(unsigned char)Delta];
    }
    else
    {
      ++Histogram[255];
    }
   
    return;
  }

  if ( Current - Mark >= 5000ul )
  {
    for ( int i = 0; i < 256; ++i )
    {
      Serial.print( i );
      Serial.write( '\t' );
      Serial.println( Histogram[i] );
    }
    Serial.println();
    while ( true );
  }
}


Code: [Select]
Five seconds to lift off...
0 0
1 4766
2 117
3 0
4 0
5 0
6 0
7 0
8 0
9 0
10 0
11 0
12 0
13 0
14 0
15 0
16 0
17 0
18 0
19 0
20 0
21 0
22 0
23 0
24 0
25 0
26 0
27 0
28 0
29 0
30 0
31 0
32 0
33 0
34 0
35 0
36 0
37 0
38 0
39 0
40 0
41 0
42 0
43 0
44 0
45 0
46 0
47 0
48 0
49 0
50 0
51 0
52 0
53 0
54 0
55 0
56 0
57 0
58 0
59 0
60 0
61 0
62 0
63 0
64 0
65 0
66 0
67 0
68 0
69 0
70 0
71 0
72 0
73 0
74 0
75 0
76 0
77 0
78 0
79 0
80 0
81 0
82 0
83 0
84 0
85 0
86 0
87 0
88 0
89 0
90 0
91 0
92 0
93 0
94 0
95 0
96 0
97 0
98 0
99 0
100 0
101 0
102 0
103 0
104 0
105 0
106 0
107 0
108 0
109 0
110 0
111 0
112 0
113 0
114 0
115 0
116 0
117 0
118 0
119 0
120 0
121 0
122 0
123 0
124 0
125 0
126 0
127 0
128 0
129 0
130 0
131 0
132 0
133 0
134 0
135 0
136 0
137 0
138 0
139 0
140 0
141 0
142 0
143 0
144 0
145 0
146 0
147 0
148 0
149 0
150 0
151 0
152 0
153 0
154 0
155 0
156 0
157 0
158 0
159 0
160 0
161 0
162 0
163 0
164 0
165 0
166 0
167 0
168 0
169 0
170 0
171 0
172 0
173 0
174 0
175 0
176 0
177 0
178 0
179 0
180 0
181 0
182 0
183 0
184 0
185 0
186 0
187 0
188 0
189 0
190 0
191 0
192 0
193 0
194 0
195 0
196 0
197 0
198 0
199 0
200 0
201 0
202 0
203 0
204 0
205 0
206 0
207 0
208 0
209 0
210 0
211 0
212 0
213 0
214 0
215 0
216 0
217 0
218 0
219 0
220 0
221 0
222 0
223 0
224 0
225 0
226 0
227 0
228 0
229 0
230 0
231 0
232 0
233 0
234 0
235 0
236 0
237 0
238 0
239 0
240 0
241 0
242 0
243 0
244 0
245 0
246 0
247 0
248 0
249 0
250 0
251 0
252 0
253 0
254 0
255 0


2.4% of the time a two was returned otherwise a one is returned.  Which passes a basic stink test: 4766 + 2*117 = 5000.
Title: Re: Demonstration code for several things at the same time
Post by: Coding Badly on Mar 11, 2014, 06:29 pm
As regards the drifting clock - I started this to produce a more extensive example of "BlinkWithoutDelay" - nothing more. I expect that someone who needs better performance will also know how to get it, or will start a new Thread about it. I don't see any need to complicate matters for newbies. It would be another thing entirely if my code did not do what it claims (and I believe it does).


Perfect.  My only concern was that your audience knows what they are getting and, with that, they do.
Title: Re: Demonstration code for several things at the same time
Post by: Robin2 on Mar 11, 2014, 06:30 pm
Thanks for your code @CodingBadly. I will try it and then I also want to reply to @PeterH.

...R
Title: Re: Demonstration code for several things at the same time
Post by: 3dprinter on Mar 11, 2014, 08:03 pm
Me sits here feeling slightly miffed :smiley-eek-blue: that my explanation (reply#8)
of the reason why timer += increment is the better way is quietly ignored by Robin2
-- only to be repeated by PeterH (reply#17)  ;)  ;)  ;) (and I am sure PeterH invented his own).

Robin2 -
Code: [Select]
void loop() {
  delay(12) ;
  Serial.println(millis()) ;
  }

millis() now increases by 12 in each loop ! Eh?! And sometimes by 13. Eh eh!?!?

Quote
SECOND ... (though, I had forgotten) The code in "BlinkWithouDelay" uses "previousMillis = currentMillis; "

Unfortunatly there are several things missing, misleading and sometimes plain wrong in the reference/tutorials.
These have been pointed out, but the Arduino team has choosen not to use advice from this forum on that matter.

Quote
MY CONCLUSION ... is that this is a discussion about angels on the head of a pin

You're entitled to your point of view. However, this is not a religous point - it is mathematically deterministically provable true.
It may be for some applications the slippage/jittery is of no consequence, but it is there.

PeterH said it succinctly "the fact that it's taking so long to explain it to you demonstrates that it's quite a subtle problem - but it is still a problem."
Title: Re: Demonstration code for several things at the same time
Post by: Robin2 on Mar 11, 2014, 08:07 pm
11 Mar 2012

@CodingBadly, I modified your code a bit to explore the phenomenon further. It seems that millis() increments by 2 every 41 or 42 steps. My code is below. Let me know if I have misrepresented your ideas. It could be interesting to try to figure out what give rise to the 2 step, and whether the frequency varies.

@PeterH, Based on the data from that sketch I think I can see the problem you refer to. For example, suppose the required interval is 41 millisecs. Let's also assume that on the previous iteration millis() was 40 (so the event did not happen). On the next iteration millis() will be 42 (because it jumped 2 places) and then the event will be triggered a millisecond late. If I use that new value of millis() as the base for the next event it should happen when millis() becomes 83. Whereas if I calculated from the originally intended event time (41) I would schedule the next event for 82. On the other hand if the required interval doesn't coincide with the millis() jump there won't be any error.

I think what has been confusing me (maybe still does) is your phrase "when there is any latency between the timed condition becoming true, and the code to detect that executing". I believe that by "saving" millis() at the start of each iteration of loop() it doesn't matter when the code actually gets around to executing the event. And the timing of the subsequent event is not linked to the actual time of execution of the previous event. Instead it is linked to the value of millis() at the time the loop() began its iteration.

Bearing in mind the limited purpose of my sketch and its intended audience I still think the problem is small enough that the balance of advantage lies with being consistent with the usage in Blink-Without-Delay rather than trying to explain this problem to newbies.

As I said earlier, I am thinking of writing a short additional note to cover this point and the two others that have been raised. Your comment has helped to clarify my understanding, and may make a description easier to write. Do feel free to write a few explanatory sentences/paragraphs on the subject yourself to save me the bother.

@Msquare, your post just came in as I finished this. Sorry if I was too thick to see your point. You, also, are invited to write a suitable explanation for newbies.

...R

Code: [Select]

static unsigned long Mark;
static unsigned long Previous;
static unsigned short Histogram[256];
static unsigned short OverOne[256];


void setup()
{
  Serial.begin( 115200 );
  Serial.println( F( "Five seconds to lift off..." ) );
 
  unsigned long Current;
  unsigned long Delta;
 
  int count = 0;
 
  while (count < 256) {
    Current = millis();
    Delta = Current - Previous;
    if (Delta > 0) {
        Previous = Current;
      Histogram[count] = (unsigned char)Delta;
      if (Delta > 1) {
        OverOne[count] = count;
      }


      count++;
    }
  }
  for ( int i = 1; i < 256; ++i )
    {
      Serial.print( i );
      Serial.write( '\t' );
      Serial.print( Histogram[i] );
      Serial.write( '\t' );
      Serial.println( OverOne[i] );
    }
  Serial.println();
}



void loop()
{
 
}
Title: Re: Demonstration code for several things at the same time
Post by: CrossRoads on Mar 11, 2014, 08:28 pm
Robin2,
This was how AWOL or CodingBadly or PaulStoffregen or maybe PaulS explained accurate time keeping to me:
Code: [Select]

void loop(){
currentMicros = micros();  // I have found micros to keep more accurate time
// likely because 16 clocks is 1uS, and millis has some "fudge factor" in it.
elapsedMicros = currentMicros - nextMicros; 
// I had trouble with this evaluation in an if early on, so now I do it outside
if (elapsedMicros >= duration){
// here's the key:
nextMicros = nextMicros + duration; // set up time for next comparison
/* nextMicros is kept independent of currentMicros -
so if currentMicros capture was delayed for any reason,
the delay does not impact when the next time comparison will happen.
the comparison will still be at a multiple of "duration".
the actual real-world time between comparisons may then wiggle some, this will be   
independent of that wiggle. */

// do the timed event
  } // end time check
} // end loop
Title: Re: Demonstration code for several things at the same time
Post by: Coding Badly on Mar 11, 2014, 09:39 pm
It seems that millis() increments by 2 every 41 or 42 steps.


125 / 3.  That's the fractional part for 16 Mhz.  I believe it's different for other speeds.
Title: Re: Demonstration code for several things at the same time
Post by: PeterH on Mar 11, 2014, 11:01 pm

I think what has been confusing me (maybe still does) is your phrase "when there is any latency between the timed condition becoming true, and the code to detect that executing". I believe that by "saving" millis() at the start of each iteration of loop() it doesn't matter when the code actually gets around to executing the event. And the timing of the subsequent event is not linked to the actual time of execution of the previous event. Instead it is linked to the value of millis() at the time the loop() began its iteration.


I think you have understood the problem correctly.

The scope for latency within a specific sketch can be affected by the placement of the call to millis() relative to the call checking whether the time has elapsed, and by how frequently the loop executes, but the latency can never be reduced to zero.

This is a problem that has varying severity and varying impact. Arguably, in many cases it can be ignored. However, the issue of how to control multiple things independently, including controlling independently timed things, crops up so frequently, and is so fundamentally important for newcomers to understand, that I think having a really good example of 'best practice', together with an explanation of why that is the best practice, would be extremely useful. It's a great shame, and a lost opportunity, that the 'blink without delay' example is so poorly explained and so mediocre in implementation. This is why I'm so keen for you to develop your example to the point where it really does represent best practice, and not just 'good enough for simple examples'.
Title: Re: Demonstration code for several things at the same time
Post by: Coding Badly on Mar 12, 2014, 03:10 am

A word of caution about the basic "mile marker" approach: an overrun will wreak havoc.  A while loop overcomes the problem.

An example from CrossRoads' snippet...

Code: [Select]
void setup()
{
 Serial.begin( 115200 );
}

void loop()
{
 unsigned long currentMicros;
 unsigned long elapsedMicros;
 static unsigned long nextMicros;
 const unsigned long duration = 1000000ul;

 currentMicros = micros();
 elapsedMicros = currentMicros - nextMicros;  
 if ( elapsedMicros >= duration )
 {
   nextMicros = nextMicros + duration;
   Serial.println( currentMicros );
 }
 // Pretend loop takes too long to execute
 delay( 1001 );
}


Change the if to a while.
Title: Re: Demonstration code for several things at the same time
Post by: Robin2 on Mar 12, 2014, 08:12 am
This is all provin' very stimulatin' to the few remaining grey cells ...

@CrossRoads, thank you, but I am not concerned with accuracy greater than you get from millis(). This is just intended as a simple learning device for newbies.

@PeterH and @CodingBadly, I hope you will have realized that my only objection to doing it "properly" was the risk that explaining the change would so confuse a newbie that all value from the demo code would be lost. I think I have now figured out a simple way to link the "+= interval" version to the "= currentMillis" version that's in Blink-Without-Delay without the need for a complex explanation.

I will modify my example and maybe post the updated version later today if I feel the change will be sufficiently unobtrusive. Edit to add ... I have now updated the code attached to the original post and the code in Reply #1.

@CrossRoads, I don't understand your use of the term "mile marker".

...R
Title: Re: Demonstration code for several things at the same time
Post by: CrossRoads on Mar 13, 2014, 05:35 am
"mile marker" refers to the event happening at regular intervals:
Code: [Select]

the comparison will still be at a multiple of "duration".

as I indicated in my code comments.
Title: Re: Demonstration code for several things at the same time
Post by: Robin2 on Mar 13, 2014, 08:48 am
Sorry @Crossroads, but I still don't see how your comments (or @CodingBadly's comments on your comments) to relate to my demo sketch. I thought you were recommending using micros instead of millis for more accurate timing.

...R
Title: Re: Demonstration code for several things at the same time
Post by: cootcraig on Mar 13, 2014, 09:08 pm

I have prepared the attached example sketch in the hope that it will be a
suitable model. I have tested it on an Uno and a Mega. I have called it
"SeveralThingsAtTheSameTime.ino". (It seems to be too long to show the
code directly in this post)
...
It also uses the "state machine" concept to manage the various activities
and enable the different functions to determine what to do.
...
Comments are welcome.


Thank you for this, I will be studying it.

I'm new to Arduino coding and learning what and how can be fit in Arduino
IDE code.  My starting approach was to leverage this SimpleTimer code:

http://playground.arduino.cc/Code/SimpleTimer#.UyIPih_f9ic (http://playground.arduino.cc/Code/SimpleTimer#.UyIPih_f9ic)

Here is a code fragment where I do periodic Serial writes.  This not
really equivalent to what your code is doing, but this is my starting
point.

Code: [Select]

...
#include <SimpleTimer.h>
...
SimpleTimer timer;
...
void setup()
{
...
  timer.setInterval((5*1000), timerWrite);
...
}
void loop()
{
...
  timer.run();
...
}
// Periodic write to Serial to test RPi <-> Arduino
void timerWrite()
{
  // Code here that queues up some text to write on Serial
}

Title: Re: Demonstration code for several things at the same time
Post by: Robin2 on Mar 13, 2014, 09:58 pm
@cootcraig, thank you for your kind words.

If you want get advice about the SimpleTimer library (about which I know nothing) I would appreciate it if you would start a new Thread as I would like to keep this thread to the one subject so as not to confuse newcomers.

...R
Title: Re: Demonstration code for several things at the same time
Post by: cootcraig on Mar 13, 2014, 11:43 pm

If you want get advice about the SimpleTimer library (about which I know nothing) I would appreciate it if you would start a new Thread as I would like to keep this thread to the one subject so as not to confuse newcomers.

...R

I'm not looking for help with SimpleTimer, sorry.  I'm learning how to multiple things on an Arduino myself., just not starting  with the same demo.  I will continue watching this thread.
Title: Re: Demonstration code for several things at the same time
Post by: evancleary on Mar 14, 2014, 03:42 am
hey guys,

i took your example and tried to apply it to a binary thermometer that i had already done
i got it to comply but it dosnt function like it should

Moderator edit: offensive phrase remove

any ideas?
Title: Re: Demonstration code for several things at the same time
Post by: keeper63 on Mar 14, 2014, 04:18 am

any ideas?


I don't know about the code, but you have a serial.print() line in the loop() function that I would like to encourage you to edit, or the moderators may do it for you.

/remember, this forum caters to many age groups and such; let's try to keep it somewhat in line with that...
Title: Re: Demonstration code for several things at the same time
Post by: Coding Badly on Mar 14, 2014, 06:09 am
...or the moderators may do it for you.


Too late.

Quote
/remember, this forum caters to many age groups and such; let's try to keep it somewhat in line with that...


Well stated @cr0sh.  Thank you for your post.

@evancleary, I make you this promise: I will not waste my time again cleaning up your mess.
Title: Re: Demonstration code for several things at the same time
Post by: Robin2 on Mar 14, 2014, 08:17 am
I take it that no input is required from me until there is some code to look at?

...R
Title: Re: Demonstration code for several things at the same time
Post by: evancleary on Mar 14, 2014, 06:12 pm
apologies for the bad language in the last post guys
was messing about with the print function and forgot to remove the phrase before post

Code: [Select]
const int ledPin1= 13;
const int ledPin2= 12;
const int ledPin3= 11; 
const int ledPin4= 10;
const int ledPin5= 9;
int sensorValue = 0;

// ==================variables====================================

int degrees_21 = LOW;
int degrees_22 = LOW;
int degrees_23 = LOW;   // these are my seperate functions
int degrees_24 = LOW;   // kept the rang of temp around room temp for
int degrees_25 = LOW;   // trial run
int degrees_26 = LOW;

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

void setup()

{
  pinMode(ledPin1, OUTPUT);
  pinMode(ledPin2, OUTPUT);
  pinMode(ledPin3, OUTPUT); 
  pinMode(ledPin4, OUTPUT);
  pinMode(ledPin5, OUTPUT);
 
  Serial.begin(9600);
}

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

void loop()

{
  sensorValue = analogRead(A0);
  Serial.println(sensorValue);
 

updatedegrees_21();
updatedegrees_22();
updatedegrees_23();
updatedegrees_24();
updatedegrees_25();
updatedegrees_26();


}

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

void updatedegrees_21()     
{
  if (degrees_21 == LOW)     // was thinking about putting an else (degrees_21 = LOW)
  {                              // but didnt think it was required
    if (sensorValue <= 43)//21
    degrees_21 = HIGH;
  }
        if (degrees_21 == HIGH)   
      { 
          digitalWrite(ledPin1, HIGH);
          digitalWrite(ledPin2, LOW);
          digitalWrite(ledPin3, HIGH);
          digitalWrite(ledPin4, LOW);
          digitalWrite(ledPin5, HIGH);
      }
   
}

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

void updatedegrees_22()
{
  if (degrees_22 == LOW)
  {
    if (sensorValue > 43 && sensorValue <= 45)//22
    degrees_22 = HIGH;
  }
        if (degrees_22 == HIGH)
      {
          digitalWrite(ledPin1, HIGH);
          digitalWrite(ledPin2, LOW);
          digitalWrite(ledPin3, HIGH);
          digitalWrite(ledPin4, HIGH);
          digitalWrite(ledPin5, LOW);
       }
   
}
     
//======================================================================

void updatedegrees_23()
{
  if (degrees_23 == LOW)
  {
    if (sensorValue > 45 && sensorValue <= 47)
     degrees_23 = HIGH;
   }
        if (degrees_23 == HIGH);
        {
            digitalWrite(ledPin1, HIGH);
            digitalWrite(ledPin2, LOW);
            digitalWrite(ledPin3, HIGH);
            digitalWrite(ledPin4, HIGH);
            digitalWrite(ledPin5, HIGH);
        }
   
}
 
//==========================================================================

void updatedegrees_24()
{
  if (degrees_24 == LOW)
  {
    if (sensorValue > 45 && sensorValue <= 47)
     degrees_24 = HIGH;
   }
        if (degrees_24 == HIGH);
        {
            digitalWrite(ledPin1, HIGH);
            digitalWrite(ledPin2, HIGH);
            digitalWrite(ledPin3, LOW);
            digitalWrite(ledPin4, LOW);
            digitalWrite(ledPin5, LOW);
        }
   
}

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

void updatedegrees_25()
{
  if (degrees_25 == LOW)
  {
    if (sensorValue > 49 && sensorValue <= 52)//25
    degrees_25 == HIGH;
  }
      if (degrees_25 == HIGH)
      {
          digitalWrite(ledPin1, HIGH);
          digitalWrite(ledPin2, HIGH);
          digitalWrite(ledPin3, LOW);
          digitalWrite(ledPin4, LOW);
          digitalWrite(ledPin5, HIGH);
      }
 
}

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

void updatedegrees_26()
{
  if (degrees_26 == LOW)
  {
     if (sensorValue > 52 && sensorValue <= 54)
     degrees_26 = HIGH;
  }
        if (degrees_26 == HIGH)
      {
          digitalWrite(ledPin1, HIGH);
          digitalWrite(ledPin2, HIGH);
          digitalWrite(ledPin3, LOW);
          digitalWrite(ledPin4, HIGH);
          digitalWrite(ledPin5, LOW);
      }
 


in the version of this code that i have working i basically have a load of if and else function on a delayed loop which constantly checks sensorValue, thought applying it with non-blocked architecture would be a good training exercise

@CodingBadly Im not looking for anyone to clean up my mess just looking for some advice or point in the right direction because i have a breathalyzer with multiple inputs/outputs and functions to have completed in the next 2 weeks

yet again folks my apologies
Title: Re: Demonstration code for several things at the same time
Post by: CrossRoads on Mar 14, 2014, 08:06 pm
For all these, you could simplify some:

void updatedegrees_25()
{
 if (degrees_25 == LOW)
 {
   if (sensorValue > 49 && sensorValue <= 52)//25
   degrees_25 == HIGH;
 }
     if (degrees_25 == HIGH)
     {
         digitalWrite(ledPin1, HIGH);
         digitalWrite(ledPin2, HIGH);
         digitalWrite(ledPin3, LOW);
         digitalWrite(ledPin4, LOW);
         digitalWrite(ledPin5, HIGH);
     }
 
}


What makes degrees_25 and the others Low again to allow another reading?
Title: Re: Demonstration code for several things at the same time
Post by: CrossRoads on Mar 14, 2014, 08:07 pm
(apparently strikeout does not work within code tags)
Title: Re: Demonstration code for several things at the same time
Post by: CrossRoads on Mar 14, 2014, 08:10 pm
Do you also find this update really fast so the outputs seem to be the same all the time?
I think I would add a time check and only update every 1/10 or 1/5 second or so.
Title: Re: Demonstration code for several things at the same time
Post by: evancleary on Mar 14, 2014, 08:27 pm
was thinking that falling out of the stated sensorValue range would set the function back to when checked and found not to be

may use an else function stating that when not within range =   LOW

im gona be looking into some tutorials posted up by GrumpyMike to try get my head more around the logic required 
Title: Re: Demonstration code for several things at the same time
Post by: Robin2 on Mar 14, 2014, 09:19 pm
What is all the digitalWrite(ledPinX, HiGH/LOW) stuff?

If these were put in named functions it would make the code much clearer.

It may also be possible to do them all in one function to reduce duplication of code.

...R
Title: Re: Demonstration code for several things at the same time
Post by: evancleary on Mar 14, 2014, 09:31 pm
its representing the degrees celcius in a 5 bit binary led setup

ie 26 degrees = 1 1 0 1 0

thus led 1 HIGH and so on

got some advice from GrumpyMike earlier saying that they can be given an array function which this page shows how to

http://www.thebox.myzen.co.uk/Tutorial/Arrays.html

it would seem ive got a lot of ground to cover and not a whole lot of time to do it considering i have 2 exams in the next couple of weeks to boot, so it all systems are non stop.  This is why Ive been looking for a bit of direction, gona run through as much of Mikes tutorials as I can and hopefully Ill be able to work out this project
Title: Re: Demonstration code for several things at the same time
Post by: Robin2 on Mar 15, 2014, 08:52 am
I think we could help you much better if you give us a clear description (in english, not code) of what you want to do.

You have jumped into the middle of this Thread (which is fine) but you might have been better starting your own Thread. I suspect you are assuming we know a great deal more about your project than we actually do. Assume we know nothing!

It's not even clear to me how you are thinking of making use of my demo sketch (which, I assume, is the reason you have asked your question here).

...R
Title: Re: Demonstration code for several things at the same time
Post by: Coding Badly on Mar 15, 2014, 09:00 am
...but you might have been better starting your own Thread.


He has.  Twice...
http://forum.arduino.cc/index.php?topic=225213.0
http://forum.arduino.cc/index.php?topic=224682.0

Quote
@CodingBadly Im not looking for anyone to clean up my mess...


Then stop posting obscenities, stop cross-posting, and stop hijacking.
Title: Re: Demonstration code for several things at the same time
Post by: Robin2 on Mar 15, 2014, 12:09 pm

He has.  Twice...


Thanks, I hadn't spotted those.

@evancleary, over to you to sort things out ....

...R
Title: Re: Demonstration code for several things at the same time
Post by: evancleary on Mar 15, 2014, 02:13 pm
ok so i made a post first time round which is the second link

after doing that i came across your post here which seemed extremely helpful because im going to have to integrate multiple functions into the one code , so i made a reply then explaining fully what it was i hoped to achieve and how i was planning to use your code in helping me learn what it was i needed to know, however that reply that i made to this post ended up being its own post? with its own new title,a title which i didnt give it.  Dont know how or why?

Apologies if my code dosnt seem neat or logical, yet again im very new to this and am just trying to find me feet with it

also yet again apologies for the obscenities but as already stated it was an absolute mistake

didnt know that i was hijacking or that posting on multiple links was a bad thing, i dont really use forums

how and ever thanks for the post it has given me an idea of how to go about getting a main loop to reference function loops, between this and GrumpyMikes stuff i should be on the right track
Title: Re: Demonstration code for several things at the same time
Post by: Robin2 on Mar 15, 2014, 02:46 pm
The problem with multiple Threads on the same subject is that none of them has the full picture. And someone may waste his/her time giving advice on one Thread which has already been given on another.

From your own point of view the problem is that contributors will only have part of the picture and won't be able to give you the best advice.

Hijacking a Thread is slightly different - it usually means causing the Thread to wander off into a discussion that the person who started the Thread hadn't intended. In this case your interest seems to have been to adapt my code to your project. I think you lose most from using this Thread for that because readers won't expect your problem to appear here.

I suggest you ask the moderator to merge your other two threads and then continue your enquiries there, and not here.

And, as I said earlier, you need to provide a very clear description of what you are trying to do before you tell us how you are trying to do it.

...R
Title: Re: Demonstration code for several things at the same time
Post by: beefy23 on Mar 25, 2014, 12:41 am
Robin,

Keith here, you referred me to this thread a couple of days ago. Thanks again for doing something like this for irritating beginners like myself  :)

It's a bit brain frying for me at present but with a bit of repetitive studying I'm sure it will start coming together for me. One of the earlier responses was about the bracketing positioning. As a beginner the first thing that made it difficult for me to read through the code, was the positioning of the curly brackets.

I modified the bracket positioning to make the functions more graphically visible (if that's a way to put it). Now I can clearly see a function inside a function inside a function, so to speak, and it leaves my beginners brain more free to learn the coding.

Example:

void updateLed_A_State()
{
    if (led_A_State == LOW)
        {
        if (currentMillis - previousLed_A_Millis >= led_A_Interval)
               {
                 led_A_State = HIGH;
                 previousLed_A_Millis += led_A_Interval;
               }
        }
      else
        {
            if (currentMillis - previousLed_A_Millis >= blinkDuration)
              {
                 led_A_State = LOW;
                 previousLed_A_Millis += blinkDuration;
              }
        }   
}

I hope I did all that correctly LOL.

Opening and closing brackets of each function line up vertically. Brackets of "inner" functions have good distance on indentation. I realise as a proficient experienced programmer you may detest this for your own use, but seeing as your sketch is for beginners I thought I'd mention this.

Keith.
Title: Re: Demonstration code for several things at the same time
Post by: PeterH on Mar 25, 2014, 02:52 am

I modified the bracket positioning to make the functions more graphically visible (if that's a way to put it). Now I can clearly see a function inside a function inside a function, so to speak, and it leaves my beginners brain more free to learn the coding.


That indentation is horrible. I recommend you use Tools / Autoformat to put it right.
Title: Re: Demonstration code for several things at the same time
Post by: Robin2 on Mar 25, 2014, 09:39 am
Indentation is a personal choice. Do it any way you like.

I like my way.

It is a good idea to use a system that is similar to what autoformat produces for stuff that you propose to post here. People find it easier to get a quick understanding if the format is familiar.

MUCH more important, @beefy23,    ALWAYS enclose code in CODE tags so that it displays properly. Read the stickies at the top of the Forum for instructions.

...R
Title: Re: Demonstration code for several things at the same time
Post by: beefy23 on Mar 25, 2014, 09:17 pm


I modified the bracket positioning to make the functions more graphically visible (if that's a way to put it). Now I can clearly see a function inside a function inside a function, so to speak, and it leaves my beginners brain more free to learn the coding.


That indentation is horrible. I recommend you use Tools / Autoformat to put it right.


Wow Pete,

that's highly constructive and educational. I love the explanation you give of why it's horrible. I was speaking as a beginner, saying what I personally find makes the code much easier to read for me. Robin started this for beginners so I simply said what aided me as a beginner to follow the code. I wasn't saying Robin or anyone else should coding should code like this themselves. I even said to Robin that he may detest that method himself.

I'll take note of your recommendation and see what results I get when I use the auto feature. For a beginner I may personally  find that result horrible. Then I can come back to you and say it's horrible and not say why.

As for my recommendation to you, don't comment if all you can say is something is horrible without giving any explanation as to why. Should I start being just as "constructive" as you and we can both start throwing rubbish at each other. Forums becomes a great place when that starts.

Edit:
I've just went at took a look at the way Jiggy Ninja (the one who said he prefers a different bracketing arrangement) does his code and remarkably it's very similar to what I did. Looks like there's 2 of us have a "horrible" arrangement. To me it's very clear and easy on the eyes. Functions stand out so clearly, perfect for a beginners eyes. I suspect I will find your personal method of bracketing much more horrible.

Keith.
Title: Re: Demonstration code for several things at the same time
Post by: beefy23 on Mar 25, 2014, 09:20 pm
Hi Robin,

thanks for the explanation on why to use the autoformat, and I'll read the stickies about putting code in the threads.

Keith.
Title: Re: Demonstration code for several things at the same time
Post by: altimmons on Mar 26, 2014, 03:17 am
I was just struggling with this myself (doing several things at once).  I will pick through the code tonight.  I appreciate it.
Title: Re: Demonstration code for several things at the same time
Post by: Robin2 on Mar 26, 2014, 10:15 am

that's highly constructive and educational. I love the explanation you give of why it's horrible.


You need to develop a thick skin here. @PeterH is by no means the most critical. Interpret "is horrible" as "I don't like it" and get over it.

...R
Title: Re: Demonstration code for several things at the same time
Post by: beefy23 on Mar 27, 2014, 01:16 am


that's highly constructive and educational. I love the explanation you give of why it's horrible.


You need to develop a thick skin here. @PeterH is by no means the most critical. Interpret "is horrible" as "I don't like it" and get over it.

...R


Completely disagree Robin.

First of all I am "over it", but I wouldn't be over it if I hadn't responded to that irritating comment.

How is it supposed to work here ??. Someone says something bordering on insulting, and definitely not constructive or educational, and the one he's telling it to just has to "get over it" and say nothing. I don't work that way, if someone talks pointless rubbish to me, I let them know I don't accept it and I give something back. Talk constructively to me, and as you have seen from my other posts I express thanks and talk with respect to others.

It's interesting that you aren't saying to Pete that if he doesn't like my bracketing style then HE should get over it and not post pointless aggressive comments. C'mon think about who is the one that initiated this rubbish, and give him the talking to, not me.

I've been a member of quite a few forums for a few years now, and comments like Pete made do nothing except irritate others & start a crap fight. And working on "interpretation" is the worst thing you can do when all there is to go on is written words, so when commenting, that should be taken into account.
Title: Re: Demonstration code for several things at the same time
Post by: Robin2 on Mar 27, 2014, 08:13 am
I complain about unhelpful and offensive comments too, including recently.

I don't happen to think that saying the appearance of something is "horrible" is insulting or offensive. It is certainly not unusual and is not confined to the sphere of programming.

Different people like different things and I believe they should be allowed to express their opinions even if we don't like them.

And I doubt if 0.0001% of human statements are ever supported by a justification.

...R
Title: Re: Demonstration code for several things at the same time
Post by: beefy23 on Mar 27, 2014, 10:30 am
Well, it's all a matter of opinion and it looks like you and me disagree.

So my advice to you is right back at you what you said to me. Why don't you get over it, get a thicker skin, and stop being bothered by my opinion about a comment made to me. I'm sure you could devote your time to some other beginners.

I've just been on the AVR Freaks forum today, and they are having a problem with certain responses. The basic request over there is that is you don't have anything decent to say then don't say it.

Keith.
Title: Re: Demonstration code for several things at the same time
Post by: Robin2 on Mar 27, 2014, 01:47 pm

and stop being bothered by my opinion about a comment made to me


My original comment in response to your opinion post was intended as a friendly assistance to somebody new to this Forum. I'm sorry you haven't seen it like that.

...R
Title: Re: Demonstration code for several things at the same time
Post by: beefy23 on Mar 28, 2014, 01:26 am


and stop being bothered by my opinion about a comment made to me


My original comment in response to your opinion post was intended as a friendly assistance to somebody new to this Forum. I'm sorry you haven't seen it like that.

...R


Robin,

thank you for your good intentions with your friendly advice. You could however, choose better words than "get over it".

The problem is I find your advice very one sided, unfair, and not conducive to helping this forum become a better one. You are totally condoning how Pete can talk to a beginner on the forum, and telling the beginner to just get over it. Further you are saying people should be allowed to express their opinions, so it's OK for Pete to post a worthless knockdown comment to a beginner, but it seems like I should not be expressing my opinion about that comment, and I should get a thick skin and get over it. So where is my freedom to express my opinion. Seems like different rules for me and Pete.

I've been busting my guts the last few days learning this coding because it's all fairly new to me. As a beginner I come to ask questions with a little nervousness, and a feeling that I may ask irritating questions. I've clearly stated I am a beginner so when a more established member has nothing more to say than, "That's horrible" without explaining why, it gets my back up a bit, and as you say member should be free to do, I express my opinion back. I'm  rather shocked that your opinion is not more along the lines of "let's keep comments constructive", especially when beginners are the target.

Just because your advice is supposed to be friendly does not mean I will lie down and take it if I feel it's completely wrong and unfair. As you said people should be free to express their opinion and looks like I'm following your advice and doing exactly that. Seems when  I give the same advice to you (my last post) that you originally gave to me, then you say I'm not seeing your advice as friendly. Seems to me like you can dish out your friendly advice but you don't like it when someone disagrees.

Don't try and make me out to be the bad one. Sparks (Petes' comment) create fires. The answer lies in not letting the sparks start.

Keith.
Title: Re: Demonstration code for several things at the same time
Post by: JChristensen on Mar 28, 2014, 02:14 am
Hi Keith,

Welcome to the forum :D  Here's my $0.02 on the indentation/style business (guaranteed to be worth every penny ;))

As you can well imagine, no two people do it exactly the same way. And people get very invested (I might say overly so) in the particular way they do it (yes, me too, absolutely). Some companies write extensive rules that specify how every tiny syntax feature should be written. But without going that far, there are certain norms or patterns or conventions that are common. It's in a programmer's best interest to adopt something fairly close because others will be able to read their code easier and vice-versa.

I'm sure I can't do a decent job here of explaining typical norms or conventions. Best to study several texts to get a feel for it. The autoformat tool does do a good job so a person can't go too far wrong with that. Most folks, once they've been at it for a while and have interacted with enough other programmers, probably adopt a style that is 90%-95% like that of others.

I know programmers far better than I, who, while they have a very good style, do one or two little things that just make me absolutely crazy. But in the end they are little things, so I figure that's just their bit of artistic flair, and we all can indulge in some small amount of that.

No doubt quite a few newcomers here feel very puzzled when they're the object of a derisive response, because they don't have the first clue as to how they caused such a reaction. The compiler didn't complain (assuming their code compiles) so what could possibly be the problem. That's unfortunate, but it happens, I guess, because it's just the fast and easy way out. Truly there is some horrible looking code around the forum, but folks usually want to focus on more immediate issues than style, like fixing a problem and getting the code working.

PS: On the lighter side, there are a good number of people out there with a sense of humor about the whole business: http://www.ioccc.org/



Title: Re: Demonstration code for several things at the same time
Post by: beefy23 on Mar 28, 2014, 09:58 am
Hi Jack,

thanks very much for those pointers. I had a quick look at that contest you gave the link to and can't believe those code examples, complete gobbledegook to me. Great to see some humour in the matter.

After reading your post I went and played with autoformat and expected it to move my curly bracket positions all over the place but surprisingly it didn't. I then went and Googled the matter and came across a writeup on different methods of indentation. The differences seem legion, but like you say I'll probably start to see a general pattern used by most coders. I was relieved to see one method was along the lines of what I suggested Robin could use for teaching beginners and in fact in the writeup it said that method is one of the easiest for beginners to understand, although it does take up more line for the same amount of code. It also said it is very common for C.

Here's a part of that writeup (italics):

Allman / "East Coast" / Horstmann

Example: GNU-example in Allman style

Code: [Select]
int f(int x, int y, int z)
{
    if (x < foo(y, z))
    {
        haha = bar[4] + 5;
    }
    else
    {
        while (z)
        {
            haha += foo(z, z);
            z--;
        }
        return ++x + bar();
    }
}

This style is named after Eric Allman, who wrote a lot of utilities for the BSD family of operating systems, which also is a reason why this style is sometimes incorrectly referred to as the BSD style. Please note that this style might sometimes be called BSD style, but that this is wrong. For BSD itself, just as for UNIX and Linux, 1TBS is used. You can read about this in the man pages of the different BSD derivates e.g. for ?FreeBSD and ?OpenBSD.

This style is usually preferred by newbes to C-derived programming languages for being the easiest. Despite the fact that the inventors of C, UNIX and BSD use 1TBS, this style is very common for C.

The main disadvantage of this style is the waste of precious screen lines. Per block at least one additional line is needed compared to 1TBS. In C, C++ and similar languages with comparable preprocessors there is one single situation where this style shows an advantage over 1TBS.


I accept that is not the norm, but I am surprised by that too. It is so easy to read and I equate it to looking at the graphical representation of a computer folder system, where you can see a folder inside a folder inside a folder with great ease, but in this case it's functions. I'm guessing as I get more proficient at C then I'll see functions and nested functions easier without my preferred bracketing method. Right now though some of the code I've looked at is incredibly confusing to my beginner eyes. I see an opening curly bracket, then in the same line another opening one. My eyes continue scanning serially along the lines and oh my God another opening bracket. Somewhere each of these opening brackets have a closing bracket and a lot of my effort is spent identifying individual functions and the nested functions inside them. Welcome to the world of C I tell myself LOL.

As per your suggestion I'll keep an eye out for what seems to be the norm in coding style. Even if I don't use it personally, my sketches are fairly simple at present and I can change it to the general method if I post it on the forum.

Cheers,

Keith.
Title: Re: Demonstration code for several things at the same time
Post by: JChristensen on Mar 28, 2014, 01:34 pm
Ha, well that'll learn me, I had no idea the topic was so thoroughly documented with names for styles and so forth. I should have known :D


I was relieved to see one method was along the lines of what I suggested Robin could use for teaching beginners and in fact in the writeup it said that method is one of the easiest for beginners to understand, although it does take up more line for the same amount of code. It also said it is very common for C.


Yeah I couldn't complain too much about that one. At least some thought went into it. If the worst thing is that it wastes some space, but makes things easier for beginners to understand, then I can live with it.

Quote

I'm guessing as I get more proficient at C then I'll see functions and nested functions easier without my preferred bracketing method.


In C and C++, while blocks of code can be nested, functions cannot be nested inside other functions.

Quote

Right now though some of the code I've looked at is incredibly confusing to my beginner eyes. I see an opening curly bracket, then in the same line another opening one. My eyes continue scanning serially along the lines and oh my God another opening bracket. Somewhere each of these opening brackets have a closing bracket and a lot of my effort is spent identifying individual functions and the nested functions inside them. Welcome to the world of C I tell myself LOL.


Actually that sounds like really bad style. That's where I'd just hit the Autoformat button before even attempting to read it.
Title: Re: Demonstration code for several things at the same time
Post by: JChristensen on Mar 28, 2014, 01:45 pm
Keith, if you don't already have one, an editor that recognizes the language can really help by providing "ident guides" (the vertical lines) and the ability to collapse or expand blocks of code. The Arduino IDE can be rigged to work with an external editor via Preferences.
Title: Re: Demonstration code for several things at the same time
Post by: beefy23 on Mar 29, 2014, 12:25 am

In C and C++, while blocks of code can be nested, functions cannot be nested inside other functions.


Cheers Jack,

ha ha, there's the beginner in me coming out.

Code: [Select]
int f(int x, int y, int z)
{
   if (x < foo(y, z))
   {
       haha = bar[4] + 5;
   }
   else
   {
       while (z)
       {
           haha += foo(z, z);
           z--;
       }
       return ++x + bar();
   }
}


I'm obviously describing things very wrong, time to re-educate myself. In the above example for instance you've got "while(z)" inside "else". I've been calling both of those functions. I thought anything between and open & closing curly bracket was a function.

You are completely correct about just trying to get things working and not focussing on learning C properly. I'm impatient (and excited LOL) to get the end result. I've built a CNC plasma cutting table and this project I've been working on is to make my table do something the standard software cannot do. I've got so much on my plate I've just done what's necessary to get it working. I hadn't touched C before I got an Arduino for this project. Then in addition I've been learning PCB making using the UV exposure method, and Diptrace PCB design software (love it). So yeah, rush rush, cram into my head what I can as quick as I can, etc. This is the result of my very first Arduino project so I'm quite elated

https://www.youtube.com/watch?v=yg-s-EAqMfI

The Arduino is controlling the plasma cutter directly instead of the computer. I'm just working on the "Mark II" version now with some additions to the PCB hardware and improved features in the code. The ease of use the Arduino provides made it possible.

Thanks as well for that pointer about the external editor, good information.

Edit:
Ha ha, just looked at the two images you supplied, and it's Notepad++. I just downloaded and installed it two days ago, as well as another one called Programmers Notepad. I was Googling for a way to print my code in colour (make it easy for the beginner again). Wow so now I can link to it from the Arduino IDE, awesome. Time to look at Preferences.

Keith.
Title: Re: Demonstration code for several things at the same time
Post by: JChristensen on Mar 29, 2014, 01:28 am
Mighty impressive project there!

Curly braces enclose a block of one or more statements. The block of statements could be the body of a function. So in the example, the function is named "f" (very original) and the outermost pair of braces enclose the function body.

The function f() expects three integers as its input arguments and its return value is likewise an integer.

Within the function we have an if statement, which if the condition (x < foo(y, z)) is true, executes a block that consists of one statement, haha = bar[4] + 5;

If the condition is false, then the else block gets executed. Within the else block is a while statement that executes a block of two statements as long as the condition (z) is true.

Sounds worse than it is when it's written out like that. Don't analyze it too much because it's just an example and a lousy one. For one thing, the function only returns a value if the else branch is taken. That's at least bad form, and likely to cause a problem, because the caller would expect the function to return an integer regardless. Another function foo() is called in two places within f(), but we don't know what it does. So again just an example.
Title: Re: Demonstration code for several things at the same time
Post by: beefy23 on Mar 29, 2014, 02:06 am
Thanks Jack,

I'll have to sit down with that one a bit and let it sink in.

Got the external editor working. Now there's no more copying and pasting just so I can print in colour, and all the coding is done in  a much better editor. Thanks a million, that's helped a lot.

Keith.
Title: Re: Demonstration code for several things at the same time
Post by: mrburnette on Mar 29, 2014, 02:21 am
@Keith,

Welcome.  Many of our most experienced members believe in tough-love.  You do not have to like it, or dislike it but you should take away that they spend countless hours a week in these forums attempting to help answer questions; all non-paid and often thankless work.  Formatting before posting (as requested in the stickies at the top of the topics) is my and your easy of making their job a bit easier.  After all, we came in with the question/need.

I personally spend from 1 to 2 hours daily, often more if available.  It is hard work, often frustrating.  I don't like being rude, but I am certain I have been sometimes.  Unlike writing a project column (I do) there is no draft review before publishing, "Post" click and move on to the next needy person.  Very few members give back from experience, so as you acquire knowledge and experience, consider taking on a few newbie questions... It is a gratifying experience and you will grow from the research you do on their behalf.

Best Arduino wishes,

Ray
Title: Re: Demonstration code for several things at the same time
Post by: beefy23 on Mar 31, 2014, 08:44 am
Hi Ray,

reading what you say has only gave me further disappointment.

A comment such as "that's horrible" is not tough love. It does nothing to help / educate the person it's aimed at. Tough love applied in this situation should be helping someone, not just putting something down with no explanation why.  So far not one member has said Pete could have refrained from putting in a criticising & pointless comment, yet seems I'm getting a gentle talking to from more than one member because I reacted to that comment. I think that is completely screwed up.

I have been a member of a cnc forum for several years, and am at the stage where I help more than ask questions. I have never gave a comment like what I got here, because of the hard thankless work I put into answering newbies questions. I understand all too well the lack of thanks for answering questions and as you'll see from my posts, I try to make of point of expressing thanks when someone helps me. I've been pretty resentful on many occasions because of zero thanks or response when I've put time into a detailed answer, but that has never led me to make the type of comment that I reacted to on here. If someone is getting hot and bothered with all the hard work of being a charity to others, and they resort to pointless irritating comments then maybe they need to take a break from the forum, and ask why they are doing it in the first place.

And based on what has been said to me so far, why would I want to help others on this forum. The very first time I suggest something with the good intention of helping beginners read code easier (whether my suggestion is right or wrong, I was trying to help), I get a crap comment fired at me. I react to that comment then I'm the one getting the talking to (however gentle). The message I keep getting, put bluntly, is that on this forum, derisive comments are completely acceptable, and the person giving them has justification for giving those comments.

Don't count on me to give help if this is the risk I put myself at on this forum. It will not be a gratifying experience when I have to eat dirt because someone does not like what I said.

Keith.
Title: Re: Demonstration code for several things at the same time
Post by: GoForSmoke on Apr 03, 2014, 10:08 am


I also prefer a different bracketing style to yours, but that's neither here nor there.


Ah, but if you use "Auto Format", it arranges things in a certain way for you.



Not completely at all. If you put the open brace on its own line, it will stay on its own line easier to see and balance.
Title: Re: Demonstration code for several things at the same time
Post by: polymorph on Jun 04, 2014, 09:05 pm

Code: [Select]
...
    if (currentMillis - previousOnBoardLedMillis >= onBoardLedInterval) {
...
       previousOnBoardLedMillis = currentMillis;
    }


The average interval will be slightly to significantly more than onBoardLedInterval.  For most uses (like blinking an LED) the longer interval is insignificant.  For some uses the longer interval is a failure.

Code: [Select]
       previousOnBoardLedMillis += onBoardLedInterval;

...produces a bit more code but keeps the average interval at exactly onBoardLedInterval.


Oh, I get it, maybe. If you make previousOnBoardLedMillis equal to currentMillis, then errors due to the time it takes to step through the program are cumulative. But if you merely add onBoardLedInterval to previousOnBoardLedMillis, while each time around will have a little error in timing, it is not cumulative.

Is that right?
Title: Re: Demonstration code for several things at the same time
Post by: Robin2 on Jun 04, 2014, 09:12 pm

Is that right?


Very close.

The errors that creep in and could accumulate happen because currMillis = millis() may happen a tiny bit late. Remember that the test is if (currMillis - prevMillis >= interval) so it may be a little greater, but it will never be a little less.

...R
Title: Re: Demonstration code for several things at the same time
Post by: GoForSmoke on Jun 05, 2014, 12:20 am
When you read millis() into currMillis, you set a time point.

The math (currMillis - prevMillis >= interval) evaluates the time point as TRUE or FALSE

When that is TRUE, you can eliminate slippage to less than 1 ms.
First, calculate millis past interval it took to run the check.
lateMillis = (currMillis - prevMillis) - interval; // partly to keep the compiler from rearranging terms
Then set your start time to the time point plus the overage at the time point.
prevMillis = curMillis + lateMillis
Slippage will be less than 1 ms, unless you time micros.

Title: Re: Demonstration code for several things at the same time
Post by: Robin2 on Jun 05, 2014, 08:07 am

Slippage will be less than 1 ms, unless you time micros.


prevMillis += interval    has NO slippage and is much simpler.

...R
Title: Re: Demonstration code for several things at the same time
Post by: GoForSmoke on Jun 05, 2014, 01:37 pm
Oh. Right.
Tired lately. Crash after caffeine burnout.
Title: Re: Demonstration code for several things at the same time
Post by: Paul Beaudet on Jun 13, 2014, 08:15 pm
First of all, I commend Robbin's effort of showing newbies how to manage time.

Going to point out something a little less technical  though. Sometimes people need to step in poo before really understanding it smells. Even after countless people have told them how much it smells. In the figurative sense my feet have a lot of lingering smell, probably the worst offender of this.

Tried to show a bunch of kids how to set robot motors without delays. Even basically built the functions for them. Long story short, gave up and told them to use delays. After that, they started making progress as opposed to being confused. The quality of my explanation mattered very little.

A smart person knows when they are right. A wise person knows when being right matters.
Title: Re: Demonstration code for several things at the same time
Post by: Robin2 on Jun 13, 2014, 08:52 pm
@Paul Beaudet,  I completely understand what you are saying.

And I am a great believer in learning by doing - the theory often makes complete sense later.

From reading a lot of stuff here it is obvious that some people grasp concepts quickly and others never do. It is always difficult to know where to pitch advice when you don't get the instant feedback that you get in a face-to-face situation.

One of the difficulties about the delay() vs BWoD choice is that it can be very difficult to convert a complex piece of code from using delay()s to using BWoD. For that reason I am inclined to encourage the early use of BWoD even when, technically, it doesn't make a lot of difference.

Conversion is not helped by the understandable "decision" by many newbies to bundle all their code into loop(). I put the word decision in quotes, because, of course it is an absence of a decision to be more organized - usually for want of experience.

Another complication is that you never know how long a newbie is going to stick with Arduino - if s/he is going to lose interest after the first project almost all teaching will be a waste of time. I think the only practical approach is to treat everyone as a long term prospect.

Following from that, my perception is that it is not helpful to propose (as opposed to assist with) second rate solutions.

And, of course, the reader is always free to reject the advice. I hope that people who use my example do so because they themselves think it is appropriate.

Thanks for your comments.

...R
Title: Re: Demonstration code for several things at the same time
Post by: polymorph on Jun 13, 2014, 09:16 pm
Quote
One of the difficulties about the delay() vs BWoD choice is that it can be very difficult to convert a complex piece of code from using delay()s to using BWoD. For that reason I am inclined to encourage the early use of BWoD even when, technically, it doesn't make a lot of difference.


Yes! Agree 100%!
Title: Re: Demonstration code for several things at the same time
Post by: GoForSmoke on Jun 13, 2014, 09:28 pm
The more time and money invested in a mistake, the harder it is to walk away.

Never time to do it right, always time to do it over.
Title: Re: Demonstration code for several things at the same time
Post by: polymorph on Jun 13, 2014, 09:58 pm
Yeah... a friend of mine has the unenviable job of cleaning up sloppy quick-fixes in other people's programming.

And this is why I'm on kind of a tear, criticizing the over-use of delay() to time things. It really annoys me how just about every book, class, website, and video that purports to be for beginners to Arduino, use delay() for everything.
Title: Re: Demonstration code for several things at the same time
Post by: JimboZA on Jun 15, 2014, 09:02 am
At last I got round to looking at this thread, although I've seen Robin2 link to it numerous times.

The esoteric discussion on latency and slippage aside- most if not all of which went splat on the wall behind me- it's an excellent piece of work and a good look at the whole bwod thing. Well done and karma to you Robin2.

I'm going to use this approach in some stuff I intend to do today- probably get really advanced and have different durations on the LEDs  8), and include some other stuff I'm fiddling with.

[whisper]It's such a pity that this thread went off the rails a number of times but that's life I guess.[/whisper]
Title: Re: Demonstration code for several things at the same time
Post by: spruce_m00se on Jun 23, 2014, 01:09 pm
Well, i just stumbled across this example after starting this thread:
http://forum.arduino.cc/index.php?topic=248643.0

I had already written a higgledy piggledy code that more or less did what I want it to do, but some things are just seemingly messed up by timing during other events using delay()

I had already taken each part of the code into individual functions as in your example before reading it and was looking into how to use millis in various functions at the same time,

this was very useful having stepped in the previously mentioned poo and looking for a way to clean my foot,

Thanks,
Title: Re: Demonstration code for several things at the same time
Post by: polymorph on Jun 23, 2014, 08:27 pm
And if you need finer grained timing, there is also micros(). Although it counts in microseconds, you should know that the granularity is 4us.
Title: Re: Demonstration code for several things at the same time
Post by: GoForSmoke on Jun 23, 2014, 11:50 pm
Months ago I saw this thread but since the principle is the same as what Nick Gammon covers very will in his blog (that explains blocking code and other basic concepts in a slow-pitch way), I just linked people to that.

If you haven't seen, this is Nock's (edit, errr Nick's) tutorial:
http://www.gammon.com.au/forum/?id=11411
Note to self: start using the new keyboard that doesn't have half the letters rubbed off.

Not long ago I got back and learned one very good lesson from Robin2 (karma to you, Robin) of not updating start time to millis() in a time check that may be late but rather adding the interval to the start which is ALWAYS right.

So this time I actually looked the code over and I see something that I have done very often before, especially when under the gun, but that does not make it good practice at all. In fact, even as beginners we are reminded to not do this thing.
And what is that?
Copy&paste then modify to suit code multiplication. Because it works and what works is good, right? Wrong.

Do I want to add a block of code for every led I add? No. That's why there's arrays, etc.

I had a pretty good day today, healthwise, so I dug out the breadboard, parts boxes and magnifier to do something.

Here is Blink Multiple Leds Without Delay in 2 versions.  
1st is the short version that I count as 24 lines of actual code (not counting braces).
2nd is a longer teaching version with loads of comments and serial report options. 1st is the short version that I count as 24 lines of actual code (not counting braces).

Mess with it. Ask questions. I had all that addressed then the forum timed me out and poof, all that is gone!
Add leds. If you want more than 8 then change ledState to unsigned int or long.

Short version:
Code: [Select]

//  Blink Multiple leds With Uneven Delays, Short Version

const byte    LEDS = 4;
const byte    ledPin[ LEDS ] = // I use Autoformat. It won't let this be 1 line.
{
 13, 3, 5, 7
};

byte          ledState = 0; // this will handle 8 led states as bits
byte          led = 0; // this example processes 1 led per pass through loop()

unsigned int  millisNow; // fill with the lower 16 bits of millis()
unsigned int  startBlink[ LEDS ]; // these all default to zero
unsigned int  waitBlink[ LEDS ][ 2 ]; // one for OFF time, one for ON time

void setup()
{
 for ( led = 0; led < LEDS; led++ )
 {
   waitBlink[ led ][ 0 ] = 250U * ((unsigned int) led + 1U ); // OFF millis
   waitBlink[ led ][ 1 ] = 10U * ((unsigned int) led + 1U ); // ON millis

   pinMode( ledPin[ led ], OUTPUT ); // default output is LOW
   digitalWrite( ledPin[ led ], bitRead( ledState, led ));
 }  

 led = 0;
}

void loop()
{
 millisNow = (unsigned int)( millis() & 0xFFFF ); // lower 16 bits roll over just fine

 if ( millisNow - startBlink[ led ] >= waitBlink[ led ][ bitRead( ledState, led ) ] )  
 {
   startBlink[ led ] += waitBlink[ led ][ bitRead( ledState, led ) ]; // update start time

   bitWrite( ledState, led, ( bitRead( ledState, led ) == 0 )); // change led state bit
   digitalWrite( ledPin[ led ], bitRead( ledState, led ) ); // change the led pin  
 }

 led++;
 if ( led >= LEDS )
 {
   led = 0;
 }
}


Long 'learning' version with serial reporting options.
Code: [Select]

//  Blink Multiple leds With Uneven Delays, Serial reporting optional

/*
The hardest part of this was getting the debug/report prints to not screw the timing
by more than 1 milli. I even left in some commented-out lines just for comparison.
Serial is not free, it blocks execution!
*/

// make SERPRINT 1 to enable serial preorti
#define  SERPRINT  1

// #if SERPRINT ---- if I leave this in, the sketch won't compile
byte runBeforeStop = 199; // to limit serial print lines set this to < 200
//#endif

const byte    LEDS = 4;
const byte    ledPin[ LEDS ] = // I use Autoformat. It won't let this be 1 line.
{
 13, 3, 5, 7
};

byte          ledState = 0; // this will handle 8 led states as bits
//            to track more than 8 leds, use larger unsigned integers than byte
byte          led = 0; // this example processes 1 led per pass through loop()

unsigned int  millisNow; // fill with the lower 16 bits of millis()
unsigned int  startBlink[ LEDS ]; // these all default to zero
unsigned int  waitBlink[ LEDS ][ 2 ]; // one for OFF time, one for ON time
//               using the low 16 bits of millis allows 65.535 second blink
//               however if you need longer, change these to unsigned long
//          you can initialize this array as const or use PROGMEM to store it
//          I chose to use a formula. With a different formula I could get rid
//          of the whole array and use one or more variables to run the formula.

// This is code. Make your own way all you *can*! More you do, better you get.
// And note, this mess just begs to be turned into a Class Objects example.

void setup()
{
#if SERPRINT
 Serial.flush();
 Serial.begin( 9600 );
 Serial.println( "\nMulti-led blink test\n" );
#endif

 for ( led = 0; led < LEDS; led++ )
 {
#if SERPRINT
   Serial.print( " Led " );
   Serial.print( led, DEC );
   Serial.print( " >> " );
#endif

   // setting the blink delays by formula here
   // YES for this the array is not needed, the code below could use the formula
   // however this example can also use a pre-compiled array
   // and if User I/O or other dynamic change method is added, the array may serve that
   // But Please, change it all to suit your ideas as they occur!

   waitBlink[ led ][ 0 ] = 250U * ((unsigned int) led + 1U ); // OFF millis
   waitBlink[ led ][ 1 ] = 10U * ((unsigned int) led + 1U ); // ON millis

#if SERPRINT
   Serial.print( " OFF millis = " );
   Serial.print( waitBlink[ led ][ 0 ] );
   Serial.print( " ON millis = " );
   Serial.println( waitBlink[ led ][ 1 ] );
#endif

   pinMode( ledPin[ led ], OUTPUT ); // default output is LOW
   digitalWrite( ledPin[ led ], bitRead( ledState, led ));
 }  
#if SERPRINT
 Serial.println( );
 
 Serial.println( "Led <led> t <millisNow> x <pin state> n <next change>" );
#endif

 led = 0;
}

void loop()
{

 millisNow = (unsigned int)( millis() & 0xFFFF ); // lower 16 bits roll over just fine

 if ( millisNow - startBlink[ led ] >= waitBlink[ led ][ bitRead( ledState, led ) ] )  
 {
#if SERPRINT
   Serial.print( led, DEC );
   Serial.print( " t " );
   Serial.print( millisNow );
/*
   Serial.print( " states " );
   Serial.print( ledState, BIN );
*/
#endif

   startBlink[ led ] += waitBlink[ led ][ bitRead( ledState, led ) ]; // update start time
   // Thank You Robin2, this really does take care of late updates

   bitWrite( ledState, led, ( bitRead( ledState, led ) == 0 )); // change led state bit
   digitalWrite( ledPin[ led ], bitRead( ledState, led ) ); // change the led pin  

#if SERPRINT
/*  put these in and see what it does occasionally to timing. then add more serial
   Serial.print( " change " );
   Serial.print( ledState, BIN );
   Serial.print( " start " );
   Serial.print( startBlink[ led ] );
   Serial.print( " wait " );
   Serial.print( waitBlink[ led ][ bitRead( ledState, led ) ] );
*/
   Serial.print( " x " );
   Serial.print( bitRead( ledState, led ) );
   Serial.print( " n " );
   Serial.print( startBlink[ led ] + waitBlink[ led ][ bitRead( ledState, led ) ] );
   Serial.println();
   
   if ( runBeforeStop < 200 )
   {
     if ( !runBeforeStop-- )
     {
       while( 1 );
     }
   }
#endif

 }

 led++;
 if ( led >= LEDS )
 {
   led = 0;
 }
}

Title: Re: Demonstration code for several things at the same time
Post by: Coding Badly on Jun 23, 2014, 11:55 pm
If you haven't seen, this is Nock's tutorial:
http://www.gammon.com.au/forum/?id=11411


In case you don't want to / can't remember a five digit number...
http://gammon.com.au/blink
Title: Re: Demonstration code for several things at the same time
Post by: Robin2 on Sep 20, 2014, 04:31 pm

Since this is a sticky it's worth to post this method here as well:


Added 02 Oct 2014 --- @casemod seems to have moved his posts out of this Thread (as was suggested in the next Post) hence this and some of the following posts are in a bit of a vacuum.

Most of the posts in this Thread are about the cumulative error associated with
Code: [Select]
previousmillis = currentmillis;
and how it is better to use
Code: [Select]
previousmillis += time;
or (in your second method)
Code: [Select]
since += time

Please don't confuse newcomers by recommending the deprecated approach in this Thread.

It would probably also be very useful for newcomers if you would modify your Post and add an explanation about how &since works. Most of them will find that concept very confusing without a clear explanation.

...R
Title: Re: Demonstration code for several things at the same time
Post by: Robin2 on Sep 20, 2014, 07:46 pm

I changed that bit and added a brief description

I posted the code with the intent of helping those trying to "multitask" or do things at the same time, not exactly the issue you mentioned, however if it is not suitable let me know so I can remove it or make further corrections


Thanks.

You don't seem to have changed the line with since = currentmillis.

And I can't see your explanation of the way &since works

Your concept might be better placed in its own Thread titled "A non-blocking alternative to delay()". If you move your code you could keep a link to the other Thread here.

...R
Title: Re: Demonstration code for several things at the same time
Post by: GoForSmoke on Sep 24, 2014, 08:49 am



You don't seem to have changed the line with since = currentmillis.


I changed this line

Code: [Select]
if (currentmillis - previousmillis >= time) {
    previousmillis = currentmillis


with
Code: [Select]
if (currentmillis - previousmillis >= time) {
    previousmillis += time;



If you're using the blinking led as a status light then the first way will let accumulated "late errors" actually show.
What code is "right" is a matter of what your output is for. As an indicator, self-correction is not the best goal.
Title: Re: Demonstration code for several things at the same time
Post by: Robin2 on Sep 24, 2014, 08:56 am

If you're using the blinking led as a status light then the first way will let accumulated "late errors" actually show.
What code is "right" is a matter of what your output is for. As an indicator, self-correction is not the best goal.


Please don't reopen this discussion. It has all been extensively covered in earlier posts and the demo in the first Post in the Thread has taken all the discussion into account. My only concern is that @Casemod's contribution might confuse newcomers. He has said he will move it to another Thread.

...R
Title: Re: Demonstration code for several things at the same time
Post by: nickgammon on Sep 24, 2014, 10:03 am

If you haven't seen, this is Nock's tutorial:
http://www.gammon.com.au/forum/?id=11411



Nick's tutorial. :P

My examples there actually do have the creep which is mentioned earlier. Putting aside coding issues, this creep is based on the fact that you reset the timer when the event is noticed, not a fixed interval from when it should have been noticed.

In the case of flashing an LED, this isn't an issue.

Let me give you an example in real-life terms. Say you get a credit card statement in the mail, and you have 30 days to pay. The 30 days is from when the statement was sent, not from when you receive it (which might be a few days later). The creep is in the delivery time (or maybe in the time it takes you to notice the mail).

To have the statements come every 30 days, the sender simply adds 30 days to when they sent the last one. To have the creep, they would add 30 days to when you received the mail.
Title: Re: Demonstration code for several things at the same time
Post by: GoForSmoke on Sep 24, 2014, 10:24 am
Sorry about that Mr. Gammon, Sir! One quoted mistype that's never going to die, is it? IIRC, I did fix the original.

In the bills case it is desired to keep the billing cycle regular.  Apps should fit needs. Been there, wrote the packages.

I want a status light to tell me more about the running of the software, not less. I've got one now that doesn't so much creep as leap whenever the GSM element runs. It's for someone else and free work so I'm not going to fix that library but wow does it need unblocking!

I thank you again for your great tutorials that put words to what I never put words to. My right-brain thinking ways don't do that and I end up with poor explanations for thoughts that are more like working pictures. What can I say? Literally! It's been great to be able to link people to your full, coherent explanations instead of my poor attempts.

Title: Re: Demonstration code for several things at the same time
Post by: larryd on Sep 25, 2014, 02:25 am
Robin2
I am sure people new to programming will find your work very beneficial.
One comment, if a newcomer reads through the whole thread I think they may a bit confused with all the discussions.
IMHO it would be best to chop everything after your example which incorporates the the discussed creep code modification.
Thanks for your time on this.
Thanks to the software guys for there explanations also.

Title: Re: Demonstration code for several things at the same time
Post by: Robin2 on Sep 25, 2014, 10:17 am

One comment, if a newcomer reads through the whole thread I think they may a bit confused with all the discussions.


I have been wondering about this as well, but I am concerned that I may be too close to the subject to take an objective view.

I have added a note for newcomers at the top of the first Post.

...R
Title: Re: Demonstration code for several things at the same time
Post by: GoForSmoke on Sep 25, 2014, 01:14 pm
I just wish that you had explained the central problem of blocking code explicitly.
That is why I still link to Nick's blog. He does a good job of doing that.



Title: Re: Demonstration code for several things at the same time
Post by: Robin2 on Sep 25, 2014, 10:42 pm

I just wish that you had explained the central problem of blocking code explicitly.
That is why I still link to Nick's blog. He does a good job of doing that.


As I say in the opening post (the only one that really matters for a newcomer) I just set out to give an extended example of the BWoD concept. I was not trying to monopolize the subject.

I like Nick's stuff - I have bookmarked several items.

But I also think it is a good idea to be able to direct people to material within the Arduino website.

It is always difficult to know how to pitch a teaching item. Some people like to read the theory. Others just want to get stuck in.

...R
Title: Re: Demonstration code for several things at the same time
Post by: GoForSmoke on Sep 26, 2014, 01:47 am
I agree with your goals very much.

But to some of this I liken it to teaching the 2 + 2 = 4 and 3 + 3 = 6 without teaching what 2 and 3 are. I want beginners to be able to say 2 + 3 = 5 without having to memorize it, look it up or get a library to do it for them.

If you don't have your fundamentals down then you make fundamental mistakes. Bits, bytes and logic are the ABC's, 123's and +-x/ operators of computing. Arrays are the spelling words and structure is grammar. Everyone with a solid grounding in those will be able to make easier sense of the rest. The how and why is more important than the what and that gets demonstrated every day here which is why I try to hand out fundamentals where I find a lack.
Title: Re: Demonstration code for several things at the same time
Post by: Robin2 on Sep 26, 2014, 09:37 am

But to some of this I liken it to teaching the 2 + 2 = 4 and 3 + 3 = 6 without teaching what 2 and 3 are.


I see that.

I guess I started from the assumption that the reason WHY would have been explained in whatever Reply told the OP not to use delay() and to look at this as an example of how to get by without it.

It seems to me that the newcomers have no difficulty understanding that delay() gets in the the way of concurrency - but they don't immediately grasp how to use millis() to replace it.

If you can suggest 2 or 3 lines (not more!) for insertion into my original post I will certainly consider it.

...R
Title: Re: Demonstration code for several things at the same time
Post by: robtillaart on Dec 20, 2014, 12:52 pm

Why is the usage of break an argument against switch()? That is the same as saying the use of else is an argument against if... It are code constructs to make an algorithm easier to maintain and give the compiler means to optimize the code.


For a switch statement there are at least 2 ways to compile to machine code while an if then else ladder (expressed functionally equivalent) cannot. One reason is that for a switch statement the compiler knows immediately that there is one element in an "is equal" compare, which is every time the same (e.g. optimize in a register). For an if then else ladder every comparison is a new one for the parse tree, which might be optimized later. In switch statements every case must be disjunct, semantics forces that. In an if then else ladder you can do the same comparison multiple times.

A switch statements allows a fall through which can be used for simple OR or for reducing double code. An if then else ladder has no (straightforward) equivalent for that.

For me the only drawback of the switch statement is that it does only support simple integer types and not complex or aggregate like strings and structs. BUt that is by design so I can (have to) live with that.