Breaking a while loop - Page 1
Forum section: electronics / projects

author: anishkgt
author_rank: Frequent Contributor
timestamp: June 26, 2018, 10:57:37 pm
content: Hi All,I am trying to break the while loop in the code below within it with an if statement, does not seem to work. Is there a better way to use the debounce code ?Code:void loop(){ENC_SWstate = digitalRead(ENC_SW);ENC_SWpressDuration = 0;if (ENC_SWstate == LOW && prevENC_SWstate == HIGH){delay(10);ENC_SWstate = digitalRead(ENC_SW);if (ENC_SWstate == LOW && prevENC_SWstate == HIGH){TimeStamp = millis();}}if (ENC_SWstate == HIGH && prevENC_SWstate == LOW){delay(10);ENC_SWstate = digitalRead(ENC_SW);if (ENC_SWstate == HIGH && prevENC_SWstate == LOW){ENC_SWpressDuration = (millis() - TimeStamp);}}if (ENC_SWpressDuration > 0 && ENC_SWpressDuration >= delayTime){menu = true;}while (menu == true){W1Value = (readEncoder() * 5) % 51;lcd.setCursor (0, 0);lcd.print("W1:");lcd.print(W1Value);lcd.print("ms ");lcd.print("*");lcd.print(" ");} menu = false;}

author: maginnovision
author_rank: Super Contributor
timestamp: June 26, 2018, 11:04:54 pm
content: You probably want break but I don't see any if statement, or I'm not sure which loop?

author: anishkgt
author_rank: Frequent Contributor
timestamp: June 26, 2018, 11:08:00 pm
content: ooops lost the other bit while copying. here it is again.Code:void loop(){ENC_SWstate = digitalRead(ENC_SW);ENC_SWpressDuration = 0;if (ENC_SWstate == LOW && prevENC_SWstate == HIGH){delay(10);ENC_SWstate = digitalRead(ENC_SW);if (ENC_SWstate == LOW && prevENC_SWstate == HIGH){TimeStamp = millis();}}if (ENC_SWstate == HIGH && prevENC_SWstate == LOW){delay(10);ENC_SWstate = digitalRead(ENC_SW);if (ENC_SWstate == HIGH && prevENC_SWstate == LOW){ENC_SWpressDuration = (millis() - TimeStamp);}}if (ENC_SWpressDuration > 0 && ENC_SWpressDuration >= delayTime){menu = true;}while (menu == true){W1Value = (readEncoder() * 5) % 51;lcd.setCursor (0, 0);lcd.print("W1:");lcd.print(W1Value);lcd.print("ms ");lcd.print("*");lcd.print(" ");ENC_SWstate = digitalRead(ENC_SW);ENC_SWpressDuration = 0;if (ENC_SWstate == LOW && prevENC_SWstate == HIGH){delay(10);ENC_SWstate = digitalRead(ENC_SW);if (ENC_SWstate == LOW && prevENC_SWstate == HIGH){TimeStamp = millis();}}if (ENC_SWstate == HIGH && prevENC_SWstate == LOW){delay(10);ENC_SWstate = digitalRead(ENC_SW);if (ENC_SWstate == HIGH && prevENC_SWstate == LOW){ENC_SWpressDuration = (millis() - TimeStamp);}}if (ENC_SWpressDuration > 0 && ENC_SWpressDuration >= delayTime){menu = false;}}

author: JohnnyMalaria
author_rank: Super Contributor
timestamp: June 26, 2018, 11:11:19 pm
content: ReplaceCode:menu = false;withCode:break;

author: Nusa
author_rank: Super Contributor
timestamp: June 26, 2018, 11:27:22 pm
content: I see no assignments to prevENC_SWstate, so I don't see how your logic would ever get to the assignment of ENC_SWpressDuration, which means it will never be > 0.But if the logic worked, either menu=false or break would work to exit the loop.

author: anishkgt
author_rank: Frequent Contributor
timestamp: June 27, 2018, 12:09:03 pm
content: That did not work, it just update encoder when i pressed button instead.

author: anishkgt
author_rank: Frequent Contributor
timestamp: June 27, 2018, 12:09:57 pm
content: Quote from: JohnnyMalaria on June 26, 2018, 11:11:19 pmThat did not work, it just update encoder when i pressed button instead.

author: IDEngineer
author_rank: Super Contributor
timestamp: June 27, 2018, 12:36:45 pm
content: I think you're missing a closing brace in your second code snippet. But anyway, to your question: If you want to exit a loop, change its conditional! You're testing (true == menu)... so if you want out of the loop change the value of menu to false. The "break" instruction is really just bad, lazy coding practice. In code with multiple (and especially nested) compound statements it can be a nightmare keeping track of just which compound statement your "break" will exit. Write your code to be clear and easy to read... it might be YOU trying to figure out what you meant a couple of years hence.And yes, I wrote that as (true == menu) on purpose. When testing for equality it's better to list the constant on the left of the equal sign. This will cause the compiler to report an error if you accidentally use a single equal sign (assignment) instead of a double (compare), which is a very common typo. Hence:while (true = menu)...will generate a helpful error, whereas:while (menu = true)...will silently compile with no error.

author: glarsson
author_rank: Frequent Contributor
timestamp: June 27, 2018, 12:51:22 pm
content: Quote from: IDEngineer on June 27, 2018, 12:36:45 pmIf I see that in a code review then the code will be rejected immediately, on purpose.The reason is that testing against true only succeeds if the variable is 1, but in C and C++ any non-zero value is true.if ( menu == true ) // badif ( true == menu ) // badif ( menu != false ) // okif ( menu ) // best

author: IDEngineer
author_rank: Super Contributor
timestamp: June 27, 2018, 01:07:37 pm
content: Quote from: glarsson on June 27, 2018, 12:51:22 pmI WHOLEHEARTEDLY agree, and prefer your "best" example, and years ago your last example was the only way I wrote boolean conditionals. The opposite test I would always write as (!menu) too. If you examine the resulting Assembly code, these pure (true) and (!true) statements give intelligent compilers more information about the test you're actually conducting and can result in more efficient code. For example, (!menu) can result in Assembly that simply sets the flags and then tests the Zero flag, rather than actually performing a mathematical comparison that takes quite a few more machine cycles.But all of this presumes a high intelligence compiler. In the years since, I have run into too many compilers that simply don't handle that properly. I know, I know... we can argue all day about them being non-compliant with the standard, etc. But when that's the manufacturer's development environment, you're kinda stuck using it. So today I grumble and write it the way I showed. Your "!= false" also works but the best choice between those two options is the one that reads most clearly given the logic being implemented. Sometimes that's the "equal" case, others it's the "non-equal" case, and I prefer to write code that is as easy to read and understand as possible. Who knows, it might be ME maintaining it someday!Also, the OP used the explicit "== true" so I was following his example.Finally, the "constant == variable" pattern works for anything, not just booleans. That's what I was trying to say. It's better to put the constant on the left so the compiler can warn you if you forget that second equal sign.

author: ajb
author_rank: Super Contributor
timestamp: June 27, 2018, 03:52:21 pm
content: Quote from: IDEngineer on June 27, 2018, 12:36:45 pmThat's an unjustifiably broad statement. I think you meant that using break to jump around willy-nilly through nested loops is bad, and sure, it is--spaghetti is spaghetti--but that is more about the structure of the program than the tool used to assemble it. There are plenty of situations where break provides the cleanest and easiest to read solution to a problem. Just like goto, it's a tool of the language, and it's up to the programmer to use it where it makes the most sense. You can just as easily create inscrutable spaghetti using tons of ifs to check different flags inside of loops where judicious use of break/continue would have done a much more elegant job. It all depends on the problem you're trying to solve.

author: Siwastaja
author_rank: Super Contributor
timestamp: June 27, 2018, 04:05:50 pm
content: Quote from: ajb on June 27, 2018, 03:52:21 pmExactly. The "break and goto are bad" attitude is one of the leading "simple" (low-level or syntax level) reasons I see leading to spaghetti code. If you forbid a beginner from using proper tools, and instruct them to "work around", they indeed will. Instead of using clear and concise, self-explanatory command (such as break or continue, or to limited extent, goto) to describe exactly what the program does, in exactly the spot where it happens, a beginner is guided to believe they need to construct a "distributed" solution with a definition of a temporary variable of unclear, hard-to-descrive purpose (and hence, often illogical name) in one place, then assign to it in another place (or multiple places!), and compare it in a third place (or God forbid, in multiple places), and then analyze what can and may happen between the variable assignment and when it's tested the next time, and possibly write corner case logic for handling that.And this would be, somehow magically, "good coding practice".Guess what - it isn't. You don't define "good coding practices" by repeating ages old, disproved-to-death mantras. You do it by careful analysis and sound reasoning. Or you do it by the mantras if you have the authority and power to do so, but then you'll bear the consequences of having broken coding practices in your company or community.This is one of the most typical litmus tests that show who are competent and who just blindly repeat "good practices" they were taught in school or by other incompetent instructors.A good coding practice should never be a workaround to the "actual" tool people would like to use, motivated by the idea that being "lazy" is bad.Laziness isgood. Simple and clear tools are good.No one has never ever been able to reason whybreakis bad using any actual argument that holdsanywater.In the situations where using break or continue is hard to follow due to too many levels (this happens, indeed), blindly changing it to some kind of "quit variable" setting and testing is often a recipe for an even worse disaster, since it might geteven more difficult to follow. A quick fix to make itbetteris sometimes goto (which explicitly stateswherethe program flow will jump from and to, allowing and necessitating the destination to have a documenting label), but thebestsolution is to restructure to remove excess levels, or blocks too long in a single function. I.e., divide into smaller functions.I have almost never seen a badly used break instruction, and quite seldom, a badly used goto. Actually seeing that famous "goto spaghetti code" is almost nonexistent, as well. But teaching how you need to avoid them - and often suggesting ridiculously bad ways to work around them - all the freaking timecausesreallybad code, everyday, everywhere, and this is actually dangerous, unlike the mythical Goto Spaghetti Monster.

author: JohnnyMalaria
author_rank: Super Contributor
timestamp: June 27, 2018, 04:21:26 pm
content: Quote from: IDEngineerThat's an absurd generalization. Break exists for a reason and it has its place. Sometimes the "correct" way leads to far messier code and, without annotation, a pita for someone else down the road.It's part of a flexible toolbox. Don't tell me which hammer I must not use for any reason.

author: Nusa
author_rank: Super Contributor
timestamp: June 27, 2018, 04:46:58 pm
content: All of which is not really helping the guy out. The guy has a logic problem, not a syntax problem. What he started with would break the loop just fine, if it were ever executed.

author: Siwastaja
author_rank: Super Contributor
timestamp: June 27, 2018, 04:52:51 pm
content: Quote from: Nusa on June 27, 2018, 04:46:58 pmThe issue is not a simple logic problem, but the fact that the code has grown beyond the capabilities of the OP to understand, possibly both in length and complexity. What he needs is sound advice on learning how to write, understand and maintain simple ideas in a programming language. It's highly important to shoot down widely appearing destructive ideas and discuss about successful teaching of programming, instead of simply solving this one problem that's clearly stemming from the high complexity of this particular implementation compared to the still low ability, which is expected to get better through learning.

author: IDEngineer
author_rank: Super Contributor
timestamp: June 27, 2018, 05:20:58 pm
content: Quote from: Siwastaja on June 27, 2018, 04:05:50 pmHey, I didn't mean to start a religious war.Interestingly, I DO use "goto" but never "break". The difference is because goto jumps to a very visible place in the code: A user-defined label. No matter what else happens to the source, no matter how it's edited, that goto statement will always end up in that place. I use goto for fatal error conditions, to jump out to the end of a function when something bad has happened, so that no matter what thread of execution the code follows there is only one way out of the function and I can easily put a breakpoint there before everything local to that function goes out of scope.Break, on the other hand, goes to "the end of the current loop". And that can change, sometimes innocently. Say someone is editing some existing code, and they wrap some part of it in a new conditional. Now where does that "break" go? Yes, it still goes to "the end of the current loop", but that may not be what is desired - maybe you need to exit the new wrapper conditional too. You can argue that the person editing the code should dig in deep enough or grok the code well enough that this shouldn't happen, and I'd sure love all projects to come in on time and under budget too!But back in the real world, many things are quickly patched and a wise Engineer designs things to anticipate and avoid problems if possible.To me, that means avoiding the use of "break" so I don't have to worry about the next guy, a couple of years from now, miscounting the number of braces and not understanding exactly where that break is going to transfer control. Using the regular control statements of the language helps to avoid such confusion. Not a guarantee, of course (is anything ever guaranteed with software?) but I like to tilt the odds in favor of success.Just my opinion, and worth exactly what you paid for it. YMMV. Standard disclaimer. Etc!

author: Siwastaja
author_rank: Super Contributor
timestamp: June 27, 2018, 05:36:59 pm
content: Quote from: IDEngineer on June 27, 2018, 05:20:58 pmThis is true. However, all solutions that use a condition variable have a similar problem - the programmer needs to analyze and search the code to find the conditional block where this variable is evaluated in (sometimes there are multiple options), then search for the end of said block. If we are talking about modifications than involves restructuring the blocks and intending them to another level, without being careful, (as in your break problem example), the very same "end of the block changes to something else" can happen to a condition variable version as well!There is an additional burden, however, and that is analyzing what happens after setting the variable and before evaluating it. It's very typical to find that modifications to the code later affect that. A hard "stop" condition seems to work fine using an exit variable instead the break, until someone (including the original writer) adds some codeafterthe point where the variable was set - this is the logical place to add new code, after all. While a "break" would still work in such situation, the variable based solution won't offer the instant "break" anymore, but runs the new code once after the expected break. I have seen this happen countless of times. So, we are back to the "behavior changes due to seemingly unrelated change". Which is why, wheninitiallywriting the code, we need to keep our brain switched on, and instead of thinking about "best practice", we need to think about what we exactly need (and possible future implications), and if we indeed need what "break" does, then we use break since working around it with something else will be inferior, unmaintainable and dangerous. If, instead, the condition variable is what we need, then we use it. Sometimes goto is the best choice, and it seems to happen more often than many people want to admit. A typical case for goto, even in C++, is breaking from a simple 2D or 3D loop, which is short enough that it doesn't make sense to divide it to subfunctions, and which is so simple that bloating it up with exit variables makes it worse for readability and maintainability.

author: anishkgt
author_rank: Frequent Contributor
timestamp: June 27, 2018, 08:05:27 pm
content: Quote from: anishkgt on June 26, 2018, 11:08:00 pmThere are two button press here one entering the While loop and the second exiting it. The first works and its the second part does not seem to be working.

author: IanB
author_rank: Super Contributor
timestamp: June 27, 2018, 08:12:17 pm
content: Quote from: anishkgt on June 27, 2018, 08:05:27 pmThe main problem is that what you have written is "spaghetti code". It is overly complicated with too many levels of nested braces, such that it takes great effort to follow the logic and understand what is going on (or not, as the case may be).Your problem will disappear if you can learn how to reorganize and simplify the code. You may start perhaps by breaking out some parts into separate functions. If you inline the functions there will not be a performance penalty.(You might also consider implementing a state machine with a switch statement.)

author: anishkgt
author_rank: Frequent Contributor
timestamp: June 27, 2018, 08:30:51 pm
content: Quote from: IanB on June 27, 2018, 08:12:17 pmI am trying to enhance my skills at coding but one can’t learn everything by onself. Any example that you could share for using a switch with the state of the switch.Www.Georgehobby.wordpress.comEquipments: DSO104z, Hakko FX888D, Brymen BM869s

author: CopperCone
author_rank: Super Contributor
timestamp: June 27, 2018, 11:53:28 pm
content: what kind of oil do you use to lubricate and condition a while loop?

author: SiliconWizard
author_rank: Super Contributor
timestamp: June 28, 2018, 12:13:31 am
content: Quote from: CopperCone on June 27, 2018, 11:53:28 pm

author: JohnnyMalaria
author_rank: Super Contributor
timestamp: June 28, 2018, 01:12:30 am
content: Quote from: anishkgt on June 27, 2018, 08:05:27 pmVariabledelayTimeappears twice but is never assigned. Do you initialize it somewhere? Are you running in debug mode? Some compilers will assign a value such as 0xCCCCCCCC instead of zero in debug versions. If this is happening then your if statements will never be true (since a delay of 0xCCCCCCCC is so unlikely). If you aren't using debug mode then you should and single-step through the code and watch the variables.

author: anishkgt
author_rank: Frequent Contributor
timestamp: June 28, 2018, 05:17:52 am
content: The delay time is initialized at the starting of the code. This is an arduino project. The delay time is 50ms