CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

help with timer

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
hemnath



Joined: 03 Oct 2012
Posts: 242
Location: chennai

View user's profile Send private message

help with timer
PostPosted: Wed Feb 10, 2016 11:36 pm     Reply with quote

hi all,
Code:
#include "18F2520.h"
#include "f2520_regs.h"
#fuses HS
#use delay(clock=12000000)
#use fixed_io(b_outputs= PIN_B4,PIN_B5,PIN_B6,PIN_B7) 

#include "defines.h"

#include "lcd.c"

int1 DOWN, ENTER, UP = 0;

unsigned int16 delay_ms_flag = 0;

unsigned int16 milliseconds;
unsigned int SECONDS1, SECONDS2, SECONDS3, SECONDS4 = 0;

void timer0_init();

#INT_EXT
void interrupt()
{
   DOWN = 1;
   clear_interrupt(INT_EXT);      // clear flag
}

#INT_EXT1
void interrupt_1()
{
   ENTER = 1;
   clear_interrupt(INT_EXT1);      // clear flag
}

#INT_EXT2
void interrupt_2()
{
   UP = 1;
   clear_interrupt(INT_EXT2);      // clear flag
}

#INT_TIMER0
void timer0_isr()
{
   if(TMR0IF == 1)
   {
      delay_ms_flag++;   // increment variable
      milliseconds++;
      
      if(milliseconds >= 1000)      //   
      {
         milliseconds = 0;
         SECONDS1++;
         SECONDS2++;
         SECONDS3++;
         SECONDS4++;
      }
      
      TMR0IF = 0;         // clear flag
      TMR0IE = 1;         // enable interrupt 
      
      TMR0H = 0xF4;      // 1ms for 12Mhz
      TMR0L = 0x47;
   }
}

void main()
{
   lcd_init();                     //   LCD initialization

   setup_adc_ports(NO_ANALOGS|VSS_VDD);   
   setup_adc(ADC_OFF|ADC_TAD_MUL_0);
   
   setup_comparator (NC_NC_NC_NC);      // Disable comparator

   ext_int_edge(H_TO_L);             // External Interupt High to LOW transistion
   enable_interrupts(INT_EXT);         // Enable External Interrupt
   
   ext_int_edge(1, H_TO_L);         // External Interupt High to LOW transistion
   enable_interrupts(INT_EXT1);      // Enable External Interrupt1   
   
   ext_int_edge(2, H_TO_L);         // External Interupt High to LOW transistion
   enable_interrupts(INT_EXT2);      // Enable External Interrupt2 
   
   timer0_init();

   enable_interrupts(INT_TIMER0);      
   enable_interrupts(GLOBAL);         // Enable Global Interrupt

   while(1)
   {         
      if(ENTER == 1)
      {
         disp_cmd(0x80);
         printf(disp_data, "ENTER");
         ENTER = 0;
         delay_ms_flag = 0;
         while(delay_ms_flag <= 200);

         SECONDS1 = 0;
         while(SECONDS1 <= 30)
         {
            disp_cmd(0x80);
            printf(disp_data, "%u", SECONDS1);
            ENTER = 0;            
         }
      }

      delay_ms_flag = 0;
      while(delay_ms_flag <= 1000);   

      disp_cmd(0x01);
      delay_ms_flag = 0;
      while(delay_ms_flag <= 1000);         
   }
}

void timer0_init()
{   
   T0CON = 0b00001000;      // 16 bit, prescaler not assigned
   
   TMR0H = 0xF4;            // 1ms for 12Mhz
   TMR0L = 0x47;
   
   TMR0ON = 1;               // Timer1 ON
   TMR0IF = 0;               // set Timer1 Interrupt Flag as zero
   TMR0IE = 1;               // Set Timer1 Interrupt Enable = 1   
}


I have a problem with the above code. displayed and compared the variable SECONDS1 with the actual clock, there is a lag of 8 seconds. Seconds1 reaches 30 secs and in my stopwatch it displays 38 seconds.

Can anyone help me?
Ttelmah



Joined: 11 Mar 2010
Posts: 19569

View user's profile Send private message

PostPosted: Thu Feb 11, 2016 2:55 am     Reply with quote

A lot of comments first:

Use the compiler.....

You are trying to use what is effectively partially ported 'assembler' in the compiler. A lot of wasted instructions. For instance:
Code:

#INT_EXT
void interrupt()
{
   DOWN = 1;
}

Is all that is needed for this interrupt handler. If you read the manual for interrupts, there is the line:
"The compiler will generate code to jump to the function when the interrupt is detected. It will generate code to save and restore the machine state, and will clear the interrupt flag".

Note the 'and will clear the interrupt flag'.

Then for the timer setup, use the setup_timer function.

It is the old comment about 'keeping a dog, and barking yourself'. You have the compiler to save you from having to do a lot of basic tasks, yet your code does not reflect this.

Then on the timer interrupt handler, you test for the interrupt flag being set. Pointless again. The interrupt handler will only be called if the flag is set.

There is a generic problem with the code. Setting a timer 'to' a value in it's ISR, does not really work (there are exceptions, for instance you can set bit 15 of a timer, or using a timer with a very large prescaler). The problem is that the timer _will_ have counted quite a few cycles once you get to the ISR (and even worse, where you set it at the end of the ISR...), so when you set it to a value, these counts are lost. Hence the timer will always run slow...
This can be improved by _adding_ the required offset to the timer, but there will still be a small loss.
This will be worse because your count is wrong. The timer interrupts when it wraps from 65535 to 0. So to count to 3000, requires it to be loaded with 65536-3000 = 62536 = 0xF448. Yet you load with 0xF447....

Much better, especially on a timer running as fast as this, to use the timer that can automatically reload itself for you. Timer2.

So your interrupt routine to use addition becomes:
Code:

#INT_TIMER0
void timer0_isr()
{
    set_timer0(get_timer0()+62536);
    delay_ms_flag++;   // increment variable
    milliseconds++;
     
    if(milliseconds >= 1000)      //   
    {
        milliseconds = 0;
        SECONDS1++;
        SECONDS2++;
        SECONDS3++;
        SECONDS4++;
    }
}


However Timer2 will be far superior.

setup_timer_2(T2_DIV_BY_4, 249, 3);

This gives 3000 counts. (4 * 250 * 3).

The timer2 interrupt will then occur every mSec, without having to set or change anything.
Mike Walne



Joined: 19 Feb 2004
Posts: 1785
Location: Boston Spa UK

View user's profile Send private message

PostPosted: Thu Feb 11, 2016 3:28 am     Reply with quote

Have a look at your interrupt routine.

How long does it take to get into the routine?
How long does it take to perform all actions within the routine?
Why do you need to enable interrupts within the routine?
What is the Timer0 value just before you reset it to -3000?

Mike
asmboy



Joined: 20 Nov 2007
Posts: 2128
Location: albany ny

View user's profile Send private message AIM Address

PostPosted: Thu Feb 11, 2016 6:38 am     Reply with quote

do you NEED actual millisecond resolution?

the way to design complex time keeping in a PIC program
is to determine the required granularity of your clock and
then back into your clock frequency.
for precise binary seconds or binary-divisible fractions

8.388608 and 16.77716 mhz are ideal oscillators /crystals
for whole seconds ( time 0-16bit prescaler div_32 or div64)
and binary fractions 500msec 250msec 125msec etc

if you really need 1 millisec granularity
a good choice of master oscillator is to use
a clock of 8,192mhz , or 16.384mhz prescalar of 8 or 16 and
then be sure to set timer0 to 8 bit mode.

the natural rollover then is 1msec with no jiggering of the
timer registers inn the ISR and perfect time keeping.

i say "do you need" because 1000 ints/sec is gonna suck some life out of any program running in the foreground.

i plan my code to know in advance what my tightest timing requirement is in ANY unit of time and make multiples of it as my master clock.

you are trying to do it in reverse with an arbitrary clock and that will always cause you to waste cycles in your ISR
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group