Go Down

Topic: Is there a project to improve/replace the official examples? (Read 4452 times) previous topic - next topic

GoForSmoke

I know they work but in many cases they are teaching new people bad habits that come back in Help! Help! threads. The whole communication set is rife with C++ String use. Blink Without Delay has longs mixed with unsigned longs for time work. Throughout, ints are used where bytes or shorts will do.

These are 8 bit machines with very limited RAM. Awareness of that from the start will result in fewer problems and the examples are not helping.

Nick Gammon on multitasking Arduinos:
1) http://gammon.com.au/blink
2) http://gammon.com.au/serial
3) http://gammon.com.au/interrupts

pYro_65

I agree, the Arduino folks should let a few of us tinker with the reference/example pages. The bloated bottomless pit of a playground is not the best place for reference material ( that you want people to find ), having  access to the official areas would be nice.

Like you say, many threads and headaches can be avoided with up to date / accurate information.

GoForSmoke

My next step was to try and address organizing examples and knowledge as it has piled up and is frustrating trying to find solutions. We need a library card catalog equivalent or better.

But first, the examples. I made some changes to BlinkWithoutDelay since I send so many new people to that. BTW, there's 12 actual lines of code in this one.

Code: [Select]

/* Blink without Delay -- with minor fixes by GFS

  Turns on and off a light emitting diode(LED) connected to a digital 
pin, without using the delay() function.  This means that other code
can run at the same time without being interrupted by the LED code.

The circuit:
* LED attached from pin 13 to ground.
* Note: on most Arduinos, there is already an LED on the board
that's attached to pin 13, so no hardware is needed for this example.


created 2005
by David A. Mellis
modified 8 Feb 2010
by Paul Stoffregen

This example code is in the public domain.

http://www.arduino.cc/en/Tutorial/BlinkWithoutDelay

GFS fixes and modifications -- May 5 2013:
. changed time variables to be ALL unsigned longs, as they should be.
. added UL to numbers being assigned to unsigned longs as should be.
. changed the variable name 'interval' to 'blinkTime' as interval is now a
word used by the IDE, it shows up red (like the word 'if') instead of black.
. changed the if-else logic to change the ledState variable to 1 line XOR logic.
. added comments about adding more tasks to the sketch.

*/

// constants won't change. Used here to
// set pin numbers:
const byte ledPin =  13;      // the number of the LED pin

// Variables will change:
byte ledState = LOW;             // ledState used to set the LED

unsigned long previousMillis = 0UL;  // will store last time LED was updated

unsigned long blinkTime = 1000UL;  // interval at which to blink (milliseconds)

void setup()
{
  // set the digital pin as output:
  pinMode(ledPin, OUTPUT);     
}

void loop()
{
  unsigned long currentMillis = millis();

  // here is where you'd put code that needs to be running all the time.
 
  // GFS adds -- you see the if() { } block below? You can add more blocks
  // whether if() or switch-case or whatever to do other tasks and as long
  // as they run quick without delays or prolonged loops, your sketch will
  // be responsive as if everything runs at the same time.
  // just as the blink runs on time, another task can run when a button or
  // sensor or serial data comes in or changes.
  // simple commands run in less than a millionth of a second so you can pack
  // a good bit of process into a block and still run quick. analog read takes
  // longer, about 9 per millisecond so it's best not to do a bunch of those
  // in a row but instead 1 analog read per time through loop() so other tasks
  // can get a chance in between analog reads.
  // it's also good to avoid using floating-point as that is slooowww and avoid
  // using C++ Strings as they mess with your RAM and suck up CPU cycles doing it.

  // Back to the original program:
  // check to see if it's time to blink the LED; that is, if the
  // difference between the current time and last time you blinked
  // the LED is bigger than the interval at which you want to
  // blink the LED.
  if(currentMillis - previousMillis >= blinkTime) // is it time to change the led?
  {
    // save the last time you blinked the LED
    previousMillis = currentMillis;   

    // if the LED is off turn it on and vice-versa:
    ledState = ledState ^ 1; // ^ is logical XOR, true if the values are different
    // using logic operations can save a lot of tedious, pain to debug if's

    // set the LED with the ledState of the variable:
    digitalWrite(ledPin, ledState);
  }
}
Nick Gammon on multitasking Arduinos:
1) http://gammon.com.au/blink
2) http://gammon.com.au/serial
3) http://gammon.com.au/interrupts

KirAsh4

While I certainly appreciate the XOR logic, a lot of beginners won't know what that is, where the standard if() block is easier to understand and read.  This is one case where I would stick with the if() block in the example, but add a comment that then mentions the one-line XOR logic.

Sergegsx

I would like to thank you GoForSmoke for that example, I have actually learned quite a bit even from such a short sketch.
I am in the process of trying to start learning how to "optimize" my code. i have big projects but I feel they could be improved by things you mention in your example.

So for example to invert a led I was doing
Code: [Select]

digitalWrite(StatusLED_System, !digitalRead(StatusLED_System));

instead of
Code: [Select]
// if the LED is off turn it on and vice-versa:
   ledState = ledState ^ 1; // ^ is logical XOR, true if the values are different
   // using logic operations can save a lot of tedious, pain to debug if's

I dont know the actual benefits but the second options sounds like more efficient, dont know why.

I would like to ask you the reason for this changes, the actual improvement it makes, please if you can, give me a hand understanding it.
Quote
changed time variables to be ALL unsigned longs, as they should be.

what are the benefits of defining it as "unsigned" as oppose to just long?

Quote
added UL to numbers being assigned to unsigned longs as should be.

I have never added the "UL", where should it be added? why?

I have used google but im not hitting the right buttons I guess.

Thanks for your help, hope more examples are "optimised" as you just did with this one.

AWOL

Code: [Select]
// ^ is logical XOR,
sp. "^ is bitwise XOR, and potentially unsuitable for use here"
"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

Sergegsx

#6
May 17, 2013, 07:19 pm Last Edit: May 17, 2013, 07:45 pm by Sergegsx Reason: 1

Code: [Select]
// ^ is logical XOR,
sp. "^ is bitwise XOR, and potentially unsuitable for use here"


interesting. So its not correctly use? it does work. could you explain AWOL so we all learn from it? thanks

would it be then like this?
Code: [Select]
ledState = ~ledState;

AWOL

The C convention (and this is apparent in the source of digitalWrite ) is that zero is false, and any non-zero value is true.
So, 2 is true, as is 1, but whereas 1 ^ 1 is zero (false) and 0 ^ 1 is one (true), 2 ^ 1 is still true.
Better to use the logical NOT operation "!".
"Pete, it's a fool looks for logic in the chambers of the human heart." Ulysses Everett McGill.
Do not send technical questions via personal messaging - they will be ignored.

GoForSmoke

Sorry about mixing up the terminology. I can't claim to be new to this either, LOL.

Potentially unsuitable... okay yes but in this case we only deal with bit zero.
The potential wrong is in how the bit(s) is/are used or checked. If other bits are used then the if() or while() or other way to check just one can include a mask of the others or use the bitRead() function to just get the one wanted.

I have no problem keeping many states as bits in unsigned variables and using bitwise logic to manipulate them en masse because I do keep track of which bits are used and how. Back in the late 80's I experimented with using Amiga graphics chip blit operations to work with whole arrays of bytes but nothing I did for work needed that.

Nick Gammon on multitasking Arduinos:
1) http://gammon.com.au/blink
2) http://gammon.com.au/serial
3) http://gammon.com.au/interrupts

Jantje

My vote would go for the ! operator. This is much easier to understand and the cpu overhead is minimal.
I mean I have a average loop time of 2miliseconds for a robot with 6 engines, 2 bumper switches, 4 analog reads, gps, remote control and serial communication. For your information: I use plenty of if ... else constructions for readability.

Personally I find this info below a bit over the top for a blink without delay example
Quote
analog read takes
  // longer, about 9 per millisecond so it's best not to do a bunch of those
  // in a row but instead 1 analog read per time through loop() so other tasks
  // can get a chance in between analog reads.
  // it's also good to avoid using floating-point as that is slooowww and avoid
  // using C++ Strings as they mess with your RAM and suck up CPU cycles doing it.

Maybe it is better to add some code that logs "how long -on average, min and max- the other work took". For help on the forum this logging could be really helpful.

Further on I find the example very good.
Best regards
Jantje
Do not PM me a question unless you are prepared to pay for consultancy.
Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -

GoForSmoke

I like to keep loop() short and not do everything every time as a matter of course. Some things get priority, especially ones that only happen on time or sensor input or interrupt flag with the ones that check quickest preferred happening sooner. I use state machines to control what part(s) run on any execution of loop(). It's not like loop() won't run again and the critical checks be made first sooner. I may run multiple sub-tasks in one pass through loop() but anything that takes as long as an analog read gets a return to start loop() again.

For me it's about response and having my time-checks close. I do use micros() instead of millis() for fine work. A lot can be done in 1000 micros().

Nick Gammon on multitasking Arduinos:
1) http://gammon.com.au/blink
2) http://gammon.com.au/serial
3) http://gammon.com.au/interrupts

Sergegsx

very interesting how all this is coming.
I also measured my loop timing in my projects, however there is one situation I think has no way of improving the timing. Every 10 seconds I upload information to a server on the internet, so I call this...
Code: [Select]
// Make a HTTP request:
        Serial.print("Connecting...");
        if (client.connect(server, 80)) {//if (client.connect())
          Serial.print("connected!");
                    client.println(str);
                    client.println();
                    client.println();
                    client.stop();


It takes around 1300ms to finish, have not found a way to improve it, if any of you know how to.
Also when reading DS18B20 you need to do some delays, that also adds nearly a seconds (I only read them every 5 minutos)

GoForSmoke

First find the part that is blocking execution.

My guess is it's client.connect(server, 80). Perhaps that library has alternatives to waiting.
Nick Gammon on multitasking Arduinos:
1) http://gammon.com.au/blink
2) http://gammon.com.au/serial
3) http://gammon.com.au/interrupts

Jantje


very interesting how all this is coming.
I also measured my loop timing in my projects, however there is one situation I think has no way of improving the timing. Every 10 seconds I upload information to a server on the internet, so I call this...
Code: [Select]
// Make a HTTP request:
        Serial.print("Connecting...");
        if (client.connect(server, 80)) {//if (client.connect())
          Serial.print("connected!");
                    client.println(str);
                    client.println();
                    client.println();
                    client.stop();


It takes around 1300ms to finish, have not found a way to improve it, if any of you know how to.
Also when reading DS18B20 you need to do some delays, that also adds nearly a seconds (I only read them every 5 minutos)

I solved this issue by offloading the ethernet stuff to a external party. This could be a pi but I choose a hacked wifi router. This way I can use Serial.print() commands and the ash script on the router knows what to do with it.
It is faster, cheaper, more modular and allows me to do lots of extras like remote upload of a sketch. I love it when my robot is in the back of  the garden in the rain and I uploaded a new sketch from the comfort of my sofa enjoying the heat of a good fire. ]:D

I still have the problem with SD logging. SD cards need to reorganize from time to time and that can take up to 140 ms. For debugging I can log all data in every loop. But for real running I simply disable logging.


... but anything that takes as long as an analog read gets a return to start loop() again.

Can you explain what you mean by this? Have you split the analog read in 2 actions?


For me it's about response and having my time-checks close. I do use micros() instead of millis() for fine work. A lot can be done in 1000 micros().

I agree lots can be done in 1000micros, but IMHO for most applications millis() is more than enough. I mean if a project has 5 (software) components each taking 2 millis() for a loop that is 10 millis() for the total project loop. That is still 100 times a second. In my experience that is more than enough for the average project and for most expert projects.

best regards
jantje
Do not PM me a question unless you are prepared to pay for consultancy.
Nederlandse sectie - http://arduino.cc/forum/index.php/board,77.0.html -

Sergegsx

Jantje, its a good idea what you propose, and I have several of those TPLink 703, actually I use one of them to convert Wifi to Ethernet for this same project, so I dont have to deal with wifi shields.
however, I wanted to keep all the programing and hacking on the arduino, so that when reproducing this project I dont need to depend also on the hacked router. Also this way I can use a network cable, with my project, or a router in bridge mode, and the sketch does not need to be changed.
however, thanks for the suggestion.

I believe there is a timeout on the upload execution, the disadvantage of this is that you start loosing uploads if things take a little bit longer than expected.

Go Up