Arduino Sketch Merge Tutorial
The Basic Steps
editThere are 8 stages to combining two sketches, although you might finish early depending on what is in your sketches. These steps are:-
- Physically get the sketches into the same file.
- Resolve any duplicate function names by renaming the functions.
- Write new setup and loop functions.
- Remove any duplication of function calls.
- Resolve any duplicate global variable names.
- Resolve any dual use of hardware resources.
- Tidy up the code.
- Think what you actually want the merged code to do.
Although you might want to consider the last step first. Anyway let's take those one at a time.
Step One: Physically Get The Sketches Into The Same File
editThere are two ways of doing this. Perhaps the simplest way is to simply copy one sketch and paste it into the other. The more complex way is to create a new sketch, with nothing in it for the time being, and save it. Then quit the Arduino application and move or copy the two target files, that is the .ino or .pde files into the same folder as your new sketch. When you open up the arduino application again the two files to merge will be in separate tabs in the interface. While this might be neat it opens up some problems later on when you come to use common variables so for the time being we will just use the simple method of copy and paste. So create a new sketch and save it under the name of Blink_Fade. Now open up the blink and fade sketches from the File -> Examples -> Basics menu. Use copy and paste to move the code from each of the two sketches into the new one and then save the new one. To exactly follow my example, copy the Fade sketch first and then the Blink after it. Close down the Blink and Fade sketches to tidy things up.
Step Two: Resolve Any Duplicate Function Names By Renaming The Functions
editIf you try and compile this by clicking the tick icon in the top left hand corner. You will be met with 6 lines of error messages. Not the error messages are not very beginner friendly, and there are normally lots of them, but if you take time to read them they will tell you what is wrong, or at least at what point the compiler became confused. In this case you get:-
Blink_Fade.cpp: In function 'void setup()': Blink_Fade:39: error: redefinition of 'void setup()' Blink_Fade:12: error: 'void setup()' previously defined here Blink_Fade.cpp: In function 'void loop()': Blink_Fade:45: error: redefinition of 'void loop()' Blink_Fade:17: error: 'void loop()' previously defined here
So lets look at the first line, it tells you there is a problem in the function setup(), then the next line tells you what that problem is, there is a redefinition of the function called setup(). The rule is that no two functions can have the same name, because if they did how would the computer know which one to choose when it was called. So where was this function first defined? The third line tells you:- error: 'void setup()' previously defined here, but where is here? Well the first part of that line says:- Blink_Fade:12: That means it was first defined in line 12 of the code. But where is that? Well if you look at the bottom left hand corner of the window you will see a number, that is the line number. Click on the line containing the first instant of setup() and it says 13. But hang on the message says that the error is in line 12 not 13. Well this is a little inconsistency between the Arduino interface and the compiler. The interface starts counting lines from one, so the first line is line one. However, the compiler starts counting lines from zero, so the first line is line zero. Hence the confusion between line 12 and 13, but not to worry it's close enough. The next three lines are telling you the same tale but only about the function called loop(). Note the function is called loop() not void loop(), the void bit is not part of the name it is just telling you what sort of variable the function returns, in this case nothing is returned, the word for nothing in this language is void. So the first step in correcting this is to rename both functions something different. So rename them setupFade(), and setupBlink() and loopFade() and loopBlink(). At this point we have done with step 2 but with another pair of sketches there might be other duplicate names both of functions and variables. These would be only variables defined outside a function, so called global variables. The compiler will tell you about them and you should now be able to read the error messages about them.
Step Three: Write New Setup And Loop Functions
editSave the sketch and click compile again. The next lot of error messages you get will say:-
core.a(main.cpp.o): In function `main': /Applications/Arduino.app/Contents/Resources/Java/hardware/arduino/cores/arduino/main.cpp:11: undefined reference to `setup' /Applications/Arduino.app/Contents/Resources/Java/hardware/arduino/cores/arduino/main.cpp:14: undefined reference to `loop'
Just to make them more unreadable, they will be split up, but lets take them one at a time:- The first line says In function `main':, What! we don't have a function called main in our sketch so what is it on about? Well main is a function that is hidden by the Arduino interface, one that it puts in itself. In that function it calls a function called setup() once and then repeatedly calls a function called loop(). It expects to find these two functions in your sketch, there used to be one, well actually two, but we renamed them both and now there aren't any. So lets add some, type this at the start of the sketch.
/* Fade Blink
an exercise in combining code */ void setup(){ setupFade(); setupBlink(); } void loop(){ loopFade(); loopBlink(); }
Save and compile again and this time no errors!!!
However, a word of caution, just because the compiler knows how to handle what you wrote it doesn't mean it makes sense, or it will do what you think. It's like a spell checker, you can have a completely correctly spelled essay, but if the words are not the right ones and in the right order a reader will not be able to understand it.
Step Four: Remove Any Duplication Of Function Calls
editWell there is no need to do that with this example but again another pair of sketches might give you different results. This is most likely to be a problem in the setup() function. Typical might be if you have a Serial.begin() in each of the old setup() functions. Remove one, or better still remove them both and put it in the new setup() function. The same goes for initialising things like I2C drivers or the 1 Wire bus.
Step Five: Remove Any Duplication Global Variable Names
editStep Six: Resolve Any Dual Use Of Hardware Resources
editHere you have to look yourself at the two sketches and ask if the two sketches are using the save resource of part of the processor. The most fundamental resource are the input / output pins does each sketch want the same pin for different functions? Is the same pin being set as an input in one sketch and an output in the other? This can be resolved by shuffling pins about and using different pins. Most of the pins are interchangeable there are only a few that have reserved functions. Such functions might be a PWM capability, an analogue input capability or a bus driver like the SPI or I2C. Note that the analogue pins can be used as normal digital inputs and outputs if you get pushed. The problem comes when each sketches need the same pins. However this is not always the problem it might at first appear, for example you can have more than one device on the I2C bus without any extra hardware. Also the SPI bus can have more than one device on it, if you have a separate line for the chip enable of each device.
Step Seven: Tidy Up The Code
editMake it look like one sketch. In the case of this example move all the global variable definitions to the start of the code and tidy up the comments. Now run the code and see what happens!
Step Eight: Think What You Actually Want the Merged Code To Do
editWell what did it do? You might be forgiven for thinking that the blinking bit still worked but the fade bit didn't. Well in fact both functions are still working but just one after the other. The on board LED still appears to blink with one second on and one second off. But the fading LED just seems to be on. However if you wait long enough you will see the LED that you have wired with a resistor to pin 9, gradually start to turn on. The loop that does the fading only gets a shot at running once every two seconds so it will take 102 seconds to get to full brightness and another 102 to get down to zero again, that's a cycle time of 3 minuets 24 seconds. In fact it is slightly longer than that because of the 30 milli second delay at the end of the fade loop, that will add another 15 seconds or so to the full cycle time. So, having merged the two sketches, in this example, was not quite the right thing to do. What is the solution? Well in this case and a lot of others you need to eliminate the delay() function from the loops. This is because the delay() completely stops the processor from doing anything else, we say it is a blocking call. To eliminate the delay() you want to look at the sketch "Blink without delay" in the File -> Examples -> Digital menu of the Arduino application. But that is for another tutorial.