Arduino Code Mistake ??? - Page 1
Forum section: electronics / projects

author: ChrisGreece52
author_rank: Frequent Contributor
timestamp: May 04, 2013, 05:50:04 pm
content: Hello i started today a small project.It basicaly calculates time . Let me explain :I have a setup with a laser diode and a photoresistor. (photoresistor) 10Kohm ResistorThe photoresistor is hoocked up to the arduino like this 5v o--/\/\/\/\/\------|-----------------/\/\/\-----------------o GND||pin A15 Arduino (that was the closest that i could use and i am using it only for technical reasons)And when the photoresistor is being hit by the laser i get an analog value of about 879 and when its not hit i get a value of about 200My Goal :When the laser beam gets interrupted (value drop from around 879 to 200 so at the code i wrote " if val <600") it starts to count miliseconds and when the laser hits the sensor again it stops counting and displays the milliseconds that the beam was interrupted.I tried "while" and "do" as a last resort but nothing the code wont work.Code :Code:/*LiquidCrystal Library - Hello WorldDemonstrates the use a 16x2 LCD display. The LiquidCrystallibrary works with all LCD displays that are compatible with theHitachi HD44780 driver. There are many of them out there, and youcan usually tell them by the 16-pin interface.This sketch prints "Hello World!" to the LCDand shows the time.The circuit:* LCD RS pin to digital pin 12* LCD Enable pin to digital pin 11* LCD D4 pin to digital pin 5* LCD D5 pin to digital pin 4* LCD D6 pin to digital pin 3* LCD D7 pin to digital pin 2* LCD R/W pin to ground* 10K resistor:* ends to +5V and ground* wiper to LCD VO pin (pin 3)Library originally added 18 Apr 2008by David A. Mellislibrary modified 5 Jul 2009by Limor Fried (http://www.ladyada.net)example added 9 Jul 2009by Tom Igoemodified 22 Nov 2010by Tom IgoeThis example code is in the public domain.http://www.arduino.cc/en/Tutorial/LiquidCrystal*/// include the library code:#include <LiquidCrystal.h>// initialize the library with the numbers of the interface pinsLiquidCrystal lcd(12, 11, 5, 4, 3, 2);int photo=A15;void setup() {// set up the LCD's number of columns and rows:lcd.begin(16, 2);Serial.begin(9600);pinMode(photo,INPUT);}void loop() {int val=analogRead(photo);int time=millis();while (val<600){Serial.print(time);}do{Serial.print("TIME : ");Serial.println(time);}while(val>600);{Serial.print("READY");}}

author: Balaur
author_rank: Unknown
timestamp: May 04, 2013, 05:54:10 pm
content: Review your code.Can you see the issue here:Code:while (val<600){Serial.print(time);}or here:Code:while(val>600);{Serial.print("READY");}

author: ChrisGreece52
author_rank: Frequent Contributor
timestamp: May 04, 2013, 06:30:00 pm
content: But sometimes when i did not put the semicolon it would not upload the code and when i did it would not work ... anyway ill try to find the mistake and ill get back to you .Thank you

author: mariush
author_rank: Super Contributor
timestamp: May 04, 2013, 06:43:15 pm
content: This is incorrect:Code:while (val<600){Serial.print(time);}do{Serial.print("TIME : ");Serial.println(time);}while(val>600);{Serial.print("READY");}First of all there's a problem with the syntax. The thing your wrote separates into three separate things:Code:while (val<600){Serial.print(time);}Code:do{Serial.print("TIME : ");Serial.println(time);}while(val>600);Code:{Serial.print("READY");}The while in the second block belongs todo { }loop. The ; at the end of the while in the second block should tell you that the third block has no while in front.The C compiler ignores the { } in the third block and simply does that serial.print once.But even if you did all three right, it's still incorrect code.When you do a while () { } or a do { } while (); block of code, you have to make sure what you test in your while can change, aka there's a stop condition and your while or do loop won't continue forever.In your loops, VAL is never re-evaluated, not measured a second time, so your loops will do what's between brackets forever.Here's how the code should be.Have a variable that holds the time when the laser is first detected on the sensor.Keep reading the sensor value for ever.When the value tells you the laser is on for the first time, put the milliseconds value in the first variable.When the value tells you the laser is not on the sensor, check if the laser ever was on the sensor before and if so,Do the difference between the current time and the start time , show the value on the screen, reset the two variables so that when laser goes on everything repeats.If the laser is not on the sensor, say readyAll throughout this, keep in mind that the value of the sensor may be read in the loop 50-100 times a second, so you can't just print ready to serial 50-100 times a second, you'll fill your screen with "Ready" lines. you should add a bit of code that makes sure ready is only printed several times a second, not hundreds of timesHere's some code I came up with, I didn't test it and it may have minor errors like forgetting a ; or something like that, but you should understand what happens. If you don't grab a pen and a paper and go through the code with some test values like 500 800 850 300 for the adc measurement ... and see what the loop does.Code:int time_start = -1; // when the laser is first detected hitting the sensorint time_last = -1; // the time when the laser was not detected hitting the sensorint time_lastready = -1; // when the ready message was last printed on the serialint val=0;int time=0;while () { // do this foreverval = analogRead(photo);time = millis();if ( val > 600 ) { // sensor is hit by laserif (time_start == -1) { // this is the first time the sensor is hit by laser after a measurementtime_start = time; // so put the current time in the variable to remember it}} else { // else from val > 600 so this is done when val is below 600if (time_start != -1) { // was the sensor ever hit by laser before this measurement ? If yes, then let's show how much time the laser was onSerial.print(time - time_start); // print the number of ms between current ms value and time_starttime_last = time; // put in time_last when we last shown on screen the number of ms, so that for a second or so we don't show "READY" on screen, we want people to see the actual ms valuetime_start = -1; // reset the start time , the next time we go through loop we print "READY", if a certain time has passed} else {// this is done when time_start = -1, which happens when we never had the laser hit the sensor, or when we displayed the ms value on screen and reset that value.if ((time - time_last) > 500 ) time_lastready = time; // delay the printing of ready to serial for 500 ms so you can actually see the the measurement.if ((time - time_lastready) > 200 ) { // print "ready" only if 200 ms have past from the last printing of ready to serial port.Serial.print("READY");time_lastready = time; // update the last ready variable so that we won't print the ready message again for 200 ms.}}}}

author: mariush
author_rank: Super Contributor
timestamp: May 04, 2013, 06:59:21 pm
content: Arduino sketches work with C language in the background.The C language expects a ";" at the end of instructions, that tells the language that instruction ends there.So you have to put the ; after, for exampleint value = 0;In that code you wrote, you used two types of loops :while (condition) { some stuff }do { some stuff } while (condition);There's an important difference between these two loop types above.With the first loop, it's possible to never do "some stuff ", for example while (1 >2 ) { value = 5; } <- value = 5; never gets processed because 1 is not bigger than 2.With the second loop, the "some stuff" is done at least ONCE, because the processor only checks if the condition is trueafterit goes through the "some stuff" once. For example do { value=5; ) while ( 1 > 2); will result in value becoming 5 because you only check if 1 is bigger than 2after.In both of the loops you used in your code, you have a problem because they're infinite.While (val > 600 ) {Serial.print(time);}The processor will print the time value forever, because val never changes. In awhile (condition) { stuff}or ado (stuff) while (condition)thestuffis supposed to contain some way to make the condition false, so that eventually the loop stops. In your case, it could be done by reading a new val value from the adc.One more thing...As I explained above, the ; is a special character in C, it tells that the instruction ends there.You havewhile (condition) { do stuff }The C language has some "rules" :1. You don't have to put a ";" after the } and most C compilers don't expect one but will let you put one and not make a fuss.2. You don't have to put a ";" at the end of the instruction right before the } (but it would be nice of you to do it). Some C compilers insist on you putting that ; and you should learn like that.3. You don't have to use { } if the "do stuff" is only one instruction, but you can use them if you want to.So there's several ways to write this while loop :while (value < 600 ) x = 100;<-- this is correct, there's only one instruction so { } are not required.while (value < 600 ) { x = 100;}<-- this is also correct, there's only one instruction so { } are not required but you can use them.while (value < 600 ) { x = 100}<-- this is also correct, ; can be omitted from the end of the instruction right before the } but some compilers don't like it, so you should learn to put the; anyway.while (value<600) ;<-- THIS is also correct, it's like saying while value is less than 600 do nothing, just wait in an infinite loop.while (value<600) {}<-- same as aboveIn your case, you have thedo { stuff } while (value < 600) ; so the while line belonged to the do above, and your last { } had no while in front. The last { } are simply ignored by the compiler.

author: ChrisGreece52
author_rank: Frequent Contributor
timestamp: May 04, 2013, 08:17:00 pm
content: Thanks for this information i have learned a lot from my mistakes and now i am going to read and understand how the correct code works after i read all the information that made my code wrong or some thing that were not needed.

author: ChrisGreece52
author_rank: Frequent Contributor
timestamp: May 04, 2013, 08:30:11 pm
content: Thank you again but as i was watching the code some questions came into my mind.1st why did you setCode:time_start=-1?and i did not got that part.Code:else { // else from val > 600 so this is done when val is below 600if (time_start != -1) { // was the sensor ever hit by laser before this measurement ? If yes, then let's show how much time the laser was onSerial.print(time - time_start); // print the number of ms between current ms value and time_starttime_last = time; // put in time_last when we last shown on screen the number of ms, so that for a second or so we don't show "READY" on screen, we want people to see the actual ms valuetime_start = -1; // reset the start time , the next time we go through loop we print "READY", if a certain time has passed} else {// this is done when time_start = -1, which happens when we never had the laser hit the sensor, or when we displayed the ms value on screen and reset that value.if ((time - time_last) > 500 ) time_lastready = time; // delay the printing of ready to serial for 500 ms so you can actually see the the measurement.if ((time - time_lastready) > 200 ) { // print "ready" only if 200 ms have past from the last printing of ready to serial port.Serial.print("READY");time_lastready = time; // update the last ready variable so that we won't print the ready message again for 200 ms.}some of it make sense to me but some does not .....

author: Rerouter
author_rank: Super Contributor
timestamp: May 04, 2013, 08:40:48 pm
content: just a small thought to tidy it up... those 2 levels look like they clearly sit on either side of half your supply rail (assuming no external reference), now couldn't you use a digital read instead? as most AVR's have schmitt triggers on there inputs, or to get it even more accurate, could use bit-reads which while being less portable are much faster depending on the relative accuracy desired?

author: ChrisGreece52
author_rank: Frequent Contributor
timestamp: May 04, 2013, 08:56:53 pm
content: Quote from: Rerouter on May 04, 2013, 08:40:48 pmWell you assumed right but i use analog inputs only to get more presice values ... correct me if i am wrong.

author: mariush
author_rank: Super Contributor
timestamp: May 04, 2013, 09:02:51 pm
content: It's always a good idea to initialize the variables with something that you know won't happen in real world.In your case, that function millis or whatever is called always gives you the number of milliseconds since your Arduino was started. Obviously, that number will always be positive, but your Integer data type can store a wide range of positive and negative numbers. So -1 is a simple value that I know won't every be returned by that Arduino function.I could have used 0 just the same, because pretty much always a few milliseconds will pass before your program actually starts running.As for the rest, here's the thinking.You want to display on a lcd screen or to a serial port some message.While you wait for the laser to hit the sensor for the first time, or after the laser no longer hits the sensor and you displayed the time, you want to show the message "Ready".When the laser WAS on the sensor and no longer is on the sensor, you know the laser was over the sensor for a period of time so you want to show that period of time.When you output stuff to the serial port, you basically output line by line and you can scroll up and down in the output and see the messages, but if you later replace the serial with a LCD screen, your message will overwrite the previous messages.So my code keeps track of when it last displayed the time and will refuse to print "Ready" for a period of time after that, so that in case you replace the serial output with a LCD screen, it won't overwrite the value you previously shown on screen or write lines on the serial output for some time.Also, everything in this loop happens lots of times a second, could be 50 times a second or hundreds of times a second.Since everything in that infinite loop may be done hundreds of times a second, we don't want to print the "ready" message hundreds of times a second. If we show the time we measured, right away in the next millisecond the LCD screen will be overwritten with Ready, or you'll see lots of "ready" messages on the serial output page.So we keep track of when was the "Ready" message printed and only print "Ready" again when a certain period has passed. We also want to print "ready" only after a small period of time while the time value was displayed on screen or on serial output page.Think about it, your serial output only has 20-50 lines, maybe a bit more, if you print "ready" hundreds of time a second you will only see "Ready" on screen.So here it is again what happens in the program:time_start = -1 means we assume the laser never hit the sensor, no time measurement was done yet, we can print "Ready" on the screen.time_last = -1 means just that we put a default value to this variable, it will be updated only when we actually made a measurementtime_ready = -1 is again just a default value, this keeps track of when "Ready" was displayed last time.Do the following forever :Read the value from the analog pin in "val"Read the number of milliseconds since Arduino runs in "time"Is the value bigger than 600, is the laser hitting the sensor ?If yes, then check if time_start is -1. That time_start is -1 only when there were no measurements done before , or there was a measurement done and time was displayed on screen/serial.Is time_start -1? OK, it means the laser touches the sensor for the first time, so record this time in the variable time_startIf not, it means the laser isn't hitting the sensor.This could mean two things, either1. the laser was on the sensor before and now it isn't anymore and we have to show how much time has passed since we first saw the laser hitting the sensor2. the laser isn't on the sensor and wasn't on the sensor in the previous reading of the analogue pin so nothing happened, we're still waiting for the laser to hit the sensor to start a measurementSo now we take care of the first case.We check if the laser was at some point hitting the sensor before by doing the if (time_start != -1) because we know time_start is only set to that "time" value when the laser hits the sensor. We show the value on the screen (current time - the time stored in time_start) and we update the time_last to the current time, so that the "Ready" message will not be shown for some period and overwrite our time value.Ok, we took care of the first case, now for the second case, where we either shown the measurement on the screen, or we're waiting for the sensor to hit the sensor.When we're here, we only want to show ready on screen or to serial port. But again, since we could be here hundreds of times of second we don't want to spam the serial out or the lcd screen with ready messages.Did enough time pass since we showed the last time value on screen? If not, update the time_lastready to current_time to delay showing the "ready" message. This makes the next test in the followin if always be false, since the time_lastready will be equal to current time, so time - time_lastready will be 0, which is less than 200.Did enough time pass since the last time we showed ready before? We do that by checking the time_lastready variable.If the current time - time_lastready is bigger than 200 ms, then we print "ready" again and update time_lastready to current time so when we go in this big loop again, we don't print ready right away hundreds of times a second.So now we go back to the beginning of the while, and everything is repeated for ever, until you unplug the arduino from powerps. now that i went through the code, there's an error...if ((time - time_last) > 500 ) time_lastready = time; // delay the printing of ready to serial for 500 ms so you can actually see the the measurement.Should be<500 , as in "if less than 500 ms have passed since displaying the time, don't print ready on screen.

author: ChrisGreece52
author_rank: Frequent Contributor
timestamp: May 04, 2013, 10:43:10 pm
content: Quote from: mariush on May 04, 2013, 09:02:51 pmThank you but i got new questions from thisQuestion about the red part : I can tweak the 500 ms value to 1 or eve 2 seconds just to see the reading right?And also you said in one part that i cant find right now ...... that it will start the time when the programm begins or i understood wrong.Also i spoted some minor errors my selfi marked them with green and the part you found to be a mistake as yellow.But the line in which i get an error too is marked with brown.Code:int time_start = -1; // when the laser is first detected hitting the sensorint time_last = -1; // the time when the laser was not detected hitting the sensorint time_lastready = -1; // when the ready message was last printed on the serial[color=green]int photo=A15;int val=0;int time=0;[color=green]void setup(){pinMode(photo,INPUT);}[color=green]void loop(){[color=brown]while () { // do this foreverval = analogRead(photo);time = millis();if ( val > 600 ) { // sensor is hit by laserif (time_start == -1) { // this is the first time the sensor is hit by laser after a measurementtime_start = time; // so put the current time in the variable to remember it}} else { // else from val > 600 so this is done when val is below 600if (time_start != -1) { // was the sensor ever hit by laser before this measurement ? If yes, then let's show how much time the laser was onSerial.print(time - time_start); // print the number of ms between current ms value and time_starttime_last = time; // put in time_last when we last shown on screen the number of ms, so that for a second or so we don't show "READY" on screen, we want people to see the actual ms valuetime_start = -1; // reset the start time , the next time we go through loop we print "READY", if a certain time has passed} else {// this is done when time_start = -1, which happens when we never had the laser hit the sensor, or when we displayed the ms value on screen and reset that value.if ((time - time_last) [color=yellow]< 500 ) time_lastready = time; // delay the printing of ready to serial for 500 ms so you can actually see the the measurement.if ((time - time_lastready) > 200 ) { // print "ready" only if 200 ms have past from the last printing of ready to serial port.Serial.print("READY");time_lastready = time; // update the last ready variable so that we won't print the ready message again for 200 ms.}}}}[color=green]}And the actual error:expected primary-expresion before ")" tokensketch_may05a.ino: In function 'void loop()':sketch_may05a:15: error: expected primary-expression before ')' token

author: mariush
author_rank: Super Contributor
timestamp: May 04, 2013, 11:02:40 pm
content: The arduino may not likewhile () {}Just do this insteadwhile (1==1) {}but anyway... you can probably take it out completely, because Arduino converts thatvoid loop() {}into a while (1==1) { } behind the curtains. So everything inside the loop function will be run for as long as you have the arduino powered for ever.-Double check the code I wrote for paranthesis closing where they should, I basically wrote the source code directly in the forum page, and I don't have an Arduino here to check. But it's pretty basic source code and shouldn't have ridiculous errors.-Oh actually, what you should look for is replacing theintdata type to something bigger, likelong, orunsigned long.The int data type can store a 16bit value, between -32,768 to 32,767 :http://arduino.cc/en/Reference/IntIf you look at millis() function, that function returns the number of milliseconds since Arduino started, which could be a value bigger than 32 thousands (basically a bit more than 30 seconds) :http://arduino.cc/en/Reference/MillisSo you should use something bigger than int, which would be long or unsigned long :http://arduino.cc/en/Reference/Long(though if you use unsigned long, you won't be able to put -1 in variables, just replace -1 with 0 everywhere if you want to use usigned long)- Also yes, you can change that 500 and 200 for bigger numbers, I just used them as example. If you want 1s , use 1000 (milliseconds), basically multiply the number of seconds by 1000 to get milliseconds.Keep in mind the message will be displayed only after that period of time passes, it doesn't show the message "exactly" after that number of milliseconds. Depending on how much time the Arduino needs to go through the loop and read the voltage from the analogue pin, the message may show up a few ms later than the time you set. In your case it doesn't really matter, but I'm just saying it in case you wonder about it.--later edit :QuoteWhat you write in that Arduino editor is your program, which in theory gets compiled into a computer program and "uploaded" into the arduino chip.But when you compile and click to send the program to Arduino, what really happens hidden away from you is that some source code is added to the top of what you wrote and that source runs first and then that source code starts your program which then runs on the Arduino chip.So that Millis() function tells you the number of milliseconds since Arduino started.If you were to make a very simple program, something like this :void loop(){long time = Millis();}but written directly in the language the Arduino hides and simplifies from you, the time variable would be 0, because all the instructions in this program would need maybe 3-5 microseconds , 3 thousands of a millisecond.Since Millis() gives you the number of milliseconds, it would have to give you 0, because 0 milliseconds passed since the Arduino started.But what happens in reality is that before the code you wrote runs on the Arduino, some other code that was added to your program runs and a few milliseconds may pass before your code actually gets the chance to run on the Arduino.So it's very unlikely you'll ever get a 0 as return value for the Millis() function. By the time your code gets a chance to access that function, 1 millisecond probably already passed.You can test that if you want. Simply add in the setup() function something likeSerial.print(Millis());Serial.print(Micros());the Micros() function (http://arduino.cc/en/Reference/Micros) gives more accurate value, it says the number of microseconds (thousands of a millisecond) since Arduino started. You could have fun writing two Serial.print(Micros()); one after another just to see how many microseconds it takes to print something to the serial port.

author: ChrisGreece52
author_rank: Frequent Contributor
timestamp: May 05, 2013, 12:22:28 am
content: Thanks for your help!!! I checked and uploaded the software to the arduino and started experimenting with the code and the values thank you!!!!

author: ChrisGreece52
author_rank: Frequent Contributor
timestamp: May 05, 2013, 12:37:12 am
content: And i thought i will not encouter another mistake .... when i break the beam for several seconds it starts saying READY,READY,READY and i have tweaked the 500 miliseconds to 1 second.... but i think that can be solved fairly easy.Code:else {// this is done when time_start = -1, which happens when we never had the laser hit the sensor, or when we displayed the ms value on screen and reset that value.if ((time - time_last) < 1000 ) time_lastready = time; // delay the printing of ready to serial for 500 ms so you can actually see the the measurement.if ((time - time_lastready) > 200 ) { // print "ready" only if 200 ms have past from the last printing of ready to serial port.Serial.println("READY");time_lastready = time; // update the last ready variable so that we won't print the ready message again for 200 ms.}by tweaking the 200 miliseconds i may get a result .shall i to make it check the value again and if the value is less than 600 (which means that the beam is still broken) then wait another 200 miliseconds to check again.but it the value is greater than 600 (the beam is hitting the photoresistor) then wait 200 miliseconds and then print "READY"but how do i do thatwith an if statement or something else?

author: mariush
author_rank: Super Contributor
timestamp: May 05, 2013, 01:39:54 am
content: Your code does not "wait" 200 milliseconds or 500 millisecondsAll that code in the loop() function is running all the time in your Arduino and probably takes a few milliseconds to run (that's how much time it takes for the ADC conversion to happen and for the data to go out the serial port.So if the whole thing takes let's say 10 ms to happen, then within a second, your loop() function is ran 100 times. The code I wrote just uses the result of that Millis() function to keep track of time, it's like a counter that always go up by some value.With those if's I just make sure a number of milliseconds have passed since the last time the program wrote something on the screen.The 500 is just something that blocks "Ready" from being written on screen ONCE, right after a measurement is completed.The 200 is a delay that happens every time after a ready message.If you don't want to say ready all the time, you can take it out from the loop and make the code say Ready once in the setup() function because that function always runs before the loop() function, then as soon as you print the time you can just print "Ready" again.You could also make it more user friendly by adding a line to say something like "Detected laser, measuring started" at the point where you detect the laser for the first time. This way something changes on the screen and Ready is no longer the last line.I imagined the "ready" message like a sort of hourglass / waiting / standby signal, to tell you that the program is running and that it's frozen, that's why I made it to print all the time, so you can can see loop() makes the code run forever.In the old days, there were such "waiting" or "loading" messages done by writing once "Loading -" and then sending the character code for "cursor left" or "backspace" to position the cursor under the - character or delete it, then write one of these : \ , | , / , - which makes it look like the line rotates.

author: ChrisGreece52
author_rank: Frequent Contributor
timestamp: May 05, 2013, 05:26:27 pm
content: Thank you for everything .... it would be nice to do that \,|,/,- thing