Difference between revisions of "Smarter Arduino Programming - Tips and Tricks"
Russ hensel (talk | contribs) |
Russ hensel (talk | contribs) |
||
(41 intermediate revisions by the same user not shown) | |||
Line 3: | Line 3: | ||
= Introduction = | = Introduction = | ||
− | This draft is for an instructable | + | This draft is for an instructable now published with pictures at: https://www.instructables.com/id/Smarter-Arduino-Programming-Tips-and-Tricks/. Updates will be made here, probably before anything at instructables, but look at it just for the graphics. Note that this is an article started by Russ Hensel, see "http://www.opencircuits.com/index.php?title=Russ_hensel#About My Articles" '''About My Articles''' |
+ | The following are some tips for better quicker programming of Arduinos. Much of the advice applies to other platforms so you may want to take a quick look even if you do not use the Arduino. This advice applies to the standard computer arduino ide, but applies to other environments as well. Some of the tips are fairly well known/standard but are often not used in the code I see published. | ||
− | + | If you are a rank beginner writing 50 line programs you may not find this useful. However, my typical arduino programs are more like 500 lines plus and these methods really begin to pay off. | |
− | + | = Sample Program = | |
− | + | I have written a simple program that illustrates some of these techniques. You can download it from github https://github.com/russ-hensel/BlinkInstruct If you download it and unzip into a directory called BlinkInstruct then you can open it with arduino.exe. And here is a tip: the download consists of several files, .ino, .h, .cpp; when you open the .ino file arduino.exe will open all of them in separate tabs of the arduino ide. Having several files offers advantages some of which will be discussed below. If you do not want to download the files you can still read them directly on github. If you do not want read along with it you can still get something out of just reading the tips. In the topics that follow I will use as examples the code in these files. | |
+ | = Easier Reading = | ||
− | + | Studies show programmers spend more time reading their code than writing it. Much of coding of all but the smallest programs involves scrolling up and down in the code looking for subroutine, names, signatures, code snippets... This scrolling makes you loose your place where you are actually writing the code. Simple solution: Open the file in another editor for read only access. You can still copy and paste between the two copies. From time to time refresh the read only copy. | |
− | + | = Easier Search = | |
− | + | Most programs consist of a bunch of subroutines. If you have a list near the top of the program ( perhaps as comments ) it is easy to highlight them ( perhaps with a double click ) find it ctrl-f ( for find ) and then zip down to the routine ( or calls to it ) in a flash. | |
− | |||
− | + | In the example I have a help routine rptHelp() with the relevant subroutine names as comments that serves this purpose, and in the loop() is a small command interpreter that dispatches to different subroutines. Each can serve double duty as an assistant to finding the code. Both are near the top of the program so you do not have to scroll a long distance to find them. | |
− | |||
− | + | = Use Header Files = | |
− | + | This is a very standard practice by C programmers, but I rarely see it in instructable projects. | |
− | + | Header files or .h files are commonly used for any settings that are used in the code that you might want to change without searching through the code. Very often this is done with pound defines. | |
+ | For example if you have a program foo.ino make a text file foo.h. In my example BlinkInstruct.h I have: | ||
+ | <pre> | ||
+ | #define VERSION_ID F( "BlinkInstruct 2018 02 03.2" ) | ||
+ | |||
+ | #define BAUD_RATE 19200 // including 9600 19200 38400 ....... set the terminal to match | ||
− | delay | + | #define MY_LED_PIN 13 // 13 is the builtin led but you can connect leds to other pins |
+ | #define DEFAULT_DELAY 100 // delay used in the blink | ||
+ | </pre> | ||
+ | Then at the top of BlinkInstruct.ino put the line | ||
− | + | <pre> | |
+ | #include "BlinkInstruct.h" | ||
+ | </pre> | ||
+ | Finally use the #defines in the code something like: | ||
− | + | <pre> | |
+ | digitalWrite( MY_LED_PIN, LOW ); | ||
+ | </pre> | ||
− | + | You will see more examples in the files. The example has another .h file, which is similar but I will not cover it here. | |
− | + | Dot H file can be use for many other useful things, but this is not an instructable on them or macro expansion. Google for a lot more useful info. | |
− | + | I am not sure what the official way is to get the arduino.exe to open the .h files ( and .cpp files.... ). My method is just to put the files in the directory with the code ( when the code is not open ). The next time you open the file the .h and other files will be show in the project, each in its own tab. | |
− | + | = Add Some Documentation = | |
+ | Many program become difficult to use and modify because of inadequate documentation. This can even trip up the author of the program. So add some documentation. But where: | ||
− | + | * Start with good naming, often if names are good you are done. | |
+ | * Add comments. Do not tell what the code is doing, for that someone can read the code. Instead tell why the code is doing something: what is the purpose, if it obvious leave the comment out. | ||
+ | * Write some additional material but where to put it: use another .h file, not for code but just comments. | ||
− | I | + | I use a file called readme.h. It is not "included" in any other file so it is not compiled. I is a good location for scratch work, example code, and longer notes that you might not want to put in the code. |
Comments in this file do not need // to mark them as comments because the file is never complied. | Comments in this file do not need // to mark them as comments because the file is never complied. | ||
− | Arduino.exe will automatically open the file so it is always at hand. | + | Arduino.exe will automatically open the file so it is always at hand when you are working on your code. |
+ | = Serial Monitor = | ||
− | + | Always have a serial monitor as part of your code. This lets you more easily see what is going on in the program and optionally control and debug it. If no serial monitor ( terminal program ) is connected there is generally no harm, the bits just go right in the bit bucket for recycling. Arduino.exe has its own serial monitor built in. I wanted more so I have written a serial monitor for the PC end of the conversations: [http://www.opencircuits.com/Python_Smart_Terminal Python Smart Terminal - OpenCircuits ] and [https://www.instructables.com/id/Python-Terminal-for-Cheap-Pi-Arduino-Connection/ Python Terminal for Cheap Pi Arduino Connection] Try it if you are a Python user as well ( and then you might also like: '''[https://www.instructables.com/id/Arduino-and-Python-and-perhaps-a-Rasberry-Pi/ Arduino and Python and Perhaps a Rasberry Pi ]''' ) | |
− | + | == Commands == | |
− | + | Many programs boot up, set up, and run a loop forever doing one thing over and over. | |
− | I | + | I like to make my programs more interesting by letting a user control them using the serial monitor ( or other terminal program, see especially: [[Python Smart Terminal]] ). I have written a library like object SerialCmd to support this. SerialCmd.cpp and SerialCmd.h are used over and over in my different programs, they are essentially library programs and you can just use them as is without every looking at them. |
− | + | So here I will not discuss there internals but just how they are used in the sample program. | |
+ | The whole program is divided into a bunch of subroutines including the familiar setup and loop. Setup gets SerialCmd, yes, setup. It is used in loop(). Subroutine loop() works this way: | ||
− | + | * It checks the UART to receive any characters that might be waiting. ( serialCmd.tryRecCmd( ); ) | |
+ | * It check for the end of a command by seeing if a carriage return character has been received. ( if ( serialCmd.gotCmd ) ) | ||
+ | * If it has a new command it separates the single character for the command, and gets any associated number into local variables. ( cmdChar = serialCmd.cmdPrior[0]; cmdNbr = SerialCmd.parseCmdNbr( serialCmd.cmdPrior ); ) Else it just loops | ||
+ | * The new command letter is used in a case statement to call the correct subroutine, optionaly with the associated number. | ||
− | + | Now you can make your arduino respond to commands, behavior can change without coding, reflashing...... | |
− | + | Read the code it is pretty clear. | |
+ | == Version == | ||
− | + | I do a lot of programs and a lot of revisions. Sometimes I am not working with the version that I want. So my code always includes a version that it sends to the serial port when the program starts and any time I ask the program for it ( with the command "v" ). | |
− | |||
In the header file: | In the header file: | ||
− | #define | + | <pre> |
− | + | #define VERSION_ID F( "BlinkInstruct 2018 02 03.2" ) | |
+ | </pre> | ||
+ | In the program: ( where there is a subroutine rptVersion( ) ) | ||
− | Serial.println( VERSION_ID ); | + | <pre> |
− | + | Serial.println( VERSION_ID ); | |
+ | </pre> | ||
− | + | == Help == | |
+ | One of the commands that is made available using the serial monitor is "?" to ask for Help. It is implemented by rptHelp(). It is really simple it just prints a little reminder of the commands the program understands. Really useful after switching between different programs or after not using a program for a period of time. | ||
+ | = F...ing Strings = | ||
+ | I use lots of messages which means lots of string literals like: | ||
+ | <pre> | ||
+ | Serial.println( "ABCDEFGHIJKLMNOPQRSTUVWXYZ" ) | ||
+ | </pre> | ||
+ | this can use a lot of dynamic memory ( which you have less of than program memory ). Change your code to: | ||
+ | <pre> | ||
+ | Serial.println( F( "ABCDEFGHIJKLMNOPQRSTUVWXYZ" ) ) | ||
+ | </pre> | ||
− | + | and the string goes in program memory ( which you normally have lots of ). This explains the "F(" which those of you with sharp eyes will have already noticed in the code. | |
+ | = Blink a Pin - Time It = | ||
− | + | It is usually fairly easy to add a blink to most programs. You can use it to indicate that power is on and that the program is ( maybe ) functioning. | |
− | + | In some cases you may want to know how fast ( usually a part of the program that is supposed to be as fast as possible ). One way to do this is to look at the assembled code and use the timing for each instruction ( and path ). The other way is to make it blink a pin and measure it with an oscilloscope of logic analyzer. Much quicker and easier. | |
− | A | + | = A better IDE = |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | = | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
+ | I have not looked hard but there may be more powerful IDE's for the Arduino. They may take some effort to find and setup, I have not done this, but if you do not like arduino.exe look around. Let me know what you like in the comments. | ||
+ | Notepad ++ is not an IDE but it is a better editor than the one in arduino.exe. If you set it to treat .ino files as c++ it will do a lot of code highlighting and clever features like code folding [[https://en.wikipedia.org/wiki/Code_folding Code Folding]]. | ||
[[Category:Arduino/RaspberryPi]] | [[Category:Arduino/RaspberryPi]] |
Latest revision as of 07:00, 6 February 2018
Smarter Arduino Programming
Contents
Introduction[edit]
This draft is for an instructable now published with pictures at: https://www.instructables.com/id/Smarter-Arduino-Programming-Tips-and-Tricks/. Updates will be made here, probably before anything at instructables, but look at it just for the graphics. Note that this is an article started by Russ Hensel, see "http://www.opencircuits.com/index.php?title=Russ_hensel#About My Articles" About My Articles
The following are some tips for better quicker programming of Arduinos. Much of the advice applies to other platforms so you may want to take a quick look even if you do not use the Arduino. This advice applies to the standard computer arduino ide, but applies to other environments as well. Some of the tips are fairly well known/standard but are often not used in the code I see published.
If you are a rank beginner writing 50 line programs you may not find this useful. However, my typical arduino programs are more like 500 lines plus and these methods really begin to pay off.
Sample Program[edit]
I have written a simple program that illustrates some of these techniques. You can download it from github https://github.com/russ-hensel/BlinkInstruct If you download it and unzip into a directory called BlinkInstruct then you can open it with arduino.exe. And here is a tip: the download consists of several files, .ino, .h, .cpp; when you open the .ino file arduino.exe will open all of them in separate tabs of the arduino ide. Having several files offers advantages some of which will be discussed below. If you do not want to download the files you can still read them directly on github. If you do not want read along with it you can still get something out of just reading the tips. In the topics that follow I will use as examples the code in these files.
Easier Reading[edit]
Studies show programmers spend more time reading their code than writing it. Much of coding of all but the smallest programs involves scrolling up and down in the code looking for subroutine, names, signatures, code snippets... This scrolling makes you loose your place where you are actually writing the code. Simple solution: Open the file in another editor for read only access. You can still copy and paste between the two copies. From time to time refresh the read only copy.
Easier Search[edit]
Most programs consist of a bunch of subroutines. If you have a list near the top of the program ( perhaps as comments ) it is easy to highlight them ( perhaps with a double click ) find it ctrl-f ( for find ) and then zip down to the routine ( or calls to it ) in a flash.
In the example I have a help routine rptHelp() with the relevant subroutine names as comments that serves this purpose, and in the loop() is a small command interpreter that dispatches to different subroutines. Each can serve double duty as an assistant to finding the code. Both are near the top of the program so you do not have to scroll a long distance to find them.
Use Header Files[edit]
This is a very standard practice by C programmers, but I rarely see it in instructable projects.
Header files or .h files are commonly used for any settings that are used in the code that you might want to change without searching through the code. Very often this is done with pound defines. For example if you have a program foo.ino make a text file foo.h. In my example BlinkInstruct.h I have:
#define VERSION_ID F( "BlinkInstruct 2018 02 03.2" ) #define BAUD_RATE 19200 // including 9600 19200 38400 ....... set the terminal to match #define MY_LED_PIN 13 // 13 is the builtin led but you can connect leds to other pins #define DEFAULT_DELAY 100 // delay used in the blink
Then at the top of BlinkInstruct.ino put the line
#include "BlinkInstruct.h"
Finally use the #defines in the code something like:
digitalWrite( MY_LED_PIN, LOW );
You will see more examples in the files. The example has another .h file, which is similar but I will not cover it here.
Dot H file can be use for many other useful things, but this is not an instructable on them or macro expansion. Google for a lot more useful info.
I am not sure what the official way is to get the arduino.exe to open the .h files ( and .cpp files.... ). My method is just to put the files in the directory with the code ( when the code is not open ). The next time you open the file the .h and other files will be show in the project, each in its own tab.
Add Some Documentation[edit]
Many program become difficult to use and modify because of inadequate documentation. This can even trip up the author of the program. So add some documentation. But where:
- Start with good naming, often if names are good you are done.
- Add comments. Do not tell what the code is doing, for that someone can read the code. Instead tell why the code is doing something: what is the purpose, if it obvious leave the comment out.
- Write some additional material but where to put it: use another .h file, not for code but just comments.
I use a file called readme.h. It is not "included" in any other file so it is not compiled. I is a good location for scratch work, example code, and longer notes that you might not want to put in the code.
Comments in this file do not need // to mark them as comments because the file is never complied.
Arduino.exe will automatically open the file so it is always at hand when you are working on your code.
Serial Monitor[edit]
Always have a serial monitor as part of your code. This lets you more easily see what is going on in the program and optionally control and debug it. If no serial monitor ( terminal program ) is connected there is generally no harm, the bits just go right in the bit bucket for recycling. Arduino.exe has its own serial monitor built in. I wanted more so I have written a serial monitor for the PC end of the conversations: Python Smart Terminal - OpenCircuits and Python Terminal for Cheap Pi Arduino Connection Try it if you are a Python user as well ( and then you might also like: Arduino and Python and Perhaps a Rasberry Pi )
Commands[edit]
Many programs boot up, set up, and run a loop forever doing one thing over and over.
I like to make my programs more interesting by letting a user control them using the serial monitor ( or other terminal program, see especially: Python Smart Terminal ). I have written a library like object SerialCmd to support this. SerialCmd.cpp and SerialCmd.h are used over and over in my different programs, they are essentially library programs and you can just use them as is without every looking at them.
So here I will not discuss there internals but just how they are used in the sample program.
The whole program is divided into a bunch of subroutines including the familiar setup and loop. Setup gets SerialCmd, yes, setup. It is used in loop(). Subroutine loop() works this way:
- It checks the UART to receive any characters that might be waiting. ( serialCmd.tryRecCmd( ); )
- It check for the end of a command by seeing if a carriage return character has been received. ( if ( serialCmd.gotCmd ) )
- If it has a new command it separates the single character for the command, and gets any associated number into local variables. ( cmdChar = serialCmd.cmdPrior[0]; cmdNbr = SerialCmd.parseCmdNbr( serialCmd.cmdPrior ); ) Else it just loops
- The new command letter is used in a case statement to call the correct subroutine, optionaly with the associated number.
Now you can make your arduino respond to commands, behavior can change without coding, reflashing......
Read the code it is pretty clear.
Version[edit]
I do a lot of programs and a lot of revisions. Sometimes I am not working with the version that I want. So my code always includes a version that it sends to the serial port when the program starts and any time I ask the program for it ( with the command "v" ).
In the header file:
#define VERSION_ID F( "BlinkInstruct 2018 02 03.2" )
In the program: ( where there is a subroutine rptVersion( ) )
Serial.println( VERSION_ID );
Help[edit]
One of the commands that is made available using the serial monitor is "?" to ask for Help. It is implemented by rptHelp(). It is really simple it just prints a little reminder of the commands the program understands. Really useful after switching between different programs or after not using a program for a period of time.
F...ing Strings[edit]
I use lots of messages which means lots of string literals like:
Serial.println( "ABCDEFGHIJKLMNOPQRSTUVWXYZ" )
this can use a lot of dynamic memory ( which you have less of than program memory ). Change your code to:
Serial.println( F( "ABCDEFGHIJKLMNOPQRSTUVWXYZ" ) )
and the string goes in program memory ( which you normally have lots of ). This explains the "F(" which those of you with sharp eyes will have already noticed in the code.
Blink a Pin - Time It[edit]
It is usually fairly easy to add a blink to most programs. You can use it to indicate that power is on and that the program is ( maybe ) functioning.
In some cases you may want to know how fast ( usually a part of the program that is supposed to be as fast as possible ). One way to do this is to look at the assembled code and use the timing for each instruction ( and path ). The other way is to make it blink a pin and measure it with an oscilloscope of logic analyzer. Much quicker and easier.
A better IDE[edit]
I have not looked hard but there may be more powerful IDE's for the Arduino. They may take some effort to find and setup, I have not done this, but if you do not like arduino.exe look around. Let me know what you like in the comments.
Notepad ++ is not an IDE but it is a better editor than the one in arduino.exe. If you set it to treat .ino files as c++ it will do a lot of code highlighting and clever features like code folding [Code Folding].