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

Using interrupt to generate 16 bit timer

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







Using interrupt to generate 16 bit timer
PostPosted: Mon Mar 19, 2007 5:17 am     Reply with quote

(Using a PIC 12F683)
I've setup the internal timer:
Code:
   setup_timer_0(RTCC_INTERNAL | RTCC_8_BIT | RTCC_DIV_256);

and this works fine. Because the chip is currently working at 4MHz this will tick every 256us, and overflow after approx 65ms. I want this level of precision. I also require a longer range to this timing - I need to get an accurate time interval of several seconds.

To do this I am trying to use an interrupt to increment a second 8bit counter:
Code:
#int_RTCC
void RTCC_isr(void) {
   timer1++;
}


As far as I understand, every time timer0 overflows it generates an interrupt. The interrupt should be serviced which should increment the timer1 counter. This is not happening reliably! I think some other part of my code must be interfering with the timing, but (as you can no doubt tell) I am new to this so don't know where to start...
(My other code is taking these two 8bit "time" codes, manipulating them and sending them via an IR pulse train)

I hope I have posted enough info, but let me know what else I need to post so you can help!
Thanks,
Ben

Here's the important stuff (I think):

Code:

void SendPreamble();
void SendEnd();
void SendData(int data);
void SendTime(int sender);
int reverse(int backwards );
int timer1=0, sender1, sender2;

#int_RTCC
void RTCC_isr(void) {
   timer1++;
}

int main()
{
CMCON0 = 7; // Turn off the comparators
ADCON0 = 0; // Set all i/o pins to digital
ANSEL = 0; // Turn off the A/D converter

   set_tris_a(0b00011011);         //set port a directions
   port_a_pullups(0b011011);
   set_options(0b00001000);      //GPWU, GPPU, T0CS, T0SE, PSA, PS2, PS1, PS0
   setup_timer_0(RTCC_INTERNAL | RTCC_8_BIT | RTCC_DIV_256);

   VISLED=0;
   IRLED=0;
   timer1=0;
   sender1=0;
   sender2=0;


   enable_interrupts(GLOBAL);
   enable_interrupts(INT_RTCC);

while(true){

   if(!SW1 && SW2 && SW3){
      VISLED=1;
      sender1=reverse(timer1);
      sender2=reverse(get_rtcc());

      SendPreamble();
      SendData(0);
      SendTime(sender1);
      SendTime(sender2);
      SendEnd();

      delay_ms(20);
      VISLED=0;
      }
   }                           //end of while(true)

}                              //end of main loop

void SendPulse()
{
   int i;
   for(i=0;i<32;i++){
   IRLED = 1;
   delay_us(13);
   IRLED = 0;
   delay_us(6);
   }
}

void SendNull()
{
   int j;
   for(j=0;j<32;j++){
   IRLED = 0;
   delay_us(13);
   IRLED = 0;
   delay_us(6);
   }
}

void SendPreamble()
{
   SendPulse();
   SendNull();
   SendPulse();
   SendPulse();               //Preamble = 1011
}

void SendEnd()
{
   SendNull();
   SendPulse();
   SendPulse();               //End = 011
}

void SendData(int data)
{
   if(data==0)
   {
      SendNull();
      SendNull();
      SendNull();
   }
   if(data==1)
   {
      SendNull();
      SendNull();
      SendPulse();
   }
   if(data==2)
   {
      SendNull();
      SendPulse();
      SendNull();
   }
}

int reverse( int backwards )
{
   int result=0;
   int x;

    for( x = 0; x < 8; x++)
       {
      if(bit_test(backwards,7-x))
         bit_set(result,x);
      else
         bit_clear(result,x);
       }

    return(result);

}

void SendTime(int sender)
{
   int k;
   for(k=0;k<8>>=1;
   }
}
Guest








PostPosted: Mon Mar 19, 2007 6:54 am     Reply with quote

1) Define "reliably". It misses some steps, it falis to increment, it increments with different times between increments?

iīm supposing that you are missing points, like if it was increased twice... letīs see how much time an interaction of your code takes:

VISLED=1; // negligibe
sender1=reverse(timer1); // negligibe
sender2=reverse(get_rtcc()); // negligibe

SendPreamble(); // 76us
SendData(0); // 57us
SendTime(sender1); // donīt know (code mangled)
SendTime(sender2); // donīt know
SendEnd(); // 57us

delay_ms(20); // 20ms
VISLED=0; // negligibe


total: about 20.17ms (without the unknown parts) so about 1/3 of the overflow time. It looks ok. Maybe the problem is at the receiver: If it gets the data and tries to print it maybe it canīt be done in under 65ms so it looses data.
WideBoy
Guest







PostPosted: Mon Mar 19, 2007 8:17 am     Reply with quote

Thanks for getting back to me.
I'm picking up the IR data train with a USB receiver. I can then see the data along with a timestamp from my USB monitor - and they don't correspond!

I've tried monitoring the output with my oscilloscope, but I can't see enough signal repetitions with a high enough resolution to draw any conclusions. If I change the program so that it just sends 2 numbers for the 2 8bit times then the sending/receiving works fine, and I can monitor the USB bus and see that the correct signal is being received every ~45ms.

The problem only starts to occur when I want to send the correct timing!

The missing code didn't paste properly, so I've reposted the function below:

Code:

void SendTime(int sender)
{
   int k;
   for(k=0;k<8;k++)
   {
      if(sender&0b00000001==0b00000001)
         SendPulse();
      else
         SendNull();
      sender>>=1;
   }
}
WideBoy
Guest







PostPosted: Mon Mar 19, 2007 8:26 am     Reply with quote

With regards to the timing, each pulse (high or low) consists of 32 pulses, which take approx 28us each. So each pulse (bit) is approx 900us. Thus:

SendPreamble (4 bits) = 3.6ms
SendData (3 bits) = 2.7ms
SendTime (8 bits) = 7.2ms
SendTime (8 bits) = 7.2ms
SendEnd (3 bits) = 2.7ms

total train is 26 bits and takes approx 23.4ms.
Ttelmah
Guest







PostPosted: Mon Mar 19, 2007 9:28 am     Reply with quote

Your problem is almost certainly not with the timer, but with using 'delay_ms'. Smile
Handling the timer interrupt takes some time. Typically about 60 instruction times (60uSec on your system). Now this is happening every 65536 instruction times, so whenever one of the delays happens to straddle this operation, the delay will be slow by this amount.
Now these times are asynchronous to the timer event, so every few loops, one fixed delay, will run slow by this amount.
The best solution, is to not used these 'fixed' delays, but instead to generate your own delay code, which calculates the 'finish' value required for the hardware timer, and it's overflow, and waits for this to happen.

Best Wishes
WideBoy
Guest







PostPosted: Mon Mar 19, 2007 10:42 am     Reply with quote

Thanks for the input,
I think you are right about the source of the problem. Speaking to a friend a short while ago he also thought the problem might arise because of the way I generate the "pulses". I'm not sure I understand your suggested solution though!
Quote:

The best solution, is to not used these 'fixed' delays, but instead to generate your own delay code, which calculates the 'finish' value required for the hardware timer, and it's overflow, and waits for this to happen.


I know I'm trying to generate a square wave, with a particular period (and 50% duty cycle), but I'm not sure I understand what you are suggesting with regard to calculating a 'finish' value and then waiting for that value....
Are you suggesting I monitor timer0 to provide the timing for the pulses, and at the same time check for overflows?

Any further help would be gratefully received
Guest








PostPosted: Mon Mar 19, 2007 11:19 am     Reply with quote

Ttelmahīs ideia is that sometimes the interrupt will happen when the main code is inside a delay, so instead of delay_us(20) generating 20us of delay it will generate 20us + execution time of the interrupt. The correction for this is to use in place of delay)us a function that:

1) gets the current value of the timer
2) adds the value of the time that we wants to delay
3) waits for the timer to achieve that value

this way it will not matter if the interrupt gets executed inside the delay (well... thinking again this is not completely true... what if it wappens at the end of the count? decisions.... hard decisions.... Smile
Ttelmah
Guest







PostPosted: Mon Mar 19, 2007 1:32 pm     Reply with quote

Spot on.
However you can go one stage further, which helps.
If you have (say) a sequence of 'events', which need to happen at (say), 1mSec, 4mSec, 8mSec etc., from a 'start' time, then if you calculate all the required counts from the starting point, though one will be 'late' if the interrupt occurs, the effect will not be cumulative, and the latter times will still be OK. It needs some thought and care, but it ought to help.
The other thing to consider is the possibility of doing the 16bit count in hardware, either using timer1, or using timer2, to feed timer0.
The big problem is with the short times in 'send_pulse'.

Best Wishes
WideBoy
Guest







PostPosted: Tue Mar 20, 2007 4:46 am     Reply with quote

Thanks for all the input.
I'll try to implement your suggestions and see how that goes....

I've already looked at using timer1, but the scalers on that means it will overflow all 16 bits too quickly. I haven't thought about using timer2 to feed timer0 - so I'll also look into that.

Cheers
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