TROUBLESHOOTING SOLUTIONS: CODE PROBLEMS, LOGICAL ERRORS
Logical errors occur when your code compiles and uploads, but doesn’t behave the way you want it to. These errors are the trickiest to find and fix because the Arduino software doesn’t give you any feedback about what might be causing the problem, like it does with compile and upload errors.
Logical errors happen when the code that you’ve written doesn’t do what you intended it to do. The code compiles and the LilyPad is following the code exactly as you’ve written it, but there is an error in the code that is making your project behave in an unexpected way.
symptoms
If your project isn’t working the way you expect it to, you may have a logical error in your code. For instance, if your code compiles and uploads but your project doesn’t do anything, or if (in the monster project) your monster doesn’t ever stop making sound, you might have a logical error. You might, however, also have an electrical problem.
finding logical errors in your code
Before you check your code for logical errors, you should make sure your project doesn’t have any electrical problems. Once you’ve eliminated the possibility of electrical issues, you should check your code for errors.
To find logical errors, read through your program line by line and try to relate what each line is doing to the behavior you’re seeing in your project. The LilyPad does exactly what your program tells it to do. Your job is to find the mismatch between what you want it to do and what the program is telling it to do.
In your read-through, look especially for the errors listed on the left. However, keep in mind that there is an infinite variety of logical errors and this guide cannot cover them all. Your particular error may not be discussed here.
the rest of this section
The next few pages explore common logical errors—the ones listed on the left—and the behaviors they generate. This section also provides tips on how to find and fix these problems.
Each section begins with examples of code with and without the specific error. The location of the problems and corrections are highlighted in yellow in the code. Below the code examples is a discussion of the behavior you will see if you make a similar mistake in your code. This is followed by advice on finding and fixing that particular type of problem.
LOGICAL ERRORS COVERED IN THIS SECTION
• missing variable initializations
• variables that do not match circuit
• conditions that are always true or false
• extra or misplaced semicolons
• incorrect variable initializations
• problems with delay statements
MISSING VARIABLE INITIALIZATIONS
error example:
int led = 13; void setup() { _________________ }
fixed example:
int led = 13; void setup() { pinMode(led, OUTPUT); }
symptoms
If you have an LED that is turning on very dimly or a speaker that is making very faint sounds, you may be missing a pinMode(component, OUTPUT); statement like the error example above. If you are missing a pinMode statement for a component, the component will either not work at all, or will barely work. For example, if the component is an LED it will only turn on very dimly.
error example:
void setup() { pinMode(led, OUTPUT); pinMode(speaker, OUTPUT); pinMode(aluminumFoil, INPUT); ______________________ Serial.begin(9600); }
fixed example:
void setup() { pinMode(led, OUTPUT); pinMode(speaker, OUTPUT); pinMode(aluminumFoil, INPUT); digitalWrite(aluminumFoil, HIGH); Serial.begin(9600); }
If you have a sensor or switch that is giving you random readings, you may be missing a digitalWrite(component, HIGH); statement like the error example above. If you’re missing this digitalWrite(component, HIGH); statement, your sensor or switch will not work properly. It will behave erratically and you will not be able to get reliable readings from it.
FIX MISSING VARIABLE INITIALIZATIONS
If you are experiencing anything like the problems described above, look for missing variable initialization statements in setup. Remember that each component you use in your project needs to be initialized in setup. You should have a pinMode statement for each LED, speaker, sensor, or switch in your design. Each sensor or switch (with the exception of the capacitive sensors in the piano project) should also have a digitalWrite(component, HIGH); statement in setup. If you find missing initialization statements, add them to your program and recompile and upload your code. Test your project to see if you have fixed the error.
VARIABLES THAT DO NOT MATCH CIRCUIT
error example:
int speaker = 5;
fixed example:
int speaker = 6;
error example:
int led = A4;
fixed example:
int led = 5;
error example:
int key1 = 6;
fixed example:
int key1 = 9;
symptoms
If there is an LED, speaker, or sensor in your project that is not working at all, your code may not match the circuit that you have built. For example, if your LED is sewn to pin 5, but your code is written as though your LED is sewn to pin A4, your LED will not work. This is the example shown above in the center.
FIX VARIABLES THAT DO NOT MATCH CIRCUIT
If you have a component that is not working at all, look carefully at your circuit and see which pins each of your components are sewn to. Make sure your code matches your circuit. If you find any places where circuit and code disagree, you’ve identified your problem.
You can address this problem in two different ways. You can either restitch your circuit so that it matches the code you’ve written or you can rewrite your code so that it matches the circuit that you’ve sewn. It’s a lot easier to change your code than to restitch your circuit! If you can, you want to edit your code so that it matches your circuit. For example, if the (+) side of your speaker is sewn to pin 6, change your code so that the speaker variable in your code also refers to pin 6 (as in the topmost example shown above).
There is one exception to this general rule. For the monster project’s sensor, one paw should be sewn to (-) and the other paw should be sewn to one of the “A” pins—pin A2, A3, A4, or A5. If you sewed your sensor paw to a pin that is not A2, A3, A4, or A5, you will need to take out your stitching and resew the sensor paw to one of the “A” pins. In all other cases, you should change your code instead of changing your circuit to correct the mismatch.
Note: See also the “incorrect variable initializations” section below.
CONDITIONS THAT ARE ALWAYS TRUE OR FALSE
error example:
sensorValue = analogRead(aluminumFoil); Serial.println(sensorValue); delay(100); if (sensorValue < 1024) { song(2000); }
fixed example:
sensorValue = analogRead(aluminumFoil); Serial.println(sensorValue); delay(100); if (sensorValue < 1000) { song(2000); }
symptoms
If something that should happen in your program never happens—for example, if your monster never sings its song—or, if something happens all the time when it shouldn’t—for example, if your monster never stops singing—you may have a bad conditional statement. You may have a conditional statement with a condition that is always true or always false. For example, in the code above on the left, the condition (sensorValue <1024) will always be true because the variable sensorValue will always be below the threshold value of 1024. This means your monster will always be singing; it will never stop singing.
If your program uploads but your project doesn’t do anything at all, you may also have a bad conditional statement. In the left example below, (i < numberOfKeys) is always true because i never changes, i is always 0. The while statement is missing an i=i+1; statement. This means you will be stuck inside the while loop forever; the LilyPad will never move on to the rest of your program.
error example:
const int numberOfKeys = 7; int i = 0; while (i < numberOfKeys) { pinMode(keys[i], INPUT); _____ }
fixed example:
const int numberOfKeys = 7; int i = 0; while (i < numberOfKeys) { pinMode(keys[i], INPUT); i = i+1; }
FIX CONDITIONS THAT ARE ALWAYS TRUE OR FALSE
If you are experiencing anything like the problems described here, look carefully at the conditional statements in your program—if else statements and while loops. Read through these sections of your program and make sure that the conditions in each conditional statement will change as the program progresses or as you interact with your project.
Once you’ve identified the problematic condition, adjust it so that it will change as the program progresses or you interact with your project. Make sure that your threshold values are appropriate for the sensor values in your project and make sure that you are not getting stuck in while loops because of missing i=i+1; statements.
Note: See also the extra semicolons entry below. Extra and/or misplaced semicolons can create similar behaviors and problems.
EXTRA OR MISPLACED SEMICOLONS
symptoms
If something in your program happens all the time when it shouldn’t—for example, if your monster never stops singing—you may have an extra semicolon in one of your if statements. If your program uploads but your project doesn’t do anything at all, you may have an extra semicolon in one of your while statements.
When you put a semicolon at the end of the first line of a conditional statement, as in the left-hand examples above, your code will not behave the way you expect it to. Adding this extra semicolon tells the compiler that the entire conditional statement should end where the semicolon is. Anything after the semicolon is treated as a separate and unrelated block of code.
error example:
if (touchValue > 1); { tone(speaker, note); delay(100); }
fixed example:
if (touchValue > 1)_ { tone(speaker, note); delay(100); }
For example, in the code above on the top, the entire if statement would end with the semicolon. The statements tone(speaker, note); and delay(100); would be treated as independent statements, unrelated to the if statement. They would always be executed, whether or not the condition in the if statement was true. This means the speaker would always play a note. Note: This particular problem will only happen with stand-alone if statements. If your if statement has a companion else statement, you will receive a compile error when you try to compile the code with the extra semicolon.
In the error example below, the entire while loop would end with the semicolon. Because there is no statement that changes the value of i between the while loop’s condition and the semicolon, the condition of the while loop would never change and the LilyPad would remain stuck in this part of the code forever. The code would upload to your project, but your project wouldn’t do anything once it reached the while loop with the extra semicolon.
error example:
const int numberOfKeys = 7; int i = 0; while (i < numberOfKeys); { checkPianoKey(keys[i], notes[i]); i = i+1; }
fixed example:
const int numberOfKeys = 7; int i = 0; while (i < numberOfKeys)_ { checkPianoKey(keys[i], notes[i]); i = i+1; }
FIX EXTRA OR MISPLACED SEMICOLONS
If you are experiencing anything like the problems described here, look carefully at the conditional statements in your program— if statements and while loops. Read through these sections of your program and make sure that they do not have any extra semicolons. The lines if (condition) and while (condition) should never be followed by semicolons. Remove any extra semicolons you find and recompile and upload your code.
INCORRECT VARIABLE INITIALIZATIONS
error example:
int C = 10; int D = 1175; int E = 1319; int F = 1397; int G = 15; int A = 17600; int B = 1976; int C1 = 2093;
fixed example:
int C = 1046; int D = 1175; int E = 1319; int F = 1397; int G = 1568; int A = 1760; int B = 1976; int C1 = 2093;
symptoms
Variables, their definitions and initializations, lay the foundation for the rest of your program. They’re like the ingredients in a recipe, the basic raw materials you have to work with. If you give a variable the wrong value at the beginning of your program it’s like starting out with the wrong ingredient for your recipe (salt instead of sugar, say). Variables with bad values can cause lots of different kinds of problems in your programs.
A pin variable that does not match your circuit (an error covered earlier in this section) is one specific example of an incorrect variable initialization. In this case, the bad variable initialization means that one of your components will not work properly.
The example above shows a different example, the incorrect initialization of several note variables. This will cause your speaker to play incorrect notes for C, G, and A and may even mean that your speaker will not make any sound at all for some of the notes that it should play.
The example below shows an example where the while loop variable i is initialized incorrectly. Its initial value should be 0, but the code sets it to 1. (Remember computer scientists always begin counting from 0 instead of 1.) This means that the loop will check the last six keys, but it will never check the first key or play the first note. That is, the program will never execute checkPianoKey(keys[0], notes[0]);. This means that the first key on the piano will not work.
error example:
const int numberOfKeys = 7; int i = 1; while (i < numberOfKeys) { checkPianoKey(keys[i], notes[i]); i = i+1; }
fixed example:
const int numberOfKeys = 7; int i = 0; while (i < numberOfKeys) { checkPianoKey(keys[i], notes[i]); i = i+1; }
FIX INCORRECT VARIABLE INITIALIZATIONS
If you are having problems with a particular part of your program make sure you investigate the variables that relate to that part of the code in your troubleshooting. Many different problems can be caused by incorrect variable initializations, so it is an important thing to check for. If you find an incorrect variable initialization, correct the problem and recompile and upload your code. Check your project’s behavior to see if your edit has fixed the problem.
PROBLEMS WITH DELAY
error example:
void loop() { digitalWrite(led, HIGH); delay(1); digitalWrite(led, LOW); delay(1); }
fixed example:
void loop() { digitalWrite(led, HIGH); delay(1000); digitalWrite(led, LOW); delay(1000); }
symptoms
Misuse of delay statements can cause a few different problems. Problem delays can be too short, too long, or missing altogether. If a delay is too short, it may seem like things that should be happening are not happening. For example, in the code above, the delays after the digitalWrite(led, HIGH); and digitalWrite(led, LOW); statements are very short. The statement delay(1); tells your project to stop and wait for one millisecond—that’s 1/1000 of a second, a tiny amount of time. In this program, the LED will turn on and off so quickly that you will not be able to see it blinking. Instead, your LED will look like it’s on dimly all of the time. The same kind of thing can happen with speakers. If you have a very short delay after a tone statement, you may not hear anything or may only hear a faint clicking sound.
If your program seems to never respond to you or to only respond very slowly—if your monster or piano never responds to your touch or responds very slowly—you may have a delay that is too long or a series of delays that are taking too much time. For example, in the code below, the last line of the song procedure (delay(20000);) will make your project stop and do nothing for 20,000 milliseconds—that’s 20 seconds, a very long time! This means you’ll have to wait 20 seconds before your project will be able to detect your touch, blink, or make sounds again. This is an extreme example. Your behavior may be much more subtle. For example, in the monster project, if your blinkPattern procedure takes a few seconds to run (say three seconds) then you may have to hold onto your monster’s paws for three seconds before it responds to your touch. This may mean that your monster is less responsive than you’d like it to be.
error example:
void song() { tone(speaker, E); delay(2000); tone(speaker, D); delay(2000); tone(speaker, C); delay(2000); noTone(speaker); delay(20000); }
fixed example:
void song() { tone(speaker, E); delay(2000); tone(speaker, D); delay(2000); tone(speaker, C); delay(2000); noTone(speaker); delay(2000); }
Remember as you think about the delays in your code, that programs execute line by line in order and the LilyPad can only do one thing at a time. It needs to finish a delay before it moves on to the next part of your program.
Remember also that if your project is sending data back to your computer with Serial.println statements, you will overload your computer with too much data if your program does not have a delay statement. If this happens, your computer will probably crash.
FIX PROBLEMS WITH DELAY
If you are having problems like any of the ones described above, read through your program line by line, paying particular attention to the delay statements. If a component like an LED or a speaker seems like its not working, look for delays that are too short and, if you find any, make them longer. If a sensor seems like it’s not working, look for delays that are too long or entire sections of code that take a long time to execute. Try to shorten the delays or edit sections of code so that they execute more quickly. If your computer has crashed from a data overload, add a delay statement to your program right after your Serial.println statement.
Recompile and upload your code. Check your project’s behavior. You may need to adjust the delays in your program a few times before you get a behavior you’re happy with.