beginner arduino problem - Page 1
Forum section: electronics / general

author: deth502
author_rank: Frequent Contributor
timestamp: January 28, 2014, 10:29:31 pm
content: i tried this on the arduino form and got no explanation.this is my first attempt at anything arduino, so i dont know much.i downloaded the sketch from the net, for a keypad lock circuit. heres my main problem with it. the code is set to 1234. it opens on "4". if you enter xxxxxxx1xxxxxxx2xxxxxx3xxxxxxxx4, it opens. what i want to do is have a code that must be entered exactly, so hitting 12354 would not open it, but as it is, a correct press advances the program 1, while an incorrect presss is just ignored.heres what i got:Code:#include <Keypad.h>char* secretCode = "1234";int position = 0;const byte rows = 4;const byte cols = 3;char keys = {{'1','2','3'},{'4','5','6'},{'7','8','9'},{'*','0','#'}};byte rowPins = {8, 7, 6, 5};byte colPins = {4, 3, 2};Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, rows, cols);int redPin = 9;int greenPin = 10;void setup(){pinMode(redPin, OUTPUT);pinMode(greenPin, OUTPUT);setLocked(true);}void loop(){char key = keypad.getKey();if (key == '*' || key == '#'){position = 0;setLocked(true);}if (key == secretCode){position ++;}if (position == 4){setLocked(false);}}void setLocked(int locked){if (locked){digitalWrite(redPin, HIGH);digitalWrite(greenPin, LOW);}else{digitalWrite(redPin, LOW);digitalWrite(greenPin, HIGH);}}now, when ever i try to put any bit of code anywhere in there, it just bricks it out.i add if key != secretCode position = 0, ive tried else position = 0, anything i try just bricks it out, the correct input does not cause it to go to an open state.today, i tried to add a few lines to see whats going on and tried this:Code:#include <Keypad.h>char* secretCode = "1234";int position = 0;const byte rows = 4;const byte cols = 3;char keys = {{'1','2','3'},{'4','5','6'},{'7','8','9'},{'*','0','#'}};byte rowPins = {8, 7, 6, 5};byte colPins = {4, 3, 2};Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, rows, cols);int redPin = 9;int greenPin = 10;void setup(){ Serial.begin(9600);pinMode(redPin, OUTPUT);pinMode(greenPin, OUTPUT);setLocked(true);}void loop(){char key = keypad.getKey();Serial.println(key);Serial.println(position);delay(500);if (key == '*' || key == '#' ){position = 0;setLocked(true);}if (key != secretCode){position = 0;}if (key == secretCode){position ++;}if (position == 4){setLocked(false);}}void setLocked(int locked){if (locked){digitalWrite(redPin, HIGH);digitalWrite(greenPin, LOW);}else{digitalWrite(redPin, LOW);digitalWrite(greenPin, HIGH);}}every half second it tells me what button is being pressed, and what the value for position is. without the key != command, it works as it did before (incorrect key strokes ignored) but with that line in, i can see that when i press the 1, it goes to position 1 for one count (1/2 sec) and then back to 0, which is why it is not doing anything, it is never advancing to "4"my first thought was that its counting no key press as a != and is resetting it to 0, but i was reassured that the char key = keypad.getKey(); command was waiting for a key press to advance, so a "non-press" wold not be counted.any ideas on what im missing/dong wrong here?

author: sleemanj
author_rank: Super Contributor
timestamp: January 28, 2014, 10:32:14 pm
content: Code:if (key == secretCode){position ++;}else{position = 0;}Should work.

author: deth502
author_rank: Frequent Contributor
timestamp: January 28, 2014, 10:34:37 pm
content: another thing i found interesting, when the program works (first version) iv noticed that the "position" variable, once it hits 4 and opens, it stays at 4 for one count (1/2 sec) then to 5 for one count, then settles at 6.why would the "position" keep advancing like that?

author: deth502
author_rank: Frequent Contributor
timestamp: January 28, 2014, 10:39:51 pm
content: Quote from: sleemanj on January 28, 2014, 10:32:14 pm

author: dannyf
author_rank: Super Contributor
timestamp: January 28, 2014, 10:46:58 pm
content: QuoteTwo possibilities:1) your code; or2) act of God.

author: deth502
author_rank: Frequent Contributor
timestamp: January 28, 2014, 10:58:49 pm
content: Quote from: dannyf on January 28, 2014, 10:46:58 pmim assuming its 1, but i dont know what part of the code is telling it to do that, hence the question. if 2, id like to know what prayer i need to recite to stop this.

author: dannyf
author_rank: Super Contributor
timestamp: January 28, 2014, 11:11:24 pm
content: QuoteThe part that increments it does that.QuoteC 101.

author: baljemmett
author_rank: Unknown
timestamp: January 29, 2014, 12:15:14 am
content: Quote from: deth502 on January 28, 2014, 10:34:37 pmIn fact, answering that will also answer your first question about why it keeps going back to 0 when you make your change with the 'else position = 0'.Of course, you'll learn more (and feel better about it, trust me!) if you work the answer out yourself, so maybe it's best to just give you a little nudge in the right direction - the secretCode that you're testing against is a string. How are strings represented/stored in C?

author: meerweten
author_rank: Contributor
timestamp: January 29, 2014, 08:40:23 am
content: i don't know if its part of the keypad program but i think you miss a waitloop for a new keypress.

author: deth502
author_rank: Frequent Contributor
timestamp: January 29, 2014, 08:53:38 pm
content: Quote from: baljemmett on January 29, 2014, 12:15:14 amok, all i know is what i got from the arduino reference pagehttp://arduino.cc/en/Reference/HomePagewhat i found is that any string will have a null character, and arduino will include one if you dont. im not sure if thats what you were getting at, but thats all i found.that kind of makes sence as to why the position state would advance past 4, but 1 null character would advance it to 5, not 6? and i cant see how that would tie into my resetting to zero problem.is ther a better resource that i should be reading?

author: mc
author_rank: Regular Contributor
timestamp: January 29, 2014, 10:02:18 pm
content: Since I've got nothing better to do, here's some hints for the appropriate bits of code.Code:void loop(){char key = keypad.getKey();First up, you should really consider what value is actually returned by getKey(). It always returns something, even if no key has been pressedCode:Serial.println(key);Serial.println(position);delay(500);Learn about non-blocking delays.delay(n) is blocking.Code:if (key != secretCode){position = 0;}So if key doesn't happen to equal the whatever is stored in the next code position, do you really want to reset the counter?(hint - see what I said above about getKey() always returning something)Code:if (key == secretCode){position ++;}Combine with the hint above, and what others have said about how char arrays are stored.

author: sleemanj
author_rank: Super Contributor
timestamp: January 29, 2014, 11:15:53 pm
content: I think you are using the "Keypad" library for Arduino, and I see in your code you are using getKey(). Please read the details for the functions.http://playground.arduino.cc/Code/Keypadchar getKey()Returns the key that is pressed, if any.This function is non-blocking.char waitForKey()This function will wait forever until someone presses a key. Warning:It blocks all other code until a key is pressed.That means no blinking LED's, no LCD screen updates, no nothing with the exception of interrupt routines.

author: deth502
author_rank: Frequent Contributor
timestamp: January 30, 2014, 12:02:24 am
content: Quotethis is what i was wondering, and what i was thinking the problem was, but i was assured by someone on the arduino forums that this was not the case and this was fine.Quotesee reply above. i think this is what i am missing/needing. yes, it is the keypad library from the arduino site. i didnt notice any documentation for it when i downloaded it. imgoing to go read that as soon as i finish my reply here, thanks!Quotethe only reason that was put there was because i was writing the info to the debug terminal, i had to slow it down to be able to see the info without it flying by. im sure it dosent mesh well with the program, but after debugging is complete, it will be deleted anyway.Quoteright, like i said, i was told that that command waited for a button press. again, i was suspicious of this being the problem, but dont know enough to be able to tell.Quotethis part i still dont get. going to read what exactly the keypad library does now, hopefully, that will shed some light on this.

author: deth502
author_rank: Frequent Contributor
timestamp: January 30, 2014, 12:10:05 am
content: Quote from: sleemanj on January 29, 2014, 11:15:53 pmyup, thats the page i downloaded from. damni stopped scrolling down when i got to the download link, didnt know they had all the functions down below. dumb mistake on my part.

author: deth502
author_rank: Frequent Contributor
timestamp: January 30, 2014, 12:42:45 am
content: perfect!!!its working just how i wanted it to now!one last question....how well does the arduino handle exceptionally long pauses? ie, im thinking to add some code that if say, 10 incorrect keys are pressed, it would lock out for 5-10 minutes with a delay 300000-600000 command.

author: Kremmen
author_rank: Super Contributor
timestamp: January 30, 2014, 06:45:12 pm
content: The Arduino millis() function returns the runtime counter count in milliseconds from last reset. The counter will overflow after some 50 days of continuous runtime so it can be used for any "normal" delays.Just read the millis() into a variable, add to it the number of milliseconds you wish to wait (3 600 000 ms per hour). Compare millis() to the variable and when it is larger you know the period has elapsed. Easy, neh?

author: dannyf
author_rank: Super Contributor
timestamp: January 30, 2014, 06:59:55 pm
content: QuoteWhat happens when millie() itself isn't overflowing but millie() + desired time internal is?You will see why those comparisons are done in a particular way.

author: Kremmen
author_rank: Super Contributor
timestamp: January 31, 2014, 06:44:31 pm
content: Tell me about it. But surely you noted that millis() overflows after some 50 days so you need to worry about it only if your application is a long-running one. Most Arduino code isn't. But if it is anyway, then simple modulo arithmetic will take care of counter overflows. Not a problem.

author: zapta
author_rank: Super Contributor
timestamp: February 06, 2014, 07:17:25 pm
content: Quote from: dannyf on January 30, 2014, 06:59:55 pmIf I recall twos complement correctly, Dt = T2 - T1 gives the correct time diff, assuming the real interval is less than one cycle (50 days).I used this assumption in one of my programs so please correct me if I wrong.(Using same uint size for all values)

author: linux-works
author_rank: Super Contributor
timestamp: February 06, 2014, 08:11:41 pm
content: Quote from: deth502 on January 28, 2014, 10:58:49 pm"arduino is NOT magic! there are fundamental technical reasons why one must sacrifice a young goat to the SPI bus every now and then."(trotting out an oldie but goodie. anyone catch the ref?)

author: psycho0815
author_rank: Regular Contributor
timestamp: February 07, 2014, 10:32:17 am
content: i'd like to go back to your observation, that after you entered the right code position gets up to 6 before it stops, since no one has commented on it and i think it's something worth knowing.As someone already said it has to do with how c stores strings. But it also has todo with what the getKey() funtion returns if no key is pressed and with how c keeps track of your memory or rather how it doesn't.As has been said in c strings are terminated by '\0', but thats just a convention c itself doesn't give a crap. As a programmer it's your responsibility to keep track of that.So after you entered your secretcode position is 4 and the value of secretcode is '\0' which is the same value getKey() returns when there's no key pressed so it increments position to 5. your string is over now, but as i said, that's your responsibility c doesn't care so it keeps going. And what is stored at secretcode?Well '\0' apparently but why? Okay the way arrays work in c is that secretcode works the same as *(secretcode+(n*sizeof datatype)). What that means is that it takes the memory address stored in secretcode, which is where your first item is stored, and it adds to that n times the size of your datatype in bytes, in this case 1.So what secretcode does is it takes that memory address and adds 5 to that. it doesn't care that your string is already over it just gives you whatever is stored at the next address. And what is stored there? Well position is, because you declared the variable right after your array. But position is 5 at this point so why is there a'\0' at that address? Because in arduino ints have a size of 16bit so the value 5 is stored as 0x0005. And 00 is the ascii code for '\0'. And at position 6 there's your actual positionvalue, so it doesnt match '\0' anymore.That's why pointers are so evil, that sort of thing can really ruin your day. Imagine what would have happend is you had done something like secretcode = 'x'.

author: deth502
author_rank: Frequent Contributor
timestamp: February 07, 2014, 11:35:17 am
content: i *think* thats what i said before because thats what i read on teh arduino site reguarding the storage of strings, but i didnt fully understand it. but with that explanation, it is now crystal clear! thank you!