While {you're down there ...} - Page 1
Forum section: electronics / general

author: PerranOak
author_rank: Frequent Contributor
timestamp: September 25, 2019, 03:14:19 pm
content: In one of my first exercises learning C, I had to: light a LED, wait with a while loop for a button press then go on.I can't think what syntax to use for a completely empty while.Is it just:while(button!=0) {}BTW is this for "Beginners" or "Programming"?

author: dave j
author_rank: Regular Contributor
timestamp: September 25, 2019, 03:46:05 pm
content: Code:while(condition){}will work, as willCode:while(condition);The former is preferable as it is more obvious that you meant to have an empty loop.Don't forget, in your code you'll need to make sure button gets updated otherwise you'll be stuck in an infinite loop.

author: dcbrown73
author_rank: Regular Contributor
timestamp: September 25, 2019, 03:52:52 pm
content: This is not an electronics question, it's a programming question.As for your question, button is not defined. How is button defined? Is it a variable that is Boolean true or 1 if the button has been pushed?If it's a boolean, you do not even need to test if it's != 0.EDIT: I'm guessing this is C programming you're referencing?// Button not True (or 0)while !(button) {// do whatever};// Button is true (or anything other than 0)while (button) {// do whatever};

author: PerranOak
author_rank: Frequent Contributor
timestamp: September 25, 2019, 04:28:11 pm
content: Cheers all.So next time should I post a dopey noob question re C in "Programming"?

author: rstofer
author_rank: Super Contributor
timestamp: September 25, 2019, 04:36:34 pm
content: Quote from: PerranOak on September 25, 2019, 03:14:19 pmI would probably do something likewhile( button != 0 ) {}And somebody won't like it...The problem I have is what exactly is 'button'. Is it a variable that is changed in an interrupt routine? If so, it needs to be declared as 'volatile'. If it is a function that returns the state of the switch then the statement is wrong and should probably be:while( button() != 0 ) {}if button is actually a MACRO like#define button ( PORTB & 0x0001 )it would probably work but macros should be all caps like#define BUTTON ( PORTB & 0x0001 )andwhile( BUTTON != 0 ) {}

author: magic
author_rank: Super Contributor
timestamp: September 25, 2019, 05:08:33 pm
content: Firstly,button != 0is same as simplybutton. That's actually a reasonable change to make.And secondly,foris less keystrokes thanwhilefor(;;button);

author: Kilrah
author_rank: Unknown
timestamp: September 25, 2019, 06:33:31 pm
content: I count the same number of keystrokes actually

author: SiliconWizard
author_rank: Super Contributor
timestamp: September 25, 2019, 06:38:40 pm
content: Very much a matter of style. To each their own pretty much.I usually do the following:while (condition) ;The advice to use braces instead of a semicolon makes sense; it avoids wreaking havoc if you ever forget the ';' or inadvertently delete it. I just don't do it. I'm not afraid. Go figure.And most often, I useCode:for (;;)instead of while (1) or while (true) for infinite loops. My rationale is that to me it looks different enough from any other loop that it's immediately obvious to the eye it's an infinite loop. Again, just a matter of style.As a side note, waiting for conditions like this is very common in embedded dev, but make sure you know what you do - they may get your software stuck forever.So when you do this, make sure that the condition IS guaranteed to occur in a timely fashion whatever happens, OR that you have enabled a watchdog. Sometimes a preferred approach is to implement a time-out, that you would add as a condition to get out of the loop.

author: SiliconWizard
author_rank: Super Contributor
timestamp: September 25, 2019, 06:39:46 pm
content: Quote from: magic on September 25, 2019, 05:08:33 pmYeah, but the condition would have to be placed second, not third. Otherwise it will never get out.Code:for (; button; ) ;Fewer keystrokes may be good, but beware of typos...

author: maginnovision
author_rank: Super Contributor
timestamp: September 26, 2019, 04:54:08 am
content: I like while for this type of stuff. This is how I'd usually do it, depending on polarity.Code:while (!(PORT & MASK)) {};

author: PerranOak
author_rank: Frequent Contributor
timestamp: September 26, 2019, 10:03:40 am
content: Wow! I can't believe there are so many ways to do such a simple thing! It's traffic lights and is supposed to wait on red until the button is pressed then go through the (UK) sequence pausing on green a little longer.BTW the whole programme is (and I don't get the "static bit button" part either!) as below:#include <xc.h>static bit button @ (unsigned) &PORTA*8+1;void main(void){unsigned int count;ANSELA = 0;ANSELB = 0;TRISB = 0;while(1==1){while(button!=0) //wait for button to be pressed{PORTB = 0b00000001; //red}PORTB = 0b00000011; //red+yellowfor( count=40000; count>0; count=count-1 );PORTB = 0b00000100; //greenfor( count=65000; count>0; count=count-1 );PORTB = 0b00000010; //yellowfor( count=40000; count>0; count=count-1 );}return;}

author: sleemanj
author_rank: Super Contributor
timestamp: September 26, 2019, 10:26:06 am
content: Code:while(1==1)Is usually writtenCode:while(true)(but will optimise to the same thing anyway).Code:for( count=40000; count>0; count=count-1 );Unless you have a really really slow clock that will be done in an instant. You probably want to insert some delaying function in there, looks like you are targetting an AVR, so ....https://www.nongnu.org/avr-libc/user-manual/group__util__delay.html

author: Kilrah
author_rank: Unknown
timestamp: September 26, 2019, 11:05:33 am
content: That looks like PIC, not AVR. But the XC compiler certainly has built in delay functions.The compiler might optimize out the entire empty loop too.

author: magic
author_rank: Super Contributor
timestamp: September 26, 2019, 07:20:10 pm
content: Yeah, these days it's safer to make the dummy count variable a volatile int or use some delay function which does more or less the same (in the case of MCUs).Quote from: sleemanj on September 26, 2019, 10:26:06 amWon't work in C without including stdbool.h.Justwhile(1), that's exactly whattrueboils down to.

author: SiliconWizard
author_rank: Super Contributor
timestamp: September 26, 2019, 08:00:37 pm
content: On modern MCUs with caches and branch prediction and whatnot, those delay loops are virtually useless, even when you make sure they don't get optimized out (which is still a common trap for young players). Just adapting them to the clock freq won't work to get any sensible idea of the real delay.On ARM Cortex ones, you can use special counter registers for that instead. I think PIC32 also have CPU counters which you can use for that as well.

author: westfw
author_rank: Super Contributor
timestamp: September 26, 2019, 08:08:26 pm
content: Empty loops make me a bit nervous, especially from a readability point of view.(and see also:https://stackoverflow.com/questions/3592557/optimizing-away-a-while1-in-c0x(which I think is not directly applicable, but adds to the nervousness.)Code:while (!button);is particularly bad. "Is that semicolon really supposed to be there?"Comments are good, like the "// Fall through" comment in case statements.Code:while (!button) ; /* spin, waiting */while (!button); // spinwhile (!button) {// wait}are all better.And I'll put in a new suggestionCode:while (1) {if (button)break;}which I like for indeterminate and long loops. (if you're checking something like a UART status flag, it's a loop that you expect to terminate "soon." Whereas with a button, it could be a very long time indeed. The less likely the event is to occur, the more I like to emphasize the "infinite-ness" of the loop. Or something like that. YMMV, local styles override, etc...)

author: rstofer
author_rank: Super Contributor
timestamp: September 26, 2019, 10:56:17 pm
content: Quote from: SiliconWizard on September 26, 2019, 08:00:37 pmThis is a HUGE trap when optimization is turned on. The program ran great, everything is ready to ship, let's optimize the code and go out for Pizza.In theory, and I wouldn't want to guarantee it, if the variable in the while statement is declared volatile, the loop shouldn't be optimized away. But it also has to be a global variable, reachable from the world. The idea is that an interrupt routine, in another module, could change the value so the compiler can't just assume it never changes and, therefore, it leaves the code alone.Spin loops are problematic!

author: westfw
author_rank: Super Contributor
timestamp: September 27, 2019, 08:34:27 am
content: Here's an improved delay mechanism for Cortex-M4, using the 32bit cycle counter that is part of the "Debug, Watchpoint, and Trace" (DWT) unit that is present in (most?) CM4 chips...https://github.com/adafruit/ArduinoCore-samd/pull/77/commits/faf28a90ca4c97229736bd5fbbbbba5b1bbcc808(replaces the instruction-counting loop in the Adafruit SAMD51 Arduino core that (surprise!) didn't work right with the cache enabled.)All ARM Cortext chips have Systick, which can be used similarly (but it's only 24 bits, and is usually set to reload periodically, and counts down, which makes it more awkward to use.https://github.com/WestfW/Duino-hacks/blob/master/systick_delay/systick_delay.ino)

author: SiliconWizard
author_rank: Super Contributor
timestamp: September 27, 2019, 06:06:05 pm
content: Yup, I actually gave some code for STM32 (HAL, but the HAL part only to get the clock frequency) here:https://www.eevblog.com/forum/microcontrollers/ad7685-reading-data-problem/msg2687904/#msg2687904

author: Siwastaja
author_rank: Super Contributor
timestamp: September 30, 2019, 10:18:31 am
content: Quote from: SiliconWizard on September 26, 2019, 08:00:37 pmI don't understand this. I have done quite some work with modern MCUs with caches, and they mostly come with core-coupled instruction scratchpad, and I just simply put all even remotely timing-critical code there. It has the same performance than having everything 100% in cache with no misses, and is predictable, including the first iteration.Branch prediction in a simple delay loop should be predictable as well.IMO, caches are there to increase theaverage performanceoflarge routineswhen you run out of small core-coupled RAM and have to run "directly" out of FLASH, or, worse, out of external SD card or similar. But this doesn't matter much for small timing critical routines (which the delay loops obviously are) - just run them out of instruction RAM.I have never turned caches on in an MCU project; turns out, I can always fit all timing-critical processing in tightly coupled RAM, and the rest can be "slow" from flash.But even if you "have" to run it from cache - it's going to be a small offset at the start, depending on whether it produces a miss or not in the first cycle. Assuming you still run from the internal flash, the difference is a flash cycle or two, or maybe about 20ns.And I'm using delay loops extensively. Of course they aren't good for precision timing in presence of interrupts, but neither are timer-based busy loops, or interrupt handlers. Doing it accurately in a system with existing interrupts requires a big picture understanding, i.e., setting your interrupt priorities right while making sure nothing breaks in edge cases.Using a simple delay loop to implement something at least won't risk the existing interrupts, and it's very obvious that the delays are going to be longer than specified depending on interrupt load level. This is much easier than to add a new interrupt handler, configure the pre-emptive priorities right, andstillget jitter to the less important task.