Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
en:examples:timer:delay [2015/03/26 13:24] heikopikneren:examples:timer:delay [2020/07/20 09:00] (current) – external edit 127.0.0.1
Line 1: Line 1:
-~~PB~~+<pagebreak>
 ====== Delay ====== ====== Delay ======
  
-//Necessary knowledge: [HW] [[en:hardware:homelab:controller]], [AVR] [[en:avr:architecture]], [LIB] [[en:software:homelab:library:pin]], [LIB] [[en:software:homelab:library:delay]]//+//Necessary knowledge:  
 +[HW] [[en:hardware:homelab:controller]],  
 +[AVR] [[en:avr:timers]], 
 +[LIB] [[en:software:homelab:library:pin]], [LIB] [[en:software:homelab:library:delay]], [LIB] [[en:software:homelab:library:timer]]//
  
 ===== Theory ===== ===== Theory =====
Line 49: Line 52:
 When dealing with the software delay it is important to know, that regardless its basic simplicity; it is extremely inefficient method from the power consumption point of view.  During all of these clock rates when the microcontroller is counting the useless, energy is consumed. So if using applications operating on batteries, it is not wise to write long software delays. Wiser is to use hardware timers, which are working independently and wake the processor from hibernating when it is time to continue the work.     When dealing with the software delay it is important to know, that regardless its basic simplicity; it is extremely inefficient method from the power consumption point of view.  During all of these clock rates when the microcontroller is counting the useless, energy is consumed. So if using applications operating on batteries, it is not wise to write long software delays. Wiser is to use hardware timers, which are working independently and wake the processor from hibernating when it is time to continue the work.    
  
 +The software delay is not the only method for creating breaks. The same can be done using timer. Timer is a hardware which counts up or down with a certain frequency. The clock frequency of the timer can be generated from microcontroller’s frequency or from some kind of other outside pace. In general the clock frequency can  be divided with a multiplier to reach a smaller frequency - this is done with prescaler. Important fact is that the fixed clock frequency timer’s value is linearly related to the time. The time can be calculated by multiplying the period of the clock frequency of the timer with the value of the timer.
  
-===== Practice ======+[{{  :examples:timer:timer_counter.png?300|The events which come with the changes of AVR timer.}}] 
 + 
 +AVR counters can be made to inform about overflow of the counter or achieving compare mach. Overflow happens when the counter has the maximal possible value and the cycle starts all over again form 0. With reaching a pre set value during the moment of growth of the counter’s value it is compared to the value given by the user. On the occurrence of the event, the bits in the status indexes of the AVR are automatically set as high.   
 +  
 +For generating a delay using a timer, it is only necessary to set the timer and waiting for the status bit to go high. Different from the software delay, the work of the timer is not depending on the compiler, which makes them more reliable. At the same time the diversity (or complexity) of the set-up of the AVR counter can be considered fairly troublesome. Depending on the microcontroller’s timing signal, may happen that it will not divide exactly with the desired delay period and the delay will not be accurate. 
  
 The following code of a program is about software delay function //sw_delay_ms// , which makes a given delay in milliseconds using the parameter //count//. The function uses avr-libc library’s function //_delay_ms// which is partly written in assembler language. The reason why the //_delay_ms// is not used in this exercise immediately is that when using the //_delay_ms// problems may occur when the delays are long. The //sw_delay_ms// enables creating 65535 ms long delays without any complications.  The following code of a program is about software delay function //sw_delay_ms// , which makes a given delay in milliseconds using the parameter //count//. The function uses avr-libc library’s function //_delay_ms// which is partly written in assembler language. The reason why the //_delay_ms// is not used in this exercise immediately is that when using the //_delay_ms// problems may occur when the delays are long. The //sw_delay_ms// enables creating 65535 ms long delays without any complications. 
  
 <code c> <code c>
-// +// Software delay in milliseconds
-// Software delay in milliseconds+
-//+
 void sw_delay_ms(unsigned short count) void sw_delay_ms(unsigned short count)
 { {
Line 63: Line 69:
  while (count-- > 0)  while (count-- > 0)
  {  {
- // 1ms delay with a special function.+ // 1ms delay with a special function
  _delay_ms(1);  _delay_ms(1);
  }  }
Line 72: Line 78:
  
 <code c> <code c>
-// +// The demonstration program of the software delay of the HomeLab 
-// The demonstration program of the software delay of the HomeLab. +// The program is blinking a LED for a moment after ~1 second
-// The program is blinking a LED for a moment after ~1 second+
-//+
 #include <homelab/pin.h> #include <homelab/pin.h>
 #include <homelab/delay.h> #include <homelab/delay.h>
    
-// 
-// Determining the pin of the test LED 
-// 
-pin debug_led = PIN(B, 7); 
-  
-// 
 // Main program // Main program
-// 
 int main(void) int main(void)
 { {
- // Setting the pin of the LED as output. + // Setting the pin of the LED as output 
- pin_setup_output(debug_led);+ pin_setup_output(led_debug);
    
  // Endless loop   // Endless loop
Line 96: Line 93:
  {  {
  // Lighting the LED  // Lighting the LED
- pin_clear(debug_led);+ pin_clear(led_debug);
    
  // Software delay for 100 ms  // Software delay for 100 ms
Line 102: Line 99:
    
  // Switching off the LED  // Switching off the LED
- pin_set(debug_led);+ pin_set(led_debug);
  
- // Software delay for 900 milliseconds.+ // Software delay for 900 milliseconds
  sw_delay_ms(900);  sw_delay_ms(900);
  }  }
Line 111: Line 108:
  
 Although it seems that the LED blinks in every 1 second, the time is actually a little bit longer, because the callouts of LED’s and delay functions are taking a couple of clock rates of the microcontroller Although it seems that the LED blinks in every 1 second, the time is actually a little bit longer, because the callouts of LED’s and delay functions are taking a couple of clock rates of the microcontroller
 +
 +The program code below is a delay function based on a timer, which is simplified a little bit. The principle of counting is the same as it is at software delay function – a desired amount of 1 ms long delays are produced. The delay is produced with an 8-bit counter 0. It is calculated previously that at clock frequency 14,7456 Mhz the timing signal has to be divided at least 64 times, so that the counter would not reach to overflow in 1 ms. The value which the counter must have so that the overflow occurs after 1 ms is presented in the form of an expression and the variable is //timer_start//. //F_CPU// which is a constant in macro-language, that shows clock frequency in Hz. The clock frequency should be 25,6 at the moment but since fractions can not be used, the initial value will be set 26. Unfortunately here arises a mistake in delay time, however it is fairly small (-1,7 μs). 
 +
 +In the cycle takes place initialing of the counter and zeroing the flag of the overflow (by writing 1 into that). Then is waited until the counter counts to 256 from the initial value, i.e. to the overflow. At the moment of the overflow the flag goes high and the delay of 1 ms has taken place. In the end of the function the timer is stopped.       
 +
 +
 +<code c>
 +// Hardware delay in milliseconds
 +void hw_delay_ms(unsigned short count)
 +{
 + // Calculating the initial value of the timer
 + register unsigned char timer_start = 256 - F_CPU / 1000 / 64;
 +
 + // Starting the timer
 + timer0_init_normal(TIMER0_PRESCALE_64);
 +
 + // Counting the variable of the delay to the 0
 + while (count-- > 0)
 + {
 + // Initializing the timer
 + timer0_set_value(timer_start);
 +
 + // Zeroing the overflow flag
 + timer0_overflow_flag_clear();
 +
 + // Waiting for overflow
 + while (!timer0_overflow_flag_is_set())
 + {
 + asm volatile ("nop");
 + }
 + }
 +
 + // Zeroing the overflow flag
 + timer0_overflow_flag_clear();
 +
 + // Stoping the timer
 + timer0_stop();
 +}
 +</code>
 +
 +Referenced delay function uses a timer library whose source code for ATmega controller looks like the following:
 +
 +<code c>
 +// Timer 0 prescaler selection type
 +typedef enum
 +{
 + TIMER0_NO_PRESCALE         = 0x01,
 + TIMER0_PRESCALE_8          = 0x02,
 + TIMER0_PRESCALE_32         = 0x03,
 + TIMER0_PRESCALE_64         = 0x04,
 + TIMER0_PRESCALE_128        = 0x05,
 + TIMER0_PRESCALE_256        = 0x06,
 + TIMER0_PRESCALE_1024       = 0x07
 +}
 +timer0_prescale;
 +
 +// Setting Timer 0 to a normal mode
 +inline void timer0_init_normal(timer0_prescale prescale)
 +{
 + TCCR0 = prescale & 0x07;
 +}
 + 
 +// Stopping the Taimer 0
 +inline void timer0_stop()
 +{
 + TCCR0 = 0x00;
 +}
 +
 +// Taimer 0 value set
 +inline void timer0_set_value(unsigned char value)
 +{
 + TCNT0 = value;
 +}
 +
 +// Timer 0 overflow flag clear
 +inline void timer0_overflow_flag_clear(void)
 +{
 + bit_set(TIFR, TOV0);
 +}
 +
 +// Timer 0 overflow flag state reading
 +inline bool timer0_overflow_flag_is_set(void)
 +{
 + return (bit_is_set(TIFR, TOV0) ? true : false);
 +}
 +</code>
 +
 +The following is a similar program to the example of the software delay. In the shorter 100 ms half-period the LED is lit and on the longer 900 ms half-period it is switched off. As the result the LED is blinking after every second. Unfortunately, in this example the period isn't precisely 1 second either, because executing other functions of the program takes also time. For exact timing  a 16-bit timer with interruptions must be used. 
 +
 +<code c>
 +// Demonstration program of hardware delay of the HomeLab
 +// The Program blinks LED for a moment after every ~1 second
 +#include <homelab/pin.h>
 +#include <homelab/delay.h>
 +
 +// Main program
 +int main(void)
 +{
 + // Setting the pin of the  LED as output
 + pin_setup_output(led_debug);
 +
 + // Endless loop
 + while (true)
 + {
 + // Lighting the LED
 + pin_clear(led_debug);
 +
 + // Hardware delay for 100 milliseconds
 + hw_delay_ms(100);
 +
 + // Switch off of the LED
 + pin_set(led_debug);
 +
 + // Hardware delay for 900 milliseconds
 + hw_delay_ms(900);
 + }
 +}
 +</code>
 +
en/examples/timer/delay.1427376293.txt.gz · Last modified: 2020/07/20 09:00 (external edit)
CC Attribution-Share Alike 4.0 International
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0