Author Topic: While {you're down there ...}  (Read 3657 times)

0 Members and 1 Guest are viewing this topic.

Offline PerranOakTopic starter

  • Frequent Contributor
  • **
  • Posts: 548
  • Country: gb
While {you're down there ...}
« on: September 25, 2019, 03:14:19 pm »
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"?
You can release yourself but the only way to go is down!
RJD
 

Offline dave j

  • Regular Contributor
  • *
  • Posts: 130
  • Country: gb
Re: While {you're down there ...}
« Reply #1 on: September 25, 2019, 03:46:05 pm »
Code: [Select]
while(condition){}will work, as will
Code: [Select]
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.
I'm not David L Jones. Apparently I actually do have to point this out.
 

Offline dcbrown73

  • Regular Contributor
  • *
  • Posts: 112
  • Country: us
Re: While {you're down there ...}
« Reply #2 on: September 25, 2019, 03:52:52 pm »
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
};
   

« Last Edit: September 25, 2019, 03:55:16 pm by dcbrown73 »
Why exactly do people feel I should have read their post before I responded?  As if that was necessary for me to get my point across.
 

Offline PerranOakTopic starter

  • Frequent Contributor
  • **
  • Posts: 548
  • Country: gb
Re: While {you're down there ...}
« Reply #3 on: September 25, 2019, 04:28:11 pm »
Cheers all.

So next time should I post a dopey noob question re C in "Programming"?
You can release yourself but the only way to go is down!
RJD
 

Offline rstofer

  • Super Contributor
  • ***
  • Posts: 9899
  • Country: us
Re: While {you're down there ...}
« Reply #4 on: September 25, 2019, 04:36:34 pm »
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) {}


I would probably do something like

while( 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 )

and

while( BUTTON != 0 ) {
}
 

Offline magic

  • Super Contributor
  • ***
  • Posts: 6822
  • Country: pl
Re: While {you're down there ...}
« Reply #5 on: September 25, 2019, 05:08:33 pm »
Firstly, button != 0 is same as simply button. That's actually a reasonable change to make.

And secondly, for is less keystrokes than while :-DD

for(;;button);
 

Offline Kilrah

  • Supporter
  • ****
  • Posts: 1852
  • Country: ch
Re: While {you're down there ...}
« Reply #6 on: September 25, 2019, 06:33:31 pm »
I count the same number of keystrokes actually ;)
 

Offline SiliconWizard

  • Super Contributor
  • ***
  • Posts: 14607
  • Country: fr
Re: While {you're down there ...}
« Reply #7 on: September 25, 2019, 06:38:40 pm »
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 use
Code: [Select]
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.
« Last Edit: September 25, 2019, 06:42:31 pm by SiliconWizard »
 

Offline SiliconWizard

  • Super Contributor
  • ***
  • Posts: 14607
  • Country: fr
Re: While {you're down there ...}
« Reply #8 on: September 25, 2019, 06:39:46 pm »
And secondly, for is less keystrokes than while :-DD

for(;;button);

Yeah, but the condition would have to be placed second, not third. Otherwise it will never get out.
Code: [Select]
for (; button; ) ;
Fewer keystrokes may be good, but beware of typos... :P
 

Offline maginnovision

  • Super Contributor
  • ***
  • Posts: 1963
  • Country: us
Re: While {you're down there ...}
« Reply #9 on: September 26, 2019, 04:54:08 am »
I like while for this type of stuff. This is how I'd usually do it, depending on polarity.

Code: [Select]
while (!(PORT & MASK)) {};
 

Offline PerranOakTopic starter

  • Frequent Contributor
  • **
  • Posts: 548
  • Country: gb
Re: While {you're down there ...}
« Reply #10 on: September 26, 2019, 10:03:40 am »
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+yellow
           for( count=40000; count>0; count=count-1 );
           PORTB = 0b00000100;                                   //green
           for( count=65000; count>0; count=count-1 );
           PORTB = 0b00000010;                                   //yellow
           for( count=40000; count>0; count=count-1 );
         }
         return;
       }
You can release yourself but the only way to go is down!
RJD
 

Offline sleemanj

  • Super Contributor
  • ***
  • Posts: 3029
  • Country: nz
  • Professional tightwad.
    • The electronics hobby components I sell.
Re: While {you're down there ...}
« Reply #11 on: September 26, 2019, 10:26:06 am »
Code: [Select]
while(1==1)
Is usually written

Code: [Select]
while(true)
(but will optimise to the same thing anyway).

Code: [Select]
  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
~~~
EEVBlog Members - get yourself 10% discount off all my electronic components for sale just use the Buy Direct links and use Coupon Code "eevblog" during checkout.  Shipping from New Zealand, international orders welcome :-)
 

Offline Kilrah

  • Supporter
  • ****
  • Posts: 1852
  • Country: ch
Re: While {you're down there ...}
« Reply #12 on: September 26, 2019, 11:05:33 am »
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.
 

Offline magic

  • Super Contributor
  • ***
  • Posts: 6822
  • Country: pl
Re: While {you're down there ...}
« Reply #13 on: September 26, 2019, 07:20:10 pm »
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).

Code: [Select]
while(1==1)
Is usually written

Code: [Select]
while(true)
Won't work in C without including stdbool.h.
Just while(1), that's exactly what true boils down to.
 

Offline SiliconWizard

  • Super Contributor
  • ***
  • Posts: 14607
  • Country: fr
Re: While {you're down there ...}
« Reply #14 on: September 26, 2019, 08:00:37 pm »
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.
 

Offline westfw

  • Super Contributor
  • ***
  • Posts: 4219
  • Country: us
Re: While {you're down there ...}
« Reply #15 on: September 26, 2019, 08:08:26 pm »
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: [Select]
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: [Select]
while (!button)  ; /* spin, waiting */
while (!button)
    ; // spin
while (!button) {
   // wait
}
are all better.
And I'll put in a new suggestion
Code: [Select]
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...)
 

Offline rstofer

  • Super Contributor
  • ***
  • Posts: 9899
  • Country: us
Re: While {you're down there ...}
« Reply #16 on: September 26, 2019, 10:56:17 pm »

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.

This 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!

 

Offline westfw

  • Super Contributor
  • ***
  • Posts: 4219
  • Country: us
Re: While {you're down there ...}
« Reply #17 on: September 27, 2019, 08:34:27 am »
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 )
 

Offline SiliconWizard

  • Super Contributor
  • ***
  • Posts: 14607
  • Country: fr
Re: While {you're down there ...}
« Reply #18 on: September 27, 2019, 06:06:05 pm »
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
 

Online Siwastaja

  • Super Contributor
  • ***
  • Posts: 8203
  • Country: fi
Re: While {you're down there ...}
« Reply #19 on: September 30, 2019, 10:18:31 am »
On modern MCUs with caches and branch prediction and whatnot, those delay loops are virtually useless...

I 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 the average performance of large routines when 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, and still get jitter to the less important task.
« Last Edit: September 30, 2019, 10:23:14 am by Siwastaja »
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf