Searching \ for '[PIC]Creating a 1 sec delay' in subject line. ()
Make payments with PayPal - it's fast, free and secure! Help us get a faster server
FAQ page: www.piclist.com/techref/microchip/time.htm?key=delay
Search entire site for: 'Creating a 1 sec delay'.

Exact match. Not showing close matches.
PICList Thread
'[PIC]Creating a 1 sec delay'
2010\02\22@011144 by Jason Hsu

picon face
I have successfully figured out how to keep an LED on for around 1 sec
(actual circuit, not a simulation) given a crystal of 3.57945 MHz.  As
you can see in the code snippet below, I have created algorithms for a
1 sec delay, 10 msec delay, 100 usec delay, and 1 usec delay.

What I'm having difficulty understanding is exactly how this works.  1
cycle is around 279 nsec.  But the code it took to create the 1 sec
delay makes it appear that it only takes .25 psec to increment the
value of a variable.  That implies a speed of 4 THz, and I know that
can't be possible for a through-hole microcontroller.

What's going on?  Does the microcontroller have a mechanism for
streamlining the process?

In applications for which timing is critical, how do you make sure the
timing is correct?

THE CODE SNIPPET:

#define __16F872
#include <stdlib.h>
#include <pic.h>
__CONFIG (XT&WDTDIS&PWRTDIS&BORDIS&UNPROTECT &  LVPDIS); // Set the
configuration bits:
// LVP must be disabled for LED8 to work.

unsigned char count, count1;

void delay_10_nsec (void)
       {
       count = 0;
       while (count < 200)
               {
               count1=0;
               while (count1 <200)
                       {count1++;}
               count++;
               }
       }

void delay_1_usec (void)
       {
       count=0;
       while (count<100)
               {
               delay_10_nsec();
               count++;
               }
       }

void delay_100_usec (void)
       {
       count = 0;
       while (count<100)
               {
               delay_1_usec(); // 100 delays of 1 usec each.
               count++;
               }
       }

void delay_10_msec (void)
       {
       count = 0;
       while (count<100)
               {
               delay_100_usec(); // 100 delays of 100 usec each.
               count++;
               }
       }

void delay_1_sec (void)
       {
       count = 0;
       while (count<100)
               {
               delay_10_msec(); // 100 delays of 10 msec each.
               count++;
               }
       }

--
Jason Hsu
http://www.jasonhsu.com/swrwatt.html
http://www.jasonhsu.com/swrwatt-c.txt
http://www.jasonhsu.com/swrwatt-asm.txt

2010\02\22@013220 by ivp

face picon face
> In applications for which timing is critical, how do you make sure the
> timing is correct?

Try starting here

http://www.piclist.com/techref/microchip/time.htm

wbr

2010\02\22@014632 by William \Chops\ Westfield

face picon face

On Feb 21, 2010, at 10:11 PM, Jason Hsu wrote:

> As you can see in the code snippet below, I have created algorithms  
> for a 1 sec delay, 10 msec delay, 100 usec delay, and 1 usec delay.

1) You have to be very careful when writing delay "loops" in a high-
level language like C.  Compilers have been known to notice that  
you're not actually doing anything inside the loop, and optimize it  
all away in favor of setting equivalent end values.

2) You're using the same "count" variable for all the delay functions,  
and each "inside" function will overwrite whatever value the outside  
function had.  Ie, delay_10_nsec returns with count == 200, so the  
delay_1_usec() loop will immediately end.

3) each PIC instruction takes 4 clock cycles, or a little over 1  
microsecond at 3.xx MHz, so you're starting off with some invalid  
assumptions.

4) most C compilers will include some "delay" primitives to address  
many of these issues, so that you don't have to reinvent the wheel...

> In applications for which timing is critical, how do you make sure  
> the timing is correct?

Code in assembler.   Perhaps inline assembler within C code.  Aside  
from all the above issues, code generation can change from one version  
of a compiler to the next, rendering any time spent getting the C code  
"just write" useless...

BillW

2010\02\22@041157 by Harry H. Arends

flavicon
face
Why are you using this odd crystal.
Why not a 4MHz version, makes calculation easier.

Looking at the schematic there's no time critical circuit.

Harry
{Quote hidden}

> -

2010\02\22@044201 by Alan B. Pearce

face picon face
> Why are you using this odd crystal.
>Why not a 4MHz version, makes calculation easier.

The crystal he is using is probably cheaper than a 4MHz one because it is a
TV colour burst frequency for US TV sets.

2010\02\22@055846 by ivp

face picon face
> The crystal he is using is probably cheaper than a 4MHz one because
> it is a TV colour burst frequency for US TV sets

3.579545 is surprisingly common on digital boards with counters like
the 4060, as well as DTMF ICs. Even on complex boards, stuffed full
of exotic chips, where you think no expense is spared, it's still way the
most common in the 4MHz-ish range. I've stripped dozens off a wide
variety of PCBs

-----------

There are some 3.58MHz here with the MC145443 300-baud modem
IC (1995 vintage). I have a feeling these are used for some sort of inter-
board comms and would like to find a use for them in a PIC context,
but they must be a bit old hat now eh ?

http://www.datasheetdir.com/MC145443+Interface

----------

wbr

2010\02\22@061846 by Matias Vidoni

picon face
Two things:
First the delay routines call each other, so if you call delay1s, you
have to save
the stack for 5 routines (delay1s calls delay_10ms, and so on) so becareful with
that because you could be running ouf of stack and your program doing some weird
stuff.

The other thing is about crystal.
I used to use some crystal of 3.582056 Mhz, because it's divisible by
2 until you reach 1.
I thinks that's better crystal for time applications than 4 Mhz.


On Mon, Feb 22, 2010 at 7:58 AM, ivp <joecolquittspamKILLspamclear.net.nz> wrote:
{Quote hidden}

> -

2010\02\22@074837 by Isaac Marino Bavaresco

flavicon
face
Em 22/2/2010 06:42, Alan B. Pearce escreveu:
>> Why are you using this odd crystal.
>> Why not a 4MHz version, makes calculation easier.
>>    
> The crystal he is using is probably cheaper than a 4MHz one because it is a
> TV colour burst frequency for US TV sets.
>  

Beware! I once used to use crystals with this frequency in my 8032
boards, and sometimes when I powered my boards near TV sets, the TV
color went away.

Hopefully, today the MCUs use much less power and the OP's boards may
radiate much less EMI/RFI interference than mine. Just to illustrate,
the 8032 (plus EPROM) consumed up to 200mA just to run code!!!


Regards,

Isaac

__________________________________________________
Faça ligações para outros computadores com o novo Yahoo! Messenger
http://br.beta.messenger.yahoo.com/

2010\02\22@202020 by Jason Hsu

picon face
Thanks for your responses.

I tried writing a delay in C code, and the microcontroller doesn't
seem efficient in the counting process.  The microcontroller can
increment a variable only 80 times in 1 msec.  So that means that it
takes 12.5 usec to increment a variable just one time.  With a 3.57945
MHz crystal, a clock cycle is .279 usec.  So incrementing a variable
just one time takes 45 clock cycles.  I know that C isn't as efficient
as Assembly language, but I didn't expect it to be this inefficient.

I understand now that delays are usually executed in Assembly code.
What is the proper way to insert Assembly language code into a C
program for PICC?  I recall trying to do this once but having
difficulty getting it to compile, so I gave up.

My new code snippit is:

void delay_1_msec (void)
       {
       count = 0;
       while (count<80)
               {
               count++;
               }
       }

void delay_10_msec (void)
       {
       count_10_msec = 0;
       while (count_10_msec<10)
               {
               delay_1_msec(); // 10 delays of 1 msec each.
               count_10_msec++;
               }
       }

void delay_1_sec (void)
       {
       count_1_sec = 0;
       while (count_1_sec<100)
               {
               delay_10_msec(); // 100 delays of 10 msec each.
               count_1_sec++;
               }
       }

--
Jason Hsu
http://www.jasonhsu.com/swrwatt.html
http://www.jasonhsu.com/swrwatt-c.txt
http://www.jasonhsu.com/swrwatt-asm.txt

2010\02\22@204438 by Marcel Duchamp

picon face
Some random comments...

1. One of the top fundamental bits of knowledge on microcontrollers is
how many clocks are required to execute one instruction.  If you are
using pics from the PIC12, 16 or 18 families, the answer is 4.  This is
in the data sheet - you should read it.

So your pic (if it's one of the above pic families) takes 4 of the .279
usec clocks - or about 1.1 Mips.

2.  To know what's going on, open the assembler listing your compiler
generates - actually see what code instructions it makes.

3. I'm not a C guru but your loops will probably go faster if you
preload and count down to zero.  For example, you preload count with 80
and count up.  The processor will take possibly several more
instructions to do a compare.  But the compare for zero is usually free;
hitting zero, if done right, sets the Z flag so a bit test instruction
can be used.

4. I think someone else may have mentioned to do a one second led blink
to check your understanding of how it all works.  This is a good idea too.

5. You probably use some sort of IDE; these often come with cycle
counters.  If you have one, use it.  See how many cycles it says your
code is using.  Then try other code re-writes to attempt to improve it.

On 2/22/2010 5:20 PM, Jason Hsu wrote:
{Quote hidden}

2010\02\22@205930 by Matias Vidoni

picon face
This is a code I use. Maybe it helps you. It's for HiTech C

<code>
#define max_millis 1953  //This is for a 2Mhz crystal

// 2000000 / 4 (cicles/instrucion) = 500000
// 500000 / 256 (8 bit timer interrupt) = 1953.12 interrupts

#define LED_PIN RB5  //Pin for led blink (1 sec on, 1 sec off)

#define delay1s t = seg2; while (t==seg2) //My 1 second delay

//Variable definitions as volatile
volatile unsigned int millis;
volatile unsigned char segundos;
volatile unsigned char minutos;
volatile unsigned char horas;
volatile unsigned char seg2;
//Temp variable for delay
unsigned char t;

void interrupt contador(void) {
       if (millis == max_millis) {
               millis = 0;
               if (LED_PIN)
                       LED_PIN = 0;
               else
                       LED_PIN = 1;
               if (segundos == 59) {
                       segundos = 0;
                       LED_PIN = 0;
                       if (minutos == 59) {
                               minutos = 0;
                               horas = horas + 1;
                       } else {
                               segundos = 0;
                               minutos = minutos + 1;
                       }
               } else {
                       segundos++;
                       seg2++;
               }
       } else {
               millis++;
       }
       T0IF = 0;
}

void main(void) {
       millis = 0;
       segundos = 0;
       minutos = 0;
       horas = 0;
       seg2 = 0;

       T0CS = 0;                        // select internal clock
       T0IE = 1;                        // enable timer interrupt
       GIE = 1;                        // enable global interrupts

       while(1) {
               //Every time I want a 1 sec delay I put:
               delay1s;
               //Do something
               delay1s;
               //And so on
       }
}        
</code>

Best regards
Matias

On Mon, Feb 22, 2010 at 10:44 PM, Marcel Duchamp
<.....marcel.duchampKILLspamspam.....sbcglobal.net> wrote:
{Quote hidden}

>

2010\02\22@210131 by Isaac Marino Bavaresco

flavicon
face
Efficiency depends on the compiler and how you write the code.

Some compilers are notorious to have excellent optimizers (when told to
do so), others not so.

In your examples you didn't show how the variables were declared, but if
you use 'long' variables then your code will be less efficient than if
you use 'short' or even 'char'.
As a rule of thumb, use the smallest type that can hold your maximum
value. In your example you count up to 80, then such variable may be
declared as a 'char' to get efficiency.

The way you write things may affect the efficiency also. For instance:

"
char count;
for( count = 0; count < 80; count++ ) ...
"

will probably be less efficient than:

"
char count;
for( count = 80; count != 0; count-- ) ...
"

Of course it all depends on the compiler, but the second form will
probably run faster and take less code than the first.


When using pointers and arrays, usually:

"
char i;
char v[64];
for( i = 0; i < sizeof v; i++ )
   putch( v[i] );
"

will be less efficient than:

"
char i;
char v[64]
char *p;
for( i = sizeof v, p = v; i != 0; i--, p++ )
   putch( *p );
"

even more if 'v' is not 'char[]' and 'p' is not 'char*', because of a
possible multiplication.


Best regards,

Isaac


Em 22/2/2010 22:20, Jason Hsu escreveu:
{Quote hidden}

__________________________________________________
Faça ligações para outros computadores com o novo Yahoo! Messenger
http://br.beta.messenger.yahoo.com/

2010\02\22@211556 by ivp

face picon face
> 5. You probably use some sort of IDE; these often come with cycle
> counters.  If you have one, use it.  See how many cycles it says your
> code is using.  Then try other code re-writes to attempt to improve it

Good idea. MPLAB has Stopwatch. Always handy for checking

>> So incrementing a variable just one time takes 45 clock cycles.  I
>> know that C isn't as efficient as Assembly language, but I didn't
>> expect it to be this inefficient

It isn't. Something's not right

A 3.579545MHz crystal is an execution frequency of 3.579545/4 =
0.89488625MHz, which is an instruction cycle time (IC) of 1.117us

So, to make a delay of 1000us, you need to execute 1000/1.117 =
894.88625 instructions. If you use 895 that's 1000.12us. Decimals will
be a problem if you have a crystal that does not divide evenly for your
application. If this was a 4MHz crystal, then 1000us = 1000 IC

If you have a base 1ms unit as above with 3.579545MHz, then your
"1s" will actually be 1s and 120us

Can't help you with the C (there's Nothing, and there's me standing next
to it) but a loop on that time scale should not be difficult

wbr

2010\02\23@005713 by William \Chops\ Westfield

face picon face

On Feb 22, 2010, at 5:20 PM, Jason Hsu wrote:

> So incrementing a variable just one time takes 45 clock cycles.  I  
> know that C isn't as efficient as Assembly language, but I didn't  
> expect it to be this inefficient.

First of all, How are you measuring this?

Secondly, that's 80 times through your loop in each 45 clocks.  The  
loop includes at least the increment, a compare, and a conditional  
jump.  And function call overhead every millisecond, and two levels of  
function call every 10ms, etc...

Thirdly, at (at least) four cycles per instruction, that's only 11  
instructions.  While that's certainly not GOOD, it's within the realm  
of "believable", especially if you're using one of those "free version  
contains reduced optimization, but which we mean that it's somewhere  
between "incredibly stupid" and "intentionally awful so you'll buy the  
real version."  (You haven't said which compiler you're using, or what  
optimization switches you're using, or any of that.)

Forth, look at the assembly language produced.  Your compiler ought to  
have an option to produce this, or you can look at it with mplab.  For  
example, using the free version of cc5x, generating code for a 16C54,  
I see the following when I run your code  through it:

delay_1_msec
                       ;        count = 0;
       CLRF  count
                       ;        while (count<80)
m001        MOVLW .80
       SUBWF count,W
       BTFSC 0x03,Carry
       GOTO  m002
                       ;                {
                       ;                count++;
       INCF  count,1
                       ;                }
       GOTO  m001
                       ;        }
m002        RETLW .0

I count 7 instruction cycles through that loop (so again, 11 would not  
be good, but isn't unthinkable.)

Lastly, it's a delay loop.  What do you care how fast it does  
nothing?  One uses a compiler largely because it does as well as you  
could do in assembly for COMPLEX operations, not trivial ones...

BillW

More... (looser matching)
- Last day of these posts
- In 2010 , 2011 only
- Today
- New search...