Processing efficiency and relation with programming techniques

Hello all,

I am quite new both with programming C++ and Arduino. I have a question regarding processing efficiency and relations with programming techniques. For the codes that I wrote, the processing efficiency was not an issue. But my next proyect will require more careful decisions and I want to make sure I understand the logic, I cannot find any clear directions on this.

Does it make any difference the way of programming the following basic things in terms of processor efficiency after compiling , or is only a matter of readibility on the code before compiling ?

Maybe to formulate this first question without examples, I would ask ... do we really need to use variables even if they never change their value in our program flow, and assign the value of digitalRead to a variable instead of using it directly in a logic statement ? ... I ask because I believe to see this done quite often when reading sketches online.

Example A (the way I see most used)

#define pinIn A0 
int pinRead ;
int var = 1023 ;

void setup() {
  pinMode (pinIn, INPUT) ;
}

void loop() {
  pinRead = analogRead (pinIn) ;
  if ( pinRead == var) { // do whatever
  }
}

Example B

#define pinIn A0

void setup() {
  pinMode (pinIn, INPUT) ;
}

void loop() {
  if ( analogRead (pinIn) == 1023) { // do whatever
  }
}

Now the second doubt ... same doubt BUT with functions. Does it really make sense to make a very short (one two or three lines) function and call it just a few times in a sketch, instead of typing directly the instructions when needed ? I am not talking about a function that is going to be called 20 times, so it is not about typing economy and sketch simplicity ... sometimes I see sketches with 20 functions and each function is called only once or twice, where it would be simpler to just put the instructions directly where the functions are called.

As an example, here goes example C (replacing what is done directly in the loop with a function)

#define pinIn A0
int pinRead ;
int var = 1023 ;

void myFunct() {
  // do whatever
}

void setup() {
  pinMode (pinIn, INPUT) ;
}

void loop() {
  pinRead = analogRead (pinIn) ;
  if ( pinRead == var) { 
    myFunct();
  }
}

All additional input and directioning will be appreciated. Thanks a lot !!

in your first case, the compiler may optimize out setting the variable if its value is never used elsewhere. i feel the use of the variable is unnecessary.

very long functions make code harder to follow. breaking a long function into a few smaller functions is usually better. having a function the is used multiple time is definitely good. but as you suggest, many small functions may be more difficult to follow.

if a function is small and used multiple times, the inline keyword avoids creating a separate function which may have some performance or readability benefits

About your first question...

If you are going to use the value read in from pinIn in more than one place, then read it into a variable once and use that variable each time you need the analogue value. Using analogRead() each time wastes CPU cycles and may lead to nasty bugs if you accidentally assume the value will be the same each time (which it would be if you used a variable).

One thing about your example B: don't put "magic numbers" into the code like you did with 1023. It makes the code harder to read (the reader needs to know that the processor has a 10-bit ADC before it makes sense). It also makes it harder to port to another platform with a different ADC. Use a const at the top of the code instead (or even a #define ANALOG_MAX 1023), neither of which takes up a memory location.

Generally, when programming, the most important thing is to make the code comprehensible to humans. For Arduino, things are slightly different because programs tend to be very short and there aren't likely to be more than one or two people working on a project.

Nevertheless, good software engineering practices can make your life easier in Arduino world. Classes, long variable names, splitting code out into well named functions, even if you only call them once, can help with comprehension. The benefits will be appreciated when you come back to your code after six months.

Processing efficiency is usually less important and if it actually is, it's likely that there will only be little hot spots in the code that need to be fast. Optimize what you have to, when you must. Otherwise, write it as plainly and clearly as you possibly can. Remember too that Arduino style hardware is cheap; if you need better performance, you can get something faster for $20. Don't break your head trying to squeeze speed out by direct port manipulation etc.

Your second question: make it a function or write it more than once? This is clearly a judgement call, so there isn't a right answer. I think the following two factors are important. Firstly, readability. Will it make the code easier to understand if you put the code into a function? For one thing, using a function allows you to describe what the code does in its function name. Imagine wading through code that didn't have analogue reads inside a function called analogRead()! This is important, not just for others but for yourself when you look at the code in a year or two.

Secondly, is the code likely to change? For example, is the algorithm still being refined? Is it likely to need changing if the code is re-tasked for another purpose? The point I'm making is that it is a bug risk to have the same code in multiple places if it is likely to need changing, because you might forget to change one of the instances. So that's another reason to have it embedded in a function: you change it in one place only.

This is how I would write it using what I consider 'best practices'. Note the use of 'const' for naming compile-time constants. This is somewhat less error prone than #define text substitutions and give the compiler type information it would not get from a #define.

const byte InputPin = A0;
const int TargetValue = 1023 ;

void setup()
{
  // pinMode(pinIn, INPUT); DO NOT USE with analogRead()
}

void loop()
{
  int inputValue = analogRead(InputPin) ;
  if (inputValue == TargetValue)
  {
    // do whatever
  }
}

Note that inputValue is a local variable. The advantage is that the compiler doesn't have to use memory space for it since it will disappear when the function ends. The generated code will likely look identical to:
if (analogRead(InputPin) == TargetValue)

It does anyone reading it even yourself just a few days or years later depending on age and other factors cough! a favor by making explicit that the code in the step the function handles is the same every time.

If you repeat yourself long hand, so to speak, you make me look to see if it’s the same as the other place(s) where similar? identical? code appears.

Also, to a first approximation, these processors are fast, and has been pointed out the compiler is very smart; the tiny amounts of time you save here and there are not worth chasing until you up to something I dare say you won’t, or shouldn’t, be until you’ve had some successes with programming,

a7

I agree. Avoid premature optimization, but don't avoid good design and readability. Once you have something running you can test where it is slow and work on that area.
If you still find your code is too slow there will be a faster board in a few months.

Thanks very much to all. I get the idea:

  • Use best practices and style to keep readability for others or myself later when I would come back to the sketch after some time.

  • Split different tasks in functions for same reason, but also to avoid repeating / spreading possible bugs while the code is still in development stage.

I used to program in the 80s (mostly basic and a just a bit of Z-80 assembler) but then I left it and became a marine engineer. Only three months ago started again... funny, because my dishwasher PCB broke down and I refused to throw it away.

Maybe because I had my brain structure used to a program language with line numbers, for me is very difficult to imagine how defining so many functions that are called outside of the visual flow of the program, would not affect performance. But I can understand that is not the case and there´s a lot more going on deeper after compiling.

Now I will start a Power Management System for 3 phase diesel generators. It should do all of this at the same time:

  • Measure total power on the grid and start - stop generators when required on a given priority order.
  • Synchronise the generators and connect in the precise moment when sync takes place (sync in 3 phase means equal potential, equal sequence, almost equal frequency, equal superposition of the 3 phases potential in time).
  • Share the total load on the grid evenly through acting on the genset governors while maintaining the bus frequency within an specific error band.
  • Enable / Disable big consumers depending on available power.
  • PID Control for the biggest consumer (propeller) maximum power.
  • Monitor power factor (cos Phi) and correct if necessary.

This is just for hobby or personal challenge, I can already picture it very easy by using more than one MCU, distributing tasks and interacting I/Os , but I want intentionally to try with only one to see if I can manage.

Thanks again.

Although not on the scale you are proposing, take a look at this off the grid Discretionary Load Control which uses frequency droop to indicate load and switches off non-essential loads accordingly. The front end is a simple set of menus/submenus on an Android mobile using my (paid) pfodApp. All the menu code is in the Arduino and there is a free pfodDesigner app that lets you build the menus, plots etc. on your mobile and then generate the Arduino code to implement them. Datalogging to your mobile is built in, but you probably want to log to an SD card and spool the data from there to your mobile for display.

HTML web pages is another way to go of course but that takes some web programming experience.