Arrays

The first steps in beginning to program, as opposed to just filling a sketch with commands to turn things on and off, is to understand arrays.

 
 

Rather than trawl the net looking for code to copy and paste into your project, how about using a bit of effort and try and understand what is going on. This shows you how to take that next step from beginner to expert, as you start writing code that is a bit beyond the plodding.

 

The use of arrays for arduino outputs

The trick in programming is to make as few lines of code do as much work as possible. Before the days of copy and paste this was an obvious thing to do, to save all that time typing. However, this is not the only, or indeed the primary reason, for making your lines of code do the most work you can get them to do.

With efficient code it is much easer to see the whole picture without trawling through pages and pages of turgid code all saying virtually the same thing. As a rule of thumb when you find yourself writing four or more lines that are nearly the same it is time to think about doing things better, smarter and more efficiently.

This is why there are looping structures built into every computer language, to make a few lines of code do a lot of work. The trick lies in making that line of code do the same thing to different things.

How to begin to write good code

Example

Outputting patterns

Now suppose those output pins were connected to LEDs and you want to output a particular pattern how could you do that in a loop. Yes the pin numbers are variable but what about the high / low pattern. Well you can put that in an array as well.


Let's look at a more realistic example. Suppose you have connected the arduino to a common cathode seven segment display like in this diagram. How would you output the number 2? You need to turn segments a, b, d, e and g on with segments c and f off. Well the long winded none smart way would be to do this:-

// output a 2

digitalWrite(2, HIGH);

digitalWrite(3, HIGH);

digitalWrite(4, LOW);

digitalWrite(5, HIGH);

digitalWrite(7, HIGH);

digitalWrite(11, LOW);

digitalWrite(12, HIGH);

We have seen how we can turn the pins into variables but what about the HIGH / LOW

well we could use an array again like this:-

boolean two [7] = { HIGH, HIGH, LOW, HIGH, HIGH, LOW, HIGH };

and one for the pins:-

int pins [7] = { 2, 3, 4, 5, 7, 11, 12 };

then a quick:-


for(int i=0; i<7; i++) digitalWrite(pins[i], two[i]);


would do it.

 

So let's start by looking at something simple.

Suppose you have a lot of pins you want to use as outputs. You know in the setup function you have to declare each one of them to be an output. The simple method is to write the same line over and over like this:-


pinMode(2, OUTPUT);

pinMode(3, OUTPUT);

pinMode(4, OUTPUT);

pinMode(5, OUTPUT);

pinMode(6, OUTPUT);


But it is repetitive and the job of a computer is to do repetitive work not you. The problem here is that each pin needs to be identified in turn on each line. So when faced with this problem your solution is always to think, how can I make this part of the line into a variable?


With a pin number it is easy especially if the pin numbers are consecutive numbers, you use a loop. The normal form of loop is a for loop and while these normally start at zero, they can actually stare with any value of loop index you like. So to initialise all the pins as inputs you only need do this:-


for(int i = 2; i<7; i++) pinMode(i, OUTPUT);


That is all very well if the pins you want to use are nicely in consecutive order but what happens if they are distributed in an arbitrary manor. The answer lyes in using an array. Think of an array as making an unordered list into an ordered one. The array has an index or box in which to put a number. That box can be addressed by a variable, so it is like making a variable name a variable. Suppose you want to use pins 3, 5, 7, 10, 12, and  13 as outputs. First you define an array with five values in it. Like this:-


int pins [6] = { 3, 5, 7, 10, 12, 13 }


This array called pins will have an index from zero to five (six boxes) So the first box pins[0] will have a value of 3 in it and the last box pins[5] will contain the number 13. Then it is easy to set all these pins to be outputs, you simply use a for loop with the index running from 0 to 4:-


for(int i=0; i<6; i++) pinMode(pins[i], OUTPUT);


Even better suppose you want to turn all these outputs off, that is put them at a logic zero then simply:-


for(int i=0; i<6; i++) digitalWrite(pins[i], LOW);


Note here this can be as many pins as you like, all you need to change is the number of entries in the pins array.

Getting a bit fancy

However we only have an array that defines the number two it would be good if we can define an array for any number. That can be done but first lets look at making that pattern array into a single number.

We just want to define a segment as being on or off so all we need to do that is one binary bit. You get eight of them in a byte so we could define that pattern in a single byte if we used a binary notation. That entire pattern could be defined as:-


char two = B1011011;


With the right and most bit being the on / off for segment a, connected to pin 2, and the left hand most bit being that for segment g which is connected to pin 12. So having got the pattern into a single byte how do we extract it for use in our for loop?


The answer lies in the use of the bitwise AND operation. This can be used to isolate bits in a variable. We use a test variable called a mask. This is a number with only one bit set and all the others clear. If we AND a mask with our pattern number we will get a zero if the bit that is set in the mask corresponds to the same bit being clear in our number. Read that again and look at these diagrams:-

The trick now is to slide this set bit in our mask along the length of the pattern number and turn on or off the segment depending on the result of the bitwise AND operation. Then each time round the loop we shift this mask one place to the left and cover a different bit next time round the loop. Like this:-


char two = B1011011;

int mask = 1;

for(int i=0; i<7; i++){

  if((mask & two) == 0) digitalWrite(pins[i], LOW); else digitalWrite(pins[i], HIGH);

  mask = mask << 1;

}


The trick here is to look at that if statement, the & is the bitwise AND and we are doing it to the variable mask, which is 1 the first time round the loop and the pattern number variable called two. As this has its least significant bit (right hand most bit) set the result will not be zero and so we write a high to that segment. Then the mask gets shifted one place to the left and becomes the number 2 ready for use the next time round the loop.

What’s the point?

Now you might quite correctly say that this is more complex than the last example with no advantage, and you would be right. But this gives us a spring board to coping with all the patterns for all the numbers of a seven segment display in one simple routine.


To do this we define an array that contains the patterns for all the numbers from 0 to 9 with one byte for each pattern:-


char sevenCode[10] = { 0x3f, 0x06, 0x5b, 0x1f, 0x66, 0x6b, 0x7b, 0x07, 0x7f, 0x67 };


Note here rather than use binary values to describe the bit pattern I have used hex numbers as these are much easer to cope with than binary. If your not comfortable with that then stick to binary defined numbers.


Now we can write a routine where we can pass a number and that will be displayed on the seven segment display.


void display7(int num){

int mask = 1;

  for(int i=0; i<7; i++){

   if((mask & sevenCode[num]) == 0) digitalWrite(pins[i], LOW); else digitalWrite(pins[i], HIGH);

   mask = mask << 1;

  }

}


We have replaced our single patten variable with an array and used the number we passed into this routine to select what pattern we want to display. Try replacing that with the long hand version and it will go on for pages. This way the display routine is short and efficient and we can see at a glance what it does.


There are several lessons here that will stand you in good stead for your understanding of programming:-


1) Use and array when you want to make an arbitrary sequence into a consecutive one. This is known as making a look up table because the array index looks up the value you need to use.


2) Arrays can be used to store patterns.


3) Bits can be extracted from bytes by use of a mask and a bitwise AND operation.


4) Loops cut down on typing and make things short and easy to read. Besides it looks like proper grown ups code.