Modified version of the delay function in avr-gcc

Publisher:丝语轻风Latest update time:2016-01-21 Source: eefocusKeywords:avr-gcc Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere
In 51, we write our own delay functions, whether in assembly or C. Although there are templates, it is still a bit annoying sometimes. Haha. But when we use avr microcontrollers, we are blessed. Because avr-gcc provides us with a very convenient delay function, just include:

#include    
and you can use it. This header file defines two levels of delay functions:
void   _delay_us (double __us);       //microsecond level
void   _delay_ms (double __ms);     //millisecond level

But don't be happy too soon, because there are conditions for using them correctly in your avr-gcc. I will explain it slowly below.

This parameter is related to the F_CPU value in the Makefile. The value of the F_CPU variable defined by the Makefile will be passed to the compiler. If you use AVR_studio 4.1X to edit and debug, use the embedded AVR-GCC for compilation, and let AVR_studio automatically generate Makefile for you, then you can go to:
                                          Project -> Configuration Options -> Gerneral -> Frequency   as shown below:

Modified version of the delay function in avr-gcc [ourdev]
Write down the value of your F_CPU. The value of F_CPU indicates the operating frequency of your AVR microcontroller. The unit is Hz, not MHZ. Don't make a mistake. For example, if it is 7.3728M,   then F_CPU = 7372800.   You
will find a definition like this in the "delay.h" header file:
#ifndef F_CPU
# warning "F_CPU not defined for "
# define F_CPU 1000000UL     // 1MHz
#endif

This is to provide a default frequency value of 1MHz when you do not define the variable F_CPU (including null) or AVR_studio Frequency does not give a value. This will prevent the compiler from making mistakes when compiling.

Below are the entities of these two functions:
void _delay_us(double __us)         //   microseconds
{
uint8_t __ticks;
double __tmp = ((F_CPU) / 3e6) * __us;   // 3e6 is because the call to _delay_loop_1() is three instructionsif
(__tmp < 1.0)
  __ticks = 1;
else if (__tmp > 255)
  __ticks = 0;
else
  __ticks = (uint8_t)__tmp;
_delay_loop_1(__ticks);
}

void _delay_ms(double __ms)       //milliseconds
{
uint16_t __ticks;
double __tmp = ((F_CPU) / 4e3) * __ms;   // 4e3 is because the call to _delay_loop_2() is four instructionsif

(__tmp < 1.0)
  __ticks = 1;
else if (__tmp > 65535)
  __ticks = 0;
else
  __ticks = (uint16_t)__tmp;
_delay_loop_2(__ticks);
}

You will find that they both call the   two functions _delay_loop_1(); and _delay_loop_2(); respectively. These two functions
are as follows:
void   _delay_loop_1(uint8_t __count)
{
__asm__ volatile (
  "1: dec %0" " "
  "brne 1b"
  : "=r" (__count)
  : "0" (__count)
);
}
 
From the function comments, we can know that this function is used to delay 3 crystal clock cycles, excluding the time spent by the program calling and exiting the function. The parameter __count of this function is an 8-bit variable, from which we can calculate the maximum delay time of this function according to the crystal frequency used by the system:
At 1MHz:   MAX_DELAY_TIME  (1/1000000)*3*256  0.000768  768  uS
At 8MHz:   MAX_DELAY_TIME  (1/8000000)*3*256  0.000096  96   uS
............
F_CPU      MAX_DELAY_TIME  (1/F_CPU)*3*256
and so on.
void  _delay_loop_2(uint16_t __count)
{
__asm__ volatile (
  "1: sbiw %0,1" " "
  "brne 1b"
  : "=w" (__count)
  : "0" (__count)
);
}
 
This function delays 4 crystal oscillator cycles. The parameter is a 16-bit variable. Similarly, we can calculate the maximum delay time of this function:
At 1MHz:   MAX_DELAY_TIME  (1/1000000)*4*65535  0.26214  262.1  mS
At 8MHz:   MAX_DELAY_TIME  (1/8000000)*4*65535  0.03277  32.8   mS
............
F_CPU      MAX_DELAY_TIME  (1/F_CPU)*4*65535
and so on.
 
Important tips: _delay_loop_1(0) and _delay_loop_1(256) have the same delay!!
Similarly, _delay_loop_2(0) and _delay_loop_2(65536) have the same delay!! The delays of these functions are all the longest delays.



These two functions are written in the inline assembly format of avr-gcc. I will not go into the specific syntax rules. You can refer to avr-libc. However, these two functions are very simple and easy to understand. One is byte decrement and the other is word decrement. If you look carefully at the above functions, you will find that there are the following conditions for using them correctly: 1.
        First, you must correctly define the value of your F_CPU, that is, the actual frequency of your AVR microcontroller. Otherwise, the delay will be inaccurate. (The delay is only inaccurate in numbers, which can be calculated specifically)
        2. You must turn on optimization when compiling. Do not select 0 for OPT in Makefile, and do not select O0 if AVR_studio.
        3. When you use these two delay() functions, use constants instead of variables as the actual parameters passed to the two functions.
        4. The time parameters __ms and __us have a range. Do not exceed the range. __ms: 1 - [262.14 ms / (F_CPU/1e6) ],   __us: 1- [768 us / (F_CPU/1e6)]   . [...]   means to take the integer part. (Is the conclusion here wrong?).
The maximum value of __us should be 768us (at 1M frequency)    MAX_VALUE  256*3/F_CPU s, the minimum value is 3 clock cycles MIN_VALUE  1*3/F_CPU s;,
the maximum value of __ms MAX_VALUE  65536*4/F_CPU s, MIN_VALUE  1*4/F_CPU s;


Only with the above conditions can you correctly use the delay functions _delay_us () and _delay_ms (). For the third condition, why should we choose constants, and why should we turn on the optimization option for the second condition. This is to allow the compiler to calculate the delay value when compiling, rather than compiling it into the program and calculating it at runtime. In that case, it will increase the length of the code, and it will also make the delay time of your delay program longer or unpredictable. Timing errors will occur.
 
 
It has been modified in version 08. The specific functions are as follows:
void
_delay_us(double __us)
{
 uint8_t __ticks;
 double __tmp = ((F_CPU) / 3e6) * __us;
 if (__tmp < 1.0)
  __ticks = 1;
 else if (__tmp > 255)
 {
  _delay_ms(__us / 1000.0);
  return;
 }
 else
  __ticks = (uint8_t)__tmp;
 _delay_loop_1(__ticks);
}
When __us is too large, _delay_ms() will be called; from the above, we can know that when 8M, _delay_ms can have a minimum delay of 4/8000000=0.5us.  When 1M, the minimum delay is 4/1000000=4us, and the connection can be established.
void
_delay_ms(double __ms)
{
 uint16_t __ticks;
 double __tmp = ((F_CPU) / 4e3) * __ms;
 if (__tmp < 1.0)
  __ticks = 1;
 else if (__tmp > 65535)
 {
  // __ticks = requested delay in 1/10 ms
  __ticks = (uint16_t) (__ms * 10.0);
  while(__ticks)
  {
   // wait 1/10 ms
   _delay_loop_2(((F_CPU) / 4e3) / 10);
   __ticks --;
  }
  return;
 }
 else
  __ticks = (uint16_t)__tmp;
 _delay_loop_2(__ticks);
}
When __ms is too large, only __ticks -- is used for delay. First, a delay of 262ms (1M, 32ms 8M) is used, and then the decrement method is used.
Keywords:avr-gcc Reference address:Modified version of the delay function in avr-gcc

Previous article:Understanding of hardware stack and software stack in AVR
Next article:AVR bit operation record

Latest Microcontroller Articles
  • Learn ARM development(21)
    First, declare the task pointer, because it will be used later. Task pointer volatile TASK_TCB* volatile g_pCurrentTask = NULL;volatile TASK_TCB* vol ...
  • Learn ARM development(20)
    With the previous Tick interrupt, the basic task switching conditions are ready. However, this "easterly" is also difficult to understand. Only through continuous practice can we understand it. ...
  • Learn ARM development(19)
    After many days of hard work, I finally got the interrupt working. But in order to allow RTOS to use timer interrupts, what kind of interrupts can be implemented in S3C44B0? There are two methods in S3C44B0. ...
  • Learn ARM development(14)
    Since development under LINUX is still quite troublesome, is there a more convenient and simple development method under WINDOWS? The answer is yes. Of course, it is not a development tool like ADS, because it ...
  • Learn ARM development(15)
    When using GCC to develop ARM, you will definitely encounter compiler problems. For example, you will encounter various warnings and errors when compiling C code. For example, I encountered several warnings yesterday, so let's take a look at what these warnings are ...
  • Learn ARM development(16)
  • Learn ARM development(17)
  • Learn ARM development(18)
  • Embedded system debugging simulation tool
Change More Related Popular Components

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号