Simple Arduino code rookie question - Page 1
Forum section: electronics / general

author: IvoS
author_rank: Frequent Contributor
timestamp: May 25, 2015, 01:50:05 pm
content: Using ATTiny85,I am trying to turn ON 3 LEDs in sequence with 1s delay when I press the button. When I press the button again, I want to turn all 3 LEDs OFF simultaneously. And then, the cycle repeats again.This is what I have: When I press the button for the first time, the initial sequence turning LEDS ON with 1s delay starts OK. But then, I can not turn LEDs OFF when I press the button again. Any help? I am not sure if I am supposed to write "delay(1000)" in setMode. Thanks.Code:const int LED1 = 0;const int LED2 = 1;const int LED3 = 2;const int button = 3;boolean lastButton = LOW;boolean currentButton = LOW;int ledMode = 0;void setup (){pinMode (LED1, OUTPUT);pinMode (LED2, OUTPUT);pinMode (LED3, OUTPUT);pinMode (button, INPUT);}boolean debounce (boolean last){boolean current = digitalRead (button);if (last != current){delay (5);current = digitalRead (button);}return current;}void setMode (int mode){if (mode == 1){digitalWrite (LED1, HIGH);delay(1000);digitalWrite (LED2, HIGH);delay(1000);digitalWrite (LED3, HIGH);}else if (mode == 2){digitalWrite (LED1, LOW);digitalWrite (LED2, LOW);digitalWrite (LED3, LOW);}else{digitalWrite (LED1, LOW);digitalWrite (LED2, LOW);digitalWrite (LED3, LOW);}}void loop (){currentButton = debounce(lastButton);if (lastButton == LOW && currentButton == HIGH){ledMode++;}lastButton = currentButton;if (ledMode == 2 ) ledMode = 0;setMode (ledMode);}

author: senso
author_rank: Frequent Contributor
timestamp: May 25, 2015, 01:57:36 pm
content: Switch this two:if (ledMode == 2 ) ledMode = 0;setMode (ledMode);And them think about what you are doing to that ledMode variable BEFORE it is passed to the setMode function.

author: IvoS
author_rank: Frequent Contributor
timestamp: May 25, 2015, 02:40:42 pm
content: I tried that, unfortunately it doesn't work. I am doing something stupid.

author: zapta
author_rank: Super Contributor
timestamp: May 25, 2015, 03:08:33 pm
content: Try to add print statements at key points. It will help you to understand what's going on.

author: m98
author_rank: Frequent Contributor
timestamp: May 25, 2015, 04:52:30 pm
content: Well, your Arduino executes the setMode() function in one piece and won't call the loop() function until finished. To respond to the button while the LED blinks, you need to useinterrupts.

author: Muxr
author_rank: Super Contributor
timestamp: May 25, 2015, 05:10:22 pm
content: I am not convinced that " if (lastButton == LOW && currentButton == HIGH)" is ever satisfied the second time. As I don't see how lastButton gets set to LOW on the 2nd push.In your loop change your "lastButton = currentButton;" to "lastButton = digitalRead (button);". Just to make sure it's actually being read from the button instead of getting stuck in a logical false state in the debounce function.Use serial for debugging if you can:Code:Serial.println("sending to serial..");

author: SL4P
author_rank: Super Contributor
timestamp: May 25, 2015, 05:13:05 pm
content: This is a really good learning project... don't rush it for someone else to hand you the answer on a plate.The ideas you are trying to use are all valid, but there are some fundamental oversights which will help you learn.As Zapta said - add some debugging print statements to see what your code is actually doing.it should not take long to figure out.Good luck. a great next step after the blinking LED "

author: IvoS
author_rank: Frequent Contributor
timestamp: May 25, 2015, 06:16:30 pm
content: Thank you. It kind of works, but I have to hold the button down for 2 sec to turn those LEDs OFF. Sometime 2 seconds, sometimes it turns OFF instantly. I think it gets stuck for 2x delay(1000); to wait for the "setMode" to finish? I thought the "void setMode" is set up only once when ATTiny is powerd up whereas void loop () runs over and over again.....

author: SL4P
author_rank: Super Contributor
timestamp: May 25, 2015, 06:20:44 pm
content: ok, so what happens if you press the button while in, or just about to enter one of the the delay() calls?What if it just happens elsewhere?

author: hneve
author_rank: Regular Contributor
timestamp: May 25, 2015, 06:52:31 pm
content: I love pseudokode.I would think like this:? Is button pressed? Is timestamp set.If set then clear and turn leds off.Else set timestamp from millis.? Is time since timestamp 1 sec.Then led 1 on.........? Is time 3 sec.Then led 3 on.This is just a Idea.... I might have thought wrong...

author: SL4P
author_rank: Super Contributor
timestamp: May 25, 2015, 07:03:08 pm
content: OP once you have this working as you want it to...Rewrite it without delay() -- that will teach you a lot about realtime, async event programming (the button).That will give you a whole new insight to 'better' code development. and structure. This should be the mandatory second lesson after the blinking LED ,delay() - in most incarnations - is a 'blocking' function - which inhibits anything else happening for the duration of the delay.

author: m98
author_rank: Frequent Contributor
timestamp: May 25, 2015, 08:23:21 pm
content: Quote from: IvoS on May 25, 2015, 06:16:30 pmAs you call setMode() in loop(), it gets called in a ...loop. And because the uC waits for setMode() to complete before doing something else, it can't check the state of the button before the blink sequence is finished. So you could use interrupts or non-blocking code. First ones interrupt the uC from whatever is happening and call a handler, where you could for e.g. change the mode and call your setMode() function again. Non-blocking code would be the more elegant solution, where @hneve posted a good example.

author: zapta
author_rank: Super Contributor
timestamp: May 25, 2015, 08:25:34 pm
content: Quote from: SL4P on May 25, 2015, 07:03:08 pm+1Delay is good for initial blinky but is a dead end otherwise.After you get this reasonably working start to learn how to program with state machines (a fancy word) and polling instead of blocking delay. You can easily model it as an arbitrary number of arduinos running on the same MCU, one to track the button events, one to control the overall state, one to blink Leeds, etc. All without having to use interrupts.Delay is not your friend.

author: IvoS
author_rank: Frequent Contributor
timestamp: May 25, 2015, 09:06:51 pm
content: Quote from: m98 on May 25, 2015, 08:23:21 pmI don't need to use the button in the middle when LEDs are sequencing. So I kind of understand what you wrote about it can't check the button before sequence is finished. The problem alone is to turn OFF all 3 LEDs after they been turned ON.But you are right. I tried to shorten the delay to delay(200) between digitalWrite (LED1, HIGH) etc., and the button responded much quickly to turn LEDs OFF. It must be pressed and held down until it turns OFF.If I write the code without delays for lets say 8 modes, every button press = next mode, then, there is no problem. So the code structure written like this is no good for this task.I have a book "Exploring Arduino" from Jeremy Blum, but there are no good examples on this kind of thing. Just a simple examples on digital read write, sensors etc. but very basics on each topic. So, I don't know where to look, tried google, no luck.

author: hneve
author_rank: Regular Contributor
timestamp: May 25, 2015, 09:11:18 pm
content: Here is some reading for you:http://playground.arduino.cc/Code/AvoidDelay

author: SL4P
author_rank: Super Contributor
timestamp: May 25, 2015, 09:32:19 pm
content: last hint:write button code that does what you want, then wrap the LEDs around that.We're not trying to be mean, and you are obviously getting the idea from your most recent attempts. The essence is that the LEDs are a consequence of the button press, so the button is more important than the LEDs.Imagine you are developing a bomb detonator... press to 'arm' then press again to stop the countdown... It won't work so well if the bpmb goes off while you're waiting!The state-machine sounds complicated, and often the explanation makes it sound that way too... Just think of a counter that increments at each state of operation... idle, press, LED1, LED2, LED3... etc.In this simple example, one state will be unique (idle)... waiting for something to start the ball rolling, and then to sequence through the remaining 'states'. Your second button press will clear the runtime conditions, and revert to that first idle condition.Even with this minimal example, there are a number of options you can consider... eg whether to stop the sequence immediately 'mid-LED' or wait for the current state to complete. This would mean 'catching' the second press, but holding the event as 'pending' until other condition are met...This discussion can go on forever. The methodology, you *must* master timing and asynchronous events before your code is worth talking about!

author: IvoS
author_rank: Frequent Contributor
timestamp: May 25, 2015, 10:14:38 pm
content: Quote from: hneve on May 25, 2015, 09:11:18 pmThis is helpful, thank you.

author: Dragon88
author_rank: Regular Contributor
timestamp: May 26, 2015, 03:02:32 am
content: Here's some code I wrote that does what you want (I think). I tested it on an Uno and it works fine:Code:#define redLED 2 //define IO#define greenLED 3#define blueLED 4#define button 5boolean lightsOn = false; // state variablesint whichLED = 2;int counter = 0; // main countervoid setup(){pinMode(redLED, OUTPUT); // set up IOpinMode(greenLED, OUTPUT);pinMode(blueLED, OUTPUT);pinMode(button, INPUT);}void loop(){if (digitalRead(button) == LOW) // The button is pressed, handle it{delay(200); // debounce and delaylightsOn = !lightsOn; // toggle stateif (lightsOn == false) // turn LED off and clean up{counter = 0;digitalWrite(whichLED, LOW);whichLED = 2;} else { // Or if we are activating LEDsdigitalWrite(whichLED, HIGH); // Turn first LED on to start}}if (lightsOn == true) // Manage LED state{counter++; // Increment counterif (counter >= 1000) // ~ 1 second has passed{ // So increment LED statecounter = 0;digitalWrite(whichLED, LOW); // Don't forget to turn old LED offwhichLED++;if (whichLED >= 5) // Don't let whichLED go to invalid statewhichLED = 2;digitalWrite(whichLED, HIGH); // Turn new LED on}}delay(1); // 1 ms delay for 1000 count = ~ 1 second}I do believe in figuring it out yourself, but I also know from teaching people that an example is worth a thousand words. Now this is very quick, inefficient code. There are a thousand ways to do things and this is just one. The timing is only approximately 1 second per LED (do you see why?) and it ties up the entire microcontroller from doing other things. But you can modify and grow this code into something much better.Notice the structure of the main loop. The LED doesn't really get turned on until the end. The entire first part of the loop is figuring out what state we are in, handling the button if it's pressed, and cleaning up as necessary. Once we know what state we should be in, acting on the state is too easy. Also notice that by using a counter and avoiding excessive delays, we can make the button far more responsive. Debouncing (really just delaying while the user removes their finger) becomes very important though with it being checked so frequently. There are far better ways to debounce. But this type of debounce also adds a "feature" or alternate mode of sorts, test it and see how.Good luck. Make sure you understand this code fully, modify it, and make it your own.

author: SL4P
author_rank: Super Contributor
timestamp: May 26, 2015, 03:18:04 am
content: Dragon88 is right, in giving some basic ideas to push you along...Another 'feature' you can might become aware of in this type of operation is a 'long press'... e.g hold for 3-secs to clear and reset some other output - buzzer, a cycle counter or whatever...keep us posted!

author: obiwanjacobi
author_rank: Super Contributor
timestamp: May 26, 2015, 01:20:54 pm
content: You can imagine how readable your code gets if you would add a couple of more buttons and a couple of more functions to perform.That would be a good next step to solve. How to manage you code readability/maintainability with increased complexity...?For instance think of how a robot main loop would look. How would all the sensor information interleave with all the processing?Don't feel bad if you don't know, not a lot of people do it right in my view (no using a real-time os with multi threading is not the way to go on a tiny mcu).

author: hneve
author_rank: Regular Contributor
timestamp: May 26, 2015, 01:24:11 pm
content: I remember once I used the watchdog timer to poll the buttons. A fun experiment, worked fine thou.

author: obiwanjacobi
author_rank: Super Contributor
timestamp: May 26, 2015, 01:39:53 pm
content: Quote from: hneve on May 26, 2015, 01:24:11 pmYou have a good point though. I think that interrupts are the secret to making your code 'multi-threading' on MCUs. Think about it, it is hardware supported and has minimal overhead (check the compiled assembler code to make sure).You have to change how you think about your code - which is hard for most.There is also another (software) option that is not known to many. It has to do with a strange construction you can do with a switch statement... (see Task.h in my library)

author: retrolefty
author_rank: Super Contributor
timestamp: May 26, 2015, 08:44:03 pm
content: It's essential when programming microcontrollers to understand the difference between 'blocking' functions and 'non-blocking' functions and how they can or might effect your application coding. A simple blocking function like delay() can be used in many cases without side effects but other times it can be a deadly bug. There can be many ways to structure your code to avoid such problems but does take understanding of the problem and how best to deal with it.

author: IvoS
author_rank: Frequent Contributor
timestamp: May 26, 2015, 09:43:55 pm
content: Thank you "Dragon88 "so much and all of you guys as well for helping me!Using "Dragon88" code, I re-arranged few things and I finally have what I wanted! It is a one time sequence:LED1 ON, delay 1sec, LED2 ON, delay 1 sec, LED3 ON.I didn't involve all of you into this small project just for fun to blink LEDs!This is a start up (turn ON) sequencer for my audio amplifier. LEDs will get replaced with:- relay (to release bleeder resistors),- opto coupler (to turn POWER (triac) ON)- relay (to bypass inrush current limiting resistor)I am also planning to use 2 remaining pins on ATTiny85 for LM35 temperature sensor to sense an overheat and another pin for overheat shut down.So, many thanks again.I may still do some tweaks on that code later as I would like to have a different (uneven) time values. I know I can just change the counter value to different value but it always gives me the same delay between LEDs.Here is the final code:Code:#define redLED 0 //define IO#define greenLED 1#define blueLED 2#define button 3boolean lightsOn = false; // state variablesint whichLED = 0;int counter = 0; // main countervoid setup(){pinMode(redLED, OUTPUT); // set up IOpinMode(greenLED, OUTPUT);pinMode(blueLED, OUTPUT);pinMode(button, INPUT);}void loop(){if (digitalRead(button) == LOW) // The button is pressed, handle it{delay(200); // debounce and delaylightsOn = !lightsOn; // toggle stateif (lightsOn == false) // turn LED off and clean up{counter = 0;digitalWrite(redLED, LOW);digitalWrite(greenLED, LOW);digitalWrite(blueLED, LOW);whichLED = 0;} else { // Or if we are activating LEDsdigitalWrite(whichLED, HIGH); // Turn first LED on to start}}if (lightsOn == true) // Manage LED state{counter++; // Increment counterif (counter >= 1000) // ~ 1 second has passed{ // So increment LED statecounter = 0;digitalWrite(whichLED, HIGH); // Don't forget to turn old LED offwhichLED++;if (whichLED >= 3) // Don't let whichLED go to invalid statewhichLED = 3;digitalWrite(whichLED, HIGH); // Turn new LED on}}delay(1); // 1 ms delay for 1000 count = ~ 1 second}

author: zapta
author_rank: Super Contributor
timestamp: May 27, 2015, 02:23:51 am
content: This code is complicated.

author: Psi
author_rank: Super Contributor
timestamp: May 27, 2015, 07:12:10 am
content: Arduino should rename delay() to. GoAwayCoverYourEyesAndCountTo()It would make things more obvious to noobs and the length would make people not want to type it out and instead use timers

author: Dragon88
author_rank: Regular Contributor
timestamp: May 27, 2015, 11:02:40 am
content: Quote from: IvoS on May 26, 2015, 09:43:55 pmIf that's all you need to do, you can simplify the code quite a bit. I thought you wanted it to cycle through and repeat while waiting for the button press to turn them off.i.e.Code:for (int i = 0; i <= 2; i++) ;For pins 0 through 2{digitalWrite(i, HIGH);delay(1000);}Run that when the button is pressed, then just wait for another button press and turn everything off.

author: IvoS
author_rank: Frequent Contributor
timestamp: May 27, 2015, 09:31:03 pm
content: Thank you Dragon88, I tried that and it also works. But once again, delay is my enemy. If I press and hold the button down, it rolls over the "delay(200)" button debounce function and the loop goes marry go round. I will have to figure out a different debounce function for the button so I can eliminate "delay()" in that loop.

author: Dragon88
author_rank: Regular Contributor
timestamp: May 28, 2015, 02:57:41 am
content: If you want to be able to hold the button down, there are plenty of ways to do that. You could start a counter, set for 3 seconds equivalent or whatever you want. Then when you check for another button press, also check that counter to see if it has reached zero. You could also flip a boolean and have some future condition that flips it back, i.e. the last LED gets turned on in the sequence. Again, compare against that boolean when checking for a "turn off" button press to see if it should be allowed yet.

author: zapta
author_rank: Super Contributor
timestamp: May 28, 2015, 04:20:37 am
content: For several months I am toying with the idea of writing an article about simple multi tasking with Arduino that will target beginners. Something along these lines:Each task has two core methods, setup() and loop(). There are several options for implementing tasks, e.g. classes, namespaces, or name prefixes. With the name prefix approach a task may look like// ----- button task... some button state variables// ---- Core functionsvoid button_setup() { ... }void button_loop() { ... }// ---- API functionsboolean button_isPressed() {} // post debouncingboolean button_consumeClickEvent() { }boolean button_consumeLongPressEvent() { }// -----and then the main will look likevoid setup() {button_setup();task2_setup();task3_setup();}void setup() {button_loop();task2_loop();task3_loop();}Some useful library tasks will be timers, debouncers, leds (on, off, blink, etc), serial line readers, and buttons (with debouncers and event detection), and the examples will include a few state machine based apps such as this one.I think this can be made simple enough for beginners to understand and follow.Here are a few examples from a previous projecthttps://github.com/zapta/power-monitors/blob/master/pmon_3v8/arduino/button.hhttps://github.com/zapta/power-monitors/blob/master/pmon_3v8/arduino/passive_timer.hhttps://github.com/zapta/power-monitors/blob/master/pmon_3v8/arduino/byte_debouncer.hhttps://github.com/zapta/power-monitors/blob/master/pmon_3v8/arduino/action_led.h

author: obiwanjacobi
author_rank: Super Contributor
timestamp: May 28, 2015, 09:31:40 am
content: For more complex tasks, you'll need a statemachine per task to keep track of what you were doing and what the next step (state) will be...

author: hamster_nz
author_rank: Super Contributor
timestamp: May 28, 2015, 08:45:25 pm
content: Quote from: obiwanjacobi on May 28, 2015, 09:31:40 amWouldn't you do the FSM inside each task?One really simple and nifty thing would be able to schedule tasks for later execution. Maybe have the return code from the "loop()" indicate how many milliseconds to wait until it is activated again. Anybody who returns 0 can just fight it out for whatever CPU cycles are left....

author: zapta
author_rank: Super Contributor
timestamp: May 29, 2015, 01:09:18 am
content: Quote from: hamster_nz on May 28, 2015, 08:45:25 pmFor most beginners programs, a simple timer check in the task's loop () is good enough.The main point is having those small state machines in the tasks as you pointed out.

author: obiwanjacobi
author_rank: Super Contributor
timestamp: May 29, 2015, 05:40:58 am
content: Quote from: hamster_nz on May 28, 2015, 08:45:25 pmI thought I said thatI check the time at the start of each loop and use that to determine if specific Tasks waiting for a certain period are up for execution yet when they come to check.The state machine in my library is implemented by a switch statement and a private var (hidden behind some macro's). This is one of the nicest ways I was able to discover to do cooperative multi tasking with very low overhead. It allows you to write code like this (template classes):Code:Task_Begin(Execute){while(true){Task_YieldUntil(DelaysT::Wait(BaseT::getId(), Timeout));BaseT::OnTimeout();}}Task_Endprivate:int _task;This is a part of the TimeoutTask in my library. The Task_ macros implement the switch statement. DelaysT::Wait is a way to have your task wait for a certain period. All you have to do is call the Execute method (of this class) from the loop() repeatedly. No, that while(true) loop will not hang your program - it's magic!

author: zapta
author_rank: Super Contributor
timestamp: May 29, 2015, 06:02:22 am
content: Quote from: obiwanjacobi on May 29, 2015, 05:40:58 amCan you explain the semantic of this code? (it doesn't matter how it's implemented).Can the task consider other inputs or events while it is delaying?

author: obiwanjacobi
author_rank: Super Contributor
timestamp: May 29, 2015, 06:52:44 am
content: DelayT::Wait returns a bool to indicate if the timeout specified has expired. In the main loop DelaysT is fed the current (delta) time. It maintains a list of waiting tasks (by Id) and counts each task down.The Task_YieldUntil will exit the Execute method if the wait is not over yet. If the wait is over, the Execute method continues and calls the OnTimeout() method implemented by the base class (BaseT is a template parameter used as base class).Then the while(true) loop takes it all to the top and the wait starts again.The Execute method is called in the loop() function where other Task-methods can be called in sequence. Each task-method will perform a short/small piece of code and the exit again from its method (using the Task_Yield macros).You could have multiple Timeout Tasks all doing different Timeout values blinking leds on different pins.More?

author: IvoS
author_rank: Frequent Contributor
timestamp: May 30, 2015, 11:01:01 pm
content: So, I had more time to play with the code to take the "delay()" completely (except 1ms at the end) out of "debouce" function and replaced it with debounce function I used from Jeremy's book. That works exactly as I want it. The button will execute(change the statement) just one time when pressed and held down. Unlike it was going in circles before.I might give it more tweaks later, time permitted.Thank you guys for helping me.Code:#define redLED 0 //define IO#define greenLED 1#define blueLED 2#define BUTTON 3boolean lightsOn = false; // state variablesboolean lastButton = LOW; // Variable containing the previous button state.boolean currentButton = LOW; // Variable containing the current button state.int whichLED = 0;int counter = 0; // main countervoid setup(){pinMode(redLED, OUTPUT); // set up IOpinMode(greenLED, OUTPUT);pinMode(blueLED, OUTPUT);pinMode(BUTTON, INPUT);}/** Debouncing function* Pass it to previous button state,* and get back the current debounced button state.*/boolean debounce (boolean last){boolean current = digitalRead (BUTTON); // Read the button stateif (last != current) // if it's different...{delay (10); // wait 10mscurrent = digitalRead (BUTTON); // read it againreturn current; // return the current value.}}void loop (){currentButton = debounce (lastButton); // read debounced stateif (lastButton == LOW && currentButton == HIGH) // if it was pressed...{lightsOn = ! lightsOn;} // toggle the LED valuelastButton = currentButton; // reset button valuedigitalWrite (whichLED, lightsOn); // change the LED stateif (lightsOn == false) // turn LED off and clean up{counter = 0;digitalWrite(redLED, LOW);digitalWrite(greenLED, LOW);digitalWrite(blueLED, LOW);whichLED = 0;} else { // Or if we are activating LEDsdigitalWrite(whichLED, HIGH); // Turn first LED on to start}if (lightsOn == true) // Manage LED state{counter++; // Increment counterif (counter >= 1000) // ~ 1 second has passed{ // So increment LED statecounter = 0;digitalWrite(whichLED, HIGH); // Don't forget to turn old LED offwhichLED++;if (whichLED >= 3) // Don't let whichLED go to invalid statewhichLED = 3;digitalWrite(whichLED, HIGH); // Turn new LED on}}delay(1); // 1 ms delay for 1000 count = ~ 1 second}

author: IvoS
author_rank: Frequent Contributor
timestamp: May 30, 2015, 11:33:50 pm
content: Quote from: zapta on May 28, 2015, 04:20:37 amI think the most difficult part for beginners it to understand the raw basic structure.When do I use } ? Do I have to use a "{" before "for" or "else" ?......I can picture the task in my head but even though I write it down on piece of paper in a simple way before I begin to write the actual code, it won't help me much later anyway. How do I even begin when I don't know things like control structures, data types and further syntax? Some of those I have never seen before and have no clue what they mean.Now, there are conversions, variable scope & qualifiers.... I don't even want to go further. I couldn't compile the code because of one crazy "}"There are so many combinations, it's just not easy for beginner. It took me a while just to wrap my head around the debounce function.....What works the best for me are examples, so I can see the actual working structure that can be modified.But that is not programming any more, is it ?

author: Dragon88
author_rank: Regular Contributor
timestamp: May 31, 2015, 02:49:34 am
content: I firmly believe in learning programming with the aid of examples. Imagine trying to learn how to drive without ever having seen a car driven by someone else. It would seem completely strange and perhaps impossible, because you don't know the process AND you don't know what the end result should look like. But with an example, you have a context in your mind for what you need to do. Granted, after a certain point you should crossover and start creating original code on your own, but the first step is learning the building blocks and mastering the basics from good instruction and good examples.

author: obiwanjacobi
author_rank: Super Contributor
timestamp: May 31, 2015, 05:58:26 am
content: But before you can really drive, you have to learn the traffic rules - same with coding: you have to know the syntax of the language of choice. If you still struggle with the '{' and the like, you need to learn that. If that stuff is automatic (enough) than you can focus on the parts that matter (the logic you wrote down on a piece of paper)...

author: SL4P
author_rank: Super Contributor
timestamp: May 31, 2015, 06:03:05 am
content: it's that darned single missing semicolon or curly brace...nested deep inside a hundred lines of new code!Comment out huge chunks until it jumps out at you as the most obvious error in the world!!

author: zapta
author_rank: Super Contributor
timestamp: May 31, 2015, 11:56:16 am
content: Quote from: IvoS on May 30, 2015, 11:33:50 pmThere is some kerning that you must go through but if different functionalities are decoupled and separated from each other is easier to understand. This is actually how the pros can handle complex programs, by breaking them to small and simple chunks.The button read/denounce function is a good example for such separation. BTW, I wouldn't even require the 'last' argument.Anyway, good job on being (almost) delay free. Stay clean

author: zapta
author_rank: Super Contributor
timestamp: May 31, 2015, 12:00:31 pm
content: Quote from: SL4P on May 31, 2015, 06:03:05 amSome tools are better than other providing useful error messages.

author: IvoS
author_rank: Frequent Contributor
timestamp: June 07, 2015, 01:28:04 pm
content: Guys, I need your help again, please.After I successfully implemented LM35 temperature sensors to my code for overheat shut down , I am kind of stuck on one more task I would like to add. When LM35 temp sensor shuts down all LEDs (this works OK), I want to disable the push BUTTON if (val > LOWER_BOUND). I tried to add some code at the very bottom but no luck. As it is right now with "do" and "while", the button gets disabled but never gets enabled again.Code:#define redLED 0 //define IO#define greenLED 1#define blueLED 2#define BUTTON 4#define TEMP 3const int LOWER_BOUND = 53;const int UPPER_BOUND = 56;int val = 0;boolean lightsOn = false; // state variablesboolean lastButton = LOW; // Variable containing the previous button state.boolean currentButton = LOW; // Variable containing the current button state.int whichLED = 0;int counter = 0; // main countervoid setup(){pinMode(redLED, OUTPUT); // set up IOpinMode(greenLED, OUTPUT);pinMode(blueLED, OUTPUT);pinMode(BUTTON, INPUT);pinMode (TEMP, INPUT);}/** Debouncing function* Pass it to previous button state,* and get back the current debounced button state.*/boolean debounce (boolean last){boolean current = digitalRead (BUTTON); // Read the button stateif (last != current) // if it's different...{delay (10); // wait 10mscurrent = digitalRead (BUTTON); // read it againreturn current; // return the current value.}}void loop (){currentButton = debounce (lastButton); // read debounced stateif (lastButton == LOW && currentButton == HIGH) // if it was pressed...{lightsOn = ! lightsOn;} // toggle the LED valuelastButton = currentButton; // reset button valuedigitalWrite (whichLED, lightsOn); // change the LED stateif (lightsOn == false) // turn LED off and clean up{counter = 0;digitalWrite(redLED, LOW);digitalWrite(greenLED, LOW);digitalWrite(blueLED, LOW);whichLED = 0;}else{ // Or if we are activating LEDsdigitalWrite(whichLED, HIGH); // Turn first LED on to start}if (lightsOn == true) // Manage LED state{counter++; // Increment counterif (counter >= 1000) // ~ 1 second has passed{ // So increment LED statecounter = 0;digitalWrite(whichLED, HIGH); // Don't forget to turn old LED offwhichLED++;if (whichLED > 2) // Don't let whichLED go to invalid statewhichLED = 2;}}delay(1); // 1 ms delay for 1000 count = ~ 1 secondval=analogRead (TEMP);if (val >= UPPER_BOUND){if (lightsOn){counter = 0;digitalWrite (redLED, LOW);digitalWrite (greenLED, LOW);digitalWrite (blueLED, LOW);lightsOn = false;}}else{lightsOn == true; // It is good up to here}val=analogRead (TEMP); //I am trying to disable button through "! lightsOn"if (val > UPPER_BOUND){if (! lightsOn){do{lightsOn = false; // "lightsOn" goes to false state and it stays false}while (val > LOWER_BOUND);}}else // When the temperature drops under LOWER_BOUND,//lightsOn should be true, but it stays false and button{ // is hence disabledlightsOn == true;}}

author: obiwanjacobi
author_rank: Super Contributor
timestamp: June 07, 2015, 01:34:18 pm
content: You could just stop calling the main-good-loop and call a different main-bad-loop...?The main-bad-loop would do nothing but check for ok-temps...?

author: kolonelkadat
author_rank: Regular Contributor
timestamp: June 07, 2015, 02:00:57 pm
content: Quote from: IvoS on June 07, 2015, 01:28:04 pmyou have to read the value again to see if it has gone below the threshold.I assume this should work. I dont know though, when I copied it to text editor, the curlies wound up all over the place.Code:#define redLED 0 //define IO#define greenLED 1#define blueLED 2#define BUTTON 4#define TEMP 3const int LOWER_BOUND = 53;const int UPPER_BOUND = 56;int val = 0;boolean lightsOn = false; // state variablesboolean lastButton = LOW; // Variable containing the previous button state.boolean currentButton = LOW; // Variable containing the current button state.int whichLED = 0;int counter = 0; // main countervoid setup(){pinMode(redLED, OUTPUT); // set up IOpinMode(greenLED, OUTPUT);pinMode(blueLED, OUTPUT);pinMode(BUTTON, INPUT);pinMode (TEMP, INPUT);}/** Debouncing function* Pass it to previous button state,* and get back the current debounced button state.*/boolean debounce (boolean last){boolean current = digitalRead (BUTTON); // Read the button stateif (last != current) // if it's different...{delay (10); // wait 10mscurrent = digitalRead (BUTTON); // read it againreturn current; // return the current value.}}void loop (){currentButton = debounce (lastButton); // read debounced stateif (lastButton == LOW && currentButton == HIGH) // if it was pressed...{lightsOn = ! lightsOn;} // toggle the LED valuelastButton = currentButton; // reset button valuedigitalWrite (whichLED, lightsOn); // change the LED stateif (lightsOn == false) // turn LED off and clean up{counter = 0;digitalWrite(redLED, LOW);digitalWrite(greenLED, LOW);digitalWrite(blueLED, LOW);whichLED = 0;}else{ // Or if we are activating LEDsdigitalWrite(whichLED, HIGH); // Turn first LED on to start}if (lightsOn == true) // Manage LED state{counter++; // Increment counterif (counter >= 1000) // ~ 1 second has passed{ // So increment LED statecounter = 0;digitalWrite(whichLED, HIGH); // Don't forget to turn old LED offwhichLED++;if (whichLED > 2) // Don't let whichLED go to invalid statewhichLED = 2;}}delay(1); // 1 ms delay for 1000 count = ~ 1 secondval=analogRead (TEMP);if (val >= UPPER_BOUND){if (lightsOn){counter = 0;digitalWrite (redLED, LOW);digitalWrite (greenLED, LOW);digitalWrite (blueLED, LOW);lightsOn = false;}}else{lightsOn == true; // It is good up to here}val=analogRead (TEMP); //I am trying to disable button through "! lightsOn"if (val > UPPER_BOUND){if (! lightsOn){do{lightsOn = false; // "lightsOn" goes to false state and it stays falseval=analogRead (TEMP);}while (val > LOWER_BOUND);}}else // When the temperature drops under LOWER_BOUND,//lightsOn should be true, but it stays false and button{ // is hence disabledlightsOn == true;}}

author: IvoS
author_rank: Frequent Contributor
timestamp: June 07, 2015, 05:06:36 pm
content: Quote from: kolonelkadat on June 07, 2015, 02:00:57 pmYES!It works!It is good to know that I was in the right ball park with "do" and "while". I know there are many many other ways to do it. I was looking yesterday on Arduino reference page and scratching my head as I had no clue what to use from control structures and further syntax.Many thanks.

author: obiwanjacobi
author_rank: Super Contributor
timestamp: June 08, 2015, 06:02:57 am
content: You try to weave the lightsOn logic through the button and led logic. I don't think you have to do that.Consider this:Code:void loop(){int temp = readDigital(TEMP);if (temp < MAX_THRESHOLD){ScanButtonAndDriveLeds();}else{DisableOutput();WaitForTempToLower();}}The ScanButtonAndDriveLeds() function is the code you had before you tried to incorporate the temp logic. DisableOutput is the code that switches of the Leds and WaitForTempToLower() performs a loop that reads the temp value and only exists if its below the Max (or any other value).I think your code will be more readable and maintainable. Remember - it is likely that you will not understand your own code if you revisit it after a couple of months (spending doing something else)...

author: IvoS
author_rank: Frequent Contributor
timestamp: June 08, 2015, 07:14:19 pm
content: Thanks, Yes, probably. The code will need revision that is for sure because I will be using ATtiny84 instead of 85, adding another temp sensor and using one more pin for LED status ON/OFF/overheat.Thank you for your suggestion.

author: SL4P
author_rank: Super Contributor
timestamp: June 09, 2015, 04:54:24 am
content: Congratulations on getting it working the way you wanted it to!This was a great example of a 'rookie' asking and receiving - with the appropriate amount of learning on the way through!Lesson 1: Avoid delay() at all costs, unless you're prepared for the consequences!Lesson 2: Ask therightquestions, don't skimp on detail, or you'll get the wrong answer!You should now have a lot better understanding of how the code and flow operates and will be able to make magic with a micro!

author: IvoS
author_rank: Frequent Contributor
timestamp: June 16, 2015, 11:30:24 pm
content: I have my code refined, I added 2 temperature sensors and I also added "LEDON" as my on/off status LED light.Everything works but, lower down in the code followingQuoteI want to have the LEDON to blink using "counter" while the temperature is still high above the LOWER_BOUNDQuotebut the LEDON blinks only once at the beginning when the "do" executes and then it's constantly ON during the while condition but it is not flashing. I am trying to figure out how to make it blink, but it looks like I have some conflicts there at the beginningperhaps that prevent the blinking?Any help appreciated.Code:#define BLEEDERS 0 //define IO#define TRIAC 1#define BYPASS 2#define LEDON 3#define BUTTON 4#define TEMP1 5#define TEMP2 6const int LOWER_BOUND = 87;const int UPPER_BOUND = 115;int val = 0;boolean lightsOn = false; // state variablesboolean lastButton = LOW; // Variable containing the previous button state.boolean currentButton = LOW; // Variable containing the current button state.int whichLED = 0;int counter = 0; // main countervoid setup(){pinMode(BLEEDERS, OUTPUT); // set up IOpinMode(TRIAC, OUTPUT);pinMode(BYPASS, OUTPUT);pinMode(LEDON, OUTPUT);pinMode(BUTTON, INPUT);pinMode(TEMP1, INPUT);pinMode(TEMP2, INPUT);}/** Debouncing function* Pass it to previous button state,* and get back the current debounced button state.*/boolean debounce (boolean last){boolean current = digitalRead (BUTTON); // Read the button stateif (last != current) // if it's different...{delay (10); // wait 10mscurrent = digitalRead (BUTTON); // read it againreturn current; // return the current value.}}void loop (){currentButton = debounce (lastButton); // read debounced stateif (lastButton == LOW && currentButton == HIGH) // if it was pressed...{lightsOn = ! lightsOn;} // toggle the LED valuelastButton = currentButton; // reset button valuedigitalWrite (whichLED, lightsOn); // change the LED statedigitalWrite (LEDON, lightsOn);if (lightsOn == false) // turn LED off and clean up{counter = 0;digitalWrite(BLEEDERS, LOW);digitalWrite(TRIAC, LOW);digitalWrite(BYPASS, LOW);digitalWrite(LEDON, LOW);whichLED = 0;}else // Or if we are activating LEDs{digitalWrite(whichLED, HIGH); // Turn first LED on to startdigitalWrite(LEDON, HIGH);}if (lightsOn == true) // Manage LED state{counter++; // Increment counterif (counter >= 500) // ~ 1 second has passed{ // So increment LED statecounter = 0;digitalWrite(whichLED, HIGH); //whichLED++;if (whichLED > 2) // Don't let whichLED go to invalid statewhichLED = 2;}}delay(1); // 1 ms delay for 1000 count = ~ 1 secondval=analogRead (TEMP1); // Read the TEMP1 sensorif (val >= UPPER_BOUND) // If value is higher than upper bound{if (lightsOn) // and OUTPUTs are ON{counter = 0; // shut everything OFF and clear the counterdigitalWrite (BLEEDERS, LOW);digitalWrite (TRIAC, LOW);digitalWrite (BYPASS, LOW);digitalWrite (LEDON, LOW);lightsOn = false;}}else{lightsOn == true; // Otherwise, toggle button, ON - OFF}val=analogRead (TEMP1); // Read the TEMP1 sensorif (val > UPPER_BOUND) //If value is higher than upper bound...{if (! lightsOn) //...and if outputs were shut OFF by TEMP1 sensor{do{lightsOn = false; // turn all outputs OFFval=analogRead (TEMP1); // and read the TEMP1 sensor againdigitalWrite(LEDON, HIGH);counter++; // I WANT THE "LED" TO BLINKif (counter >= 500) // USING counter INSTEAD OF delay(){ //counter = 0;digitalWrite(LEDON, LOW); //}else{digitalWrite(LEDON, HIGH);}}while (val > LOWER_BOUND); // keep all outputs OFF during the time when value is} // above lower bound, BUTTON is disabled}else{lightsOn == true; // Otherwise, toggle button, ON - OFF}val=analogRead (TEMP2); //Read the TEMP2 sensorif (val >= UPPER_BOUND) //If value is higher than upper bound{if (lightsOn) // and OUTPUTs are ON{counter = 0;digitalWrite (BLEEDERS, LOW); //shut everything OFF and clear the counterdigitalWrite (TRIAC, LOW);digitalWrite (BYPASS, LOW);lightsOn = false;}}else{lightsOn == true; // Otherwise, toggle button, ON - OFF}val=analogRead (TEMP2); // read the TEMP2 sensorif (val > UPPER_BOUND) // if value is higher than upper bound...{if (! lightsOn) //...and if outputs were shut OFF by TEMP2 sensor{do{lightsOn = false; // turn all outputs OFFval=analogRead (TEMP2); // and read the TEMP2 sensor again}while (val > LOWER_BOUND); // keep all outputs OFF during the time when value is} // above lower bound, BUTTON is disabled}else{lightsOn == true; // Otherwise, toggle button, ON - OFF}}

author: kolonelkadat
author_rank: Regular Contributor
timestamp: June 17, 2015, 12:04:40 am
content: wow what a mess...anyways what I think i did to your code was move the initial truning on of the led outside of the loop, then set up a led state variable (probably a terrible way to do it ram wise) and then every timecounter >= 500we toggle the ledstate and write the ledstate to ledon(~ledstate)&HIGH should do the business, bitwise inversion of ledstate, taking only the HIGH bit...Code:#define BLEEDERS 0 //define IO#define TRIAC 1#define BYPASS 2#define LEDON 3#define BUTTON 4#define TEMP1 5#define TEMP2 6const int LOWER_BOUND = 87;const int UPPER_BOUND = 115;int val = 0;boolean lightsOn = false; // state variablesboolean lastButton = LOW; // Variable containing the previous button state.boolean currentButton = LOW; // Variable containing the current button state.int whichLED = 0;int counter = 0; // main countervoid setup(){pinMode(BLEEDERS, OUTPUT); // set up IOpinMode(TRIAC, OUTPUT);pinMode(BYPASS, OUTPUT);pinMode(LEDON, OUTPUT);pinMode(BUTTON, INPUT);pinMode(TEMP1, INPUT);pinMode(TEMP2, INPUT);}/** Debouncing function* Pass it to previous button state,* and get back the current debounced button state.*/boolean debounce (boolean last){boolean current = digitalRead (BUTTON); // Read the button stateif (last != current) // if it's different...{delay (10); // wait 10mscurrent = digitalRead (BUTTON); // read it againreturn current; // return the current value.}}void loop (){currentButton = debounce (lastButton); // read debounced stateif (lastButton == LOW && currentButton == HIGH) // if it was pressed...{lightsOn = ! lightsOn;} // toggle the LED valuelastButton = currentButton; // reset button valuedigitalWrite (whichLED, lightsOn); // change the LED statedigitalWrite (LEDON, lightsOn);if (lightsOn == false) // turn LED off and clean up{counter = 0;digitalWrite(BLEEDERS, LOW);digitalWrite(TRIAC, LOW);digitalWrite(BYPASS, LOW);digitalWrite(LEDON, LOW);whichLED = 0;}else // Or if we are activating LEDs{digitalWrite(whichLED, HIGH); // Turn first LED on to startdigitalWrite(LEDON, HIGH);}if (lightsOn == true) // Manage LED state{counter++; // Increment counterif (counter >= 500) // ~ 1 second has passed{ // So increment LED statecounter = 0;digitalWrite(whichLED, HIGH); //whichLED++;if (whichLED > 2) // Don't let whichLED go to invalid statewhichLED = 2;}}delay(1); // 1 ms delay for 1000 count = ~ 1 secondval=analogRead (TEMP1); // Read the TEMP1 sensorif (val >= UPPER_BOUND) // If value is higher than upper bound{if (lightsOn) // and OUTPUTs are ON{counter = 0; // shut everything OFF and clear the counterdigitalWrite (BLEEDERS, LOW);digitalWrite (TRIAC, LOW);digitalWrite (BYPASS, LOW);digitalWrite (LEDON, LOW);lightsOn = false;}}else{lightsOn == true; // Otherwise, toggle button, ON - OFF}val=analogRead (TEMP1); // Read the TEMP1 sensorif (val > UPPER_BOUND) //If value is higher than upper bound...{if (! lightsOn) //...and if outputs were shut OFF by TEMP1 sensor{int ledstate= HIGH;digitalWrite(LEDON, ledstate);do{lightsOn = false; // turn all outputs OFFval=analogRead (TEMP1); // and read the TEMP1 sensor againcounter++; // I WANT THE "LED" TO BLINKif (counter >= 500) // USING counter INSTEAD OF delay(){ //counter = 0;ledstate = (~ledstate)&HIGH; //toggle ledstatedigitalWrite(LEDON, ledstate); //}}while (val > LOWER_BOUND); // keep all outputs OFF during the time when value is} // above lower bound, BUTTON is disabled}else{lightsOn == true; // Otherwise, toggle button, ON - OFF}val=analogRead (TEMP2); //Read the TEMP2 sensorif (val >= UPPER_BOUND) //If value is higher than upper bound{if (lightsOn) // and OUTPUTs are ON{counter = 0;digitalWrite (BLEEDERS, LOW); //shut everything OFF and clear the counterdigitalWrite (TRIAC, LOW);digitalWrite (BYPASS, LOW);lightsOn = false;}}else{lightsOn == true; // Otherwise, toggle button, ON - OFF}val=analogRead (TEMP2); // read the TEMP2 sensorif (val > UPPER_BOUND) // if value is higher than upper bound...{if (! lightsOn) //...and if outputs were shut OFF by TEMP2 sensor{do{lightsOn = false; // turn all outputs OFFval=analogRead (TEMP2); // and read the TEMP2 sensor again}while (val > LOWER_BOUND); // keep all outputs OFF during the time when value is} // above lower bound, BUTTON is disabled}else{lightsOn == true; // Otherwise, toggle button, ON - OFF}}

author: IvoS
author_rank: Frequent Contributor
timestamp: June 17, 2015, 08:25:22 pm
content: Super! Thank you very much.I will be honest, I would probably never figure it out like this (lack of experience). I don't have any example in my book similar to this one, or at least something close to it I could use and modify.I was looking at this line you wrote: "ledstate = (~ledstate)&HIGH;" and I have no clue of its exact function other your note: //toggle ledstate.Only I know of a state toggling is something like this: LEDON = ! LEDON, for example.Anyway, it works as I need and I will leave it as it is. Even though it's a mess, it only has 1.5k bytes, so I am not expecting any misbehavior.Thanks.

author: kolonelkadat
author_rank: Regular Contributor
timestamp: June 18, 2015, 06:29:37 am
content: Quote from: IvoS on June 17, 2015, 08:25:22 pmlet me break down that line for you.(~ledstate)~ means to do a bitwise inversion, meaning to look at the variable and turn every bit that is 0 to 1 and turn every bit that is 1 to 0so if ledstate were 0b00000011, ~ledstate would be 0b11111100.&HIGH& means do a bitwise AND operation. The bitwise AND operator (&) compares each bit of the first operand to the corresponding bit of the second operand. If both bits are 1, the corresponding result bit is set to 1. Otherwise, the corresponding result bit is set to 0.so in the case of &HIGH we limit ourselves to looking only at the bit that HIGH uses.something like LEDON = !LEDON will do a boolean inversion, which might work fine in this use case, but it technically only swaps between 'true' and 'false'.

author: IvoS
author_rank: Frequent Contributor
timestamp: June 18, 2015, 07:01:53 pm
content: Thanks.