Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

Timer Interrupt of AVR

Status
Not open for further replies.

imranahmed

Advanced Member level 3
Joined
Dec 4, 2011
Messages
817
Helped
3
Reputation
6
Reaction score
3
Trophy points
1,298
Location
Karachi,Pakistan
Activity points
6,492
Please let me know that can we generate different time delays using timer interrupt of AVR series uC`s for several functions?
 

Hi,

Yes.

The timers are very complex and usefull. For longtime delay you may need to extend the timers with software.

Klaus
 
Dear Klaus,

I need not to obtain long delay in program but I need explanation here,

"If I generate Timer1 overflow interrupt for 1 sec and use it but for same timer1 overflow interrupt can I generate 500ms or any delay in other function".
 

Hi,

I'm not sure if i understand you right.

If you want one event every 1 second and another event every 500ms but use the same timer:
Then i'd configure timer1 to interrupt every 100ms. Every 5 timer ticks trigger task1 and every 10 timer ticks trigger task2.
You can choose to set flags to only trigger the tasks(flags) within the isr, but run the tasks in main loop,
Or you can run the tasks within thr isr.

Hope this is what you meant.
Klaus
 
Dear Klaus,

Thank you very much I programmed as you define, program runs very smoothly and I am free to generate any time delay using timer interrupt and leave time delay (_delay_ms) function.
 

Dear Klaus,

Please can you refer me some example code for using timer interrupt to generate different time delays.
 

Hi,

No code available.

Interrupt with variable delay between ticks:
Setup timer in ctc mode
Select desired clock sorce and prescaler
Select top value (Ocr, delay time)
Clear timer overflow flag
Enable timer overflow interrupt
Enable clobal interrupt

Change ocr as your variable delay time.

Example: 1MHz cpu clock, delay time 100ms
This means interrupt every 100.000 clock cycles
Ocr can not be set to 100000 therfore you need a prescaler, lets use 8.
Now the timer overflow needs to be every 100000/8 counts = 12500
Set ocr to 12500-1 = 12499

For 20ms set ocr to 2499
For 1 ms set ocr to 124

Hope this helps
Klaus
 
Code:
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
unsigned char a=0;

void InitTimer1(){
  
  TCCR1B = 0x0B;   
  OCR1A  = 12499;   
  TIFR   = 0x00;                 
  TIMSK  = 0x04;   
  sei();  
}
         
         
void main(void)
{

DDRD  = 0xff;
PORTD = 0x00;

InitTimer1();
while(1)
{
PORTD = a;
}
}
 
ISR(TIMER1_OVF_vect) 
{
a++;
}

Dear KlausST,

I wrote this code but it caanot work.
 

Hi,

at first look it seemd to be OK

But some considerations:
* definition of "a" is OK
* I found out that you use prescaler of 64 instead of 8 because you work with 8Mhz.
* OCR1A: some older compilers had a problem with the order of acessing the two 8 bit registers: First write H then Write L is correct.
* TIFR: clear a flag by writing a "1";
--> so it has to be: TIFR = 0xFF;
* TIMSK is OK
* sei is OK.

ISR: You have chosen Mode 4, ctc with OCR1A; with that flag OCF1A is set; activating ISR "Output Compare Match A";
-->Use "TIM1_COMPA_vect".

********
Now it should work.

BTW:
because
PORTD = a;
is a very small task you can do this within the ISR.
But i know it´s just for trial..

Good luck
Klaus
 
Dear KlausST,

Thank you for replying.

It should be something like that,

12499=30D3 ==> H=30 , L=D3.

Code:
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
unsigned char a=0;

void InitTimer1(){
  
  TCCR1B  = 0x0B;   
  OCR1AH = 0x30;
  OCR1AL = 0xD3;  
  TIFR     = 0xFF;                 
  TIMSK   = 0x04;   
  sei();  
}
         
         
void main(void)
{

DDRD  = 0xff;
PORTD = 0x00;

InitTimer1();
while(1)
{
PORTD = a;
}
}
 
ISR(TIMER1_COMPA_vect) 
{
a++;
}

But one thing is remaining is that how to use as a delay function,below code.

Code:
while(1)
{
PORTD = 0xa0;
delay by using timer interrupt
PORTD = 0x30;
delay by using timer interrupt
PORTD = 0x08;
delay by using timer interrupt
}
}
}
 

Hi Imran,

i hope the code is working now.

Remaining wait function:
Now i am wondering why you want a delay by interrupt.
I see three main benifits with delay by timer interrupt:
1) there is a lot of processing power free during this delay time. You can use it in main loop. But the timed job (here PORTD update) should be done within ISR.
2) you can power down during this delay and save power. This is good for a battery driven device.
3) you want exact timing, that is not influenced by other tasks.

Some examples:
for 1) In your main loop you measure temperature and display it. But if temperature is high then a LED should blink. The blinking of the LED can be handled by the ISR. Clean constant blinking.
for 2) measure temperature, calculate and transmit data to PC, and power down. Wakeup by interrupt. This can be done exactely every 1s independent of task time. and also save as much battery power as possible.
for 3) this is how a software clock works. Within the ISR update the time_data. and the time is exact, independent of task time in main loop.

Klaus
 
Dear KlausST,

The code is working properly.

Actually I am making volt/amp meter combine ,there is a need of delay between ADC_read function for proper
obtaining of ADC samples.The delay is between changing one channel to another channel.
I attached my part of code this is working properly but I need to use timer interrupt for delay because delay_ms
function slow down the processing and take more space in memory.

Code:
void Debounce()
{
   uint8_t i;
   for(i=0;i<20;i++)
   {
      _delay_loop_2(0);
   }
}
void Wait()
{
   uint8_t i;
   for(i=0;i<10;i++)
   {
      _delay_loop_2(0);
   }
}
//This is below done in main loop.
while(1)
   {
    
	 if((PIND & (1<<PD6))== 0){
	 p++;
	 Debounce(); 
     }
     switch(p){
	 	 
	 case 0:	 
     
	  
     Print1(read_adc(1));  //Yellow Volts
	 Wait();
      
	 Print(read_adc(3));   //Yellow Amps
	 Wait();
	 
	 break;

	 case 1:	 
	 	     
	 Red=(read_adc(0));  
	 _delay_us(60);
     Blue=(read_adc(2));
	 _delay_us(60);
     YellowAmps=(read_adc(3));	     
	 _delay_us(60);

	 Red_Blue_Result=((Red+Blue)/2)*1.732;
 
     Print1(Red_Blue_Result);
     _delay_us(60);

  	 Print(YellowAmps);   //Yellow Amps
	 Wait();
     
	 break;
 

Dear KlausST,

The voltmeter I build is successfully runs. But some features I need to add in my meter,

1) When we power-on the meter the voltage should be display with slowly increasing
for example: when on first display 98v then 149v then 202v then 220v or any gap between
increasing voltage.

2) Signal conditioning for AC voltage sensing.
 

Hi,

1) a simple filter could be like this: dv = dv + ( av - dv) * fc
Where dv is the value to display, and av the actual measured value and fc the filter constant.

Fc depends on how often the function is called, either every display update or every adc sample.

For a rule of thumb the cutoff frequency is the function call frequency * fc.

For exampl if you want a cutoff frequency ofc1 Hz and you call the function with 100Hz, then fc should be about 0.01.

Hope this helps
Klaus
 
1) a simple filter could be like this: dv = dv + ( av - dv) * fc
Where dv is the value to display, and av the actual measured value and fc the filter constant.

Fc depends on how often the function is called, either every display update or every adc sample.

For a rule of thumb the cutoff frequency is the function call frequency * fc.

For exampl if you want a cutoff frequency ofc1 Hz and you call the function with 100Hz, then fc should be about 0.01.

Dear KlausST

I do not understand what you want to say. :thinker:
 
Last edited:

Hi Imran,

You want a slowly decreasing value on the display. Now a example. For every adc value i take 220.
For my filter constant i take 0.45
The init value to disply is 0.

With the formula i calculate: dv = 0 + ( 220 - 0) × 0.45 = 99
My first display value is 99.
The next time i calculate: dv = 99 + (220 -99) × 0.45 = 153 --> display
Next time: dv = 153 + (220 -153) × 0.45 = 183 --> display
And so on

Is this what you meant with increasing display?

Klaus
 
Dear KlausST,
Thanku

The uC works at 8MHz and ADC prescalar set to 64 now ADC frequency is 125kHz.

How to calculate fc=filter constant I think by this==>1/2*pi*f*c.
and how this is decreasing value?. Is this value not increasing.
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top