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 support@ccsinfo.com

problem delay function by timer0

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



Joined: 09 May 2012
Posts: 46
Location: KSA

View user's profile Send private message Send e-mail MSN Messenger

problem delay function by timer0
PostPosted: Sun Aug 12, 2012 2:24 pm     Reply with quote

hi guys,

I'm doing a project that counts seconds and minutes on 4-digit 7SD.
Seconds and minutes are generated using timer0 , but in the main function i was forced to use delay_ms function to avoid the flickering on the 7SD, then the project worked 100%.

But my plan was not to use "delay" function, I wanted to work with the timing using real time.

However I tried so many things to solve this but all didn't make sense.

So how can I make delay function using timer0 like the one ccs uses, I mean
for example if I need 50ms delay, I would use "mydelay_ms".

A clear example:

Code:

output_high(pin_b0); //turn on led on B0
mydelay_ms(50); //wait 50 ! using timer0

I hope if I can get help from anyone, please guys, and thank you all.

This is the code that works but using delay:
Code:

#include <16F877.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use Delay(clock=4000000)

//values to be displayed on 7SD 0-9 in hex(lookup table)
byte const display[10]={0x40, 0x79, 0x24, 0x30, 0x19, 0x12, 0x02, 0x78, 0x00, 0x10};

byte  c1=0, c2=0, c3=0, c4=0, high_count;

//HIGH_START: number of interrupts every sec: (F/4)/ Prescalar / 2^8 = 61(16393us) so every second 61 interrupts are generated.
#define HIGH_START 61

//this isr function is entered on each timer0 overflow(0-255)
#INT_RTCC
void clock_isr()
{
   if(--high_count==0) //decrease high_count from 61 to 0 on every interrupt, when high_count reaches 0, it means 1Sec
   {
      ++c1; //increment c1(first digit seconds) every second 
     
      high_count=HIGH_START; //reinitiallising high_count to HIGH_START(61)
   }
   
}

void main()
{
   high_count=HIGH_START; //high_count gets 61
   set_rtcc(0); //timer0 starts counting from 0
   setup_counters(RTCC_INTERNAL, RTCC_DIV_64); //using internal instruction, using pre-scalar of 64
   enable_interrupts(INT_RTCC); //enable timer0 interrupt
   enable_interrupts(GLOBAL);  //enable global interrupt
   
  for(;;)
  {   
     if(c1==10) //each time c1(first digit seconds) reaches 10
     {
         c2++; //increment c2(second digit seconds)
         c1=0; //reset c1(first digit seconds)
         
         if(c2==6) //if c2(second digit seconds) reaches 6, that means minute counter will start
         {
            c3++; //increment c3(first digit minutes)
            c2=0; //reset c2(second digit seconds)
         }
         
         if(c3==10) //if c3(first digit minutes) reaches 10
         {
            c4++; //increment c4(second digit minutes)
            c3=0; //reset c3(first digit minutes)
         }
     }
     
     //send high to C0 to select c1(first digit seconds), then display its value
     output_c(0b00000001);
     output_b(display[c1]);
     delay_ms(10);
     
     //send high to C1 to select c2(second digit seconds), then display value
     output_c(0b00000010);
     output_b(display[c2]);
     delay_ms(10);
     
     //send high to C2 to select c3(first digit minutes), then display its value
     output_c(0b00000100);
     output_b(display[c3]);
     delay_ms(10);
     
     //send high to C3 to select c4(second digit minutes), then display its value number from lookup table
     output_c(0b00001000);
     output_b(display[c4]);
     delay_ms(10);
         
  }//endless loop
}//main




And this is the code, I tried to avoid using delay but didn't work!!!:
Code:


#include <16F877.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use Delay(clock=4000000)

//values to be displayed on 7SD 0-9 in hex(lookup table)
byte const display[10]={0x40, 0x79, 0x24, 0x30, 0x19, 0x12, 0x02, 0x78, 0x00, 0x10};


byte  c1=0, c2=0, c3=0, c4=0, high_count, high_count_2, t1=0;

//HIGH_START: number of interrupts every sec: (F/4)/ Prescalar / 2^8 = 61(16393us) so every second 61 interrupts are generated.
#define HIGH_START 61
#define HIGH_START_2 30 //half a second 61/2=30(50ms)

//this isr function is entered on each timer0 overflow(0-255)
#INT_RTCC
void clock_isr()
{
   if(--high_count==0) //decrease high_count from 61 to 0 on every interrupt, when high_count reaches 0, it means 1Sec
   {
      ++c1; //increment c1(first digit seconds) every second 
     
      high_count=HIGH_START; //reinitiallising high_count to HIGH_START(61)
   }
   
   if(--high_count_2==0)//decrease from 30 to 0, on each interrupt
   {
      ++t1;
      high_count_2=HIGH_START_2;
   }
   
}

void main()
{
   high_count_2=HIGH_START_2;
   high_count=HIGH_START; //high_count gets 61
   set_rtcc(0); //timer0 starts counting from 0
   setup_counters(RTCC_INTERNAL, RTCC_DIV_64); //using internal instruction, using pre-scalar of 64
   enable_interrupts(INT_RTCC); //enable timer0 interrupt
   enable_interrupts(GLOBAL);  //enable global interrupt
   
  for(;;)
  {   
     loop:
     if(c1==10) //each time c1(first digit seconds) reaches 10
     {
         c2++; //increment c2(second digit seconds)
         c1=0; //reset c1(first digit seconds)
         
         if(c2==6) //if c2(second digit seconds) reaches 6, that means minute counter will start
         {
            c3++; //increment c3(first digit minutes)
            c2=0; //reset c2(second digit seconds)
         }
         
         if(c3==10) //if c3(first digit minutes) reaches 10
         {
            c4++; //increment c4(second digit minutes)
            c3=0; //reset c3(first digit minutes)
         }
     }
     
     //send high to C0 to select c1(first digit seconds), then display its value number from lookup table
     output_c(0b00000001);
     output_b(display[c1]);
     //delay_ms(10);
     
     if(t1==10){ //if 10ms , do below
     
     //send high to C1 to select c2(second digit seconds), then display its value number from lookup table
     output_c(0b00000010);
     output_b(display[c2]);
     //delay_ms(10);
     }
     
     if(t1==20){ //after 20ms , do below

     //send high to C2 to select c3(first digit minutes), then display its value number from lookup table
     output_c(0b00000100);
     output_b(display[c3]);
     //delay_ms(10);
     }
     
     if(t1==30){after 30ms, do below

     //send high to C3 to select c4(second digit minutes), then display its value number from lookup table
     output_c(0b00001000);
     output_b(display[c4]);
     //delay_ms(10);
     }
     
     if(t1==40) t1=0; goto loop; //now after 40ms, reset t1 start over
         
  }//endless loop
}//main

NePe



Joined: 21 Jun 2011
Posts: 9

View user's profile Send private message

PostPosted: Sun Aug 12, 2012 2:57 pm     Reply with quote

Are you using external clock for timer0?

Try something like that:
Code:

void my_delay(int16 time) {
   set_timer0(0);
   while(get_timer0()!=time);
}
asmboy



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

View user's profile Send private message AIM Address

PostPosted: Sun Aug 12, 2012 3:12 pm     Reply with quote

Quote:

Try something like that:


better yet - dont

The compare is of an 8 bit timer with a 16 bit count with your 16f877 PIC in YOUR app.

It is only going to work if it is an 18F part (used in 16bit timer0 mode) - NOT a 16F part as timer0 is only 8 bits.
semmoor



Joined: 09 May 2012
Posts: 46
Location: KSA

View user's profile Send private message Send e-mail MSN Messenger

PostPosted: Sun Aug 12, 2012 4:35 pm     Reply with quote

NePe wrote:
Are you using external clock for timer0?

Try something like that:
Code:

void my_delay(int16 time) {
   set_timer0(0);
   while(get_timer0()!=time);
}


I'm using internal clock.

I will try your method but can you please clarify more about your method, and by the way I'm using an 8bit timer0 so I think int16 will not work here!
Thanks guys.
semmoor



Joined: 09 May 2012
Posts: 46
Location: KSA

View user's profile Send private message Send e-mail MSN Messenger

PostPosted: Sun Aug 12, 2012 5:21 pm     Reply with quote

NePe thank you I tried it and it worked 100%,

I changed your code to:
Code:

void my_delay(int8 time)
{
   while(t1 != time); t1=0;
}

I'm just wondering about "while(get_timer0()!=time);" does this hold the cpu if the timer is not equal to the variable "time" ??

Because as think this line says if the timer counter is not equal time stay here, not really sure.
NePe



Joined: 21 Jun 2011
Posts: 9

View user's profile Send private message

PostPosted: Sun Aug 12, 2012 7:43 pm     Reply with quote

Code:

void my_delay(int8 time) {
   set_timer0(0);
   while(get_timer0()!=time);
}


Its simply checks the timer value until its reach the value of the time variable.


Code:

void my_delay(int8 time)
{
   while(t1 != time); t1=0;
}



I'm not really understand your code. Where the t1 variable comes from?

Quote:

I'm using internal clock.


When you are using same clock for the cpu and the timer, no difference between accuracy of them. Why do you want to use timers for delay ?
Douglas Kennedy



Joined: 07 Sep 2003
Posts: 755
Location: Florida

View user's profile Send private message AIM Address

PostPosted: Mon Aug 13, 2012 1:59 am     Reply with quote

Well, there are plus's and minus's. Delay_xx has the minus of being blocking ( until it times out the main loop code is blocked). Delay_ms has the plus is that it is easy to use.
Now a timer with an ISR or just a test in code to see the timer count will be non blocking. The plus is that main code loop can be running as the timer counts out. The minus is that it is a bit more complicated to get the timer set right to give the exact delay needed.
A non blocking example could be the need to make a short event visible say data is received over the CAN bus. The CAN receive isr sets flag for the delay timer isr to turn on a LED. The timer isr turns on the LED and when it times out it turns it off. The main code isn't blocked by the LED timer and can process the CAN bus data received.
Mike Walne



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

View user's profile Send private message

PostPosted: Mon Aug 13, 2012 3:58 am     Reply with quote

You've got a rounding off error in your time generation.

You could lift something from this code which solves the problem.

http://www.ccsinfo.com/forum/viewtopic.php?t=26177

Like DK says there are pros and cons. With an ISR you can have (within limits) as many timers going as you want, without your code getting locked up.

OK. So you don't actually need one for your simple clock, but you are obviously looking to do something more advanced in the future and can see the need to avoid delay_ms(xx).

Mike
semmoor



Joined: 09 May 2012
Posts: 46
Location: KSA

View user's profile Send private message Send e-mail MSN Messenger

PostPosted: Mon Aug 13, 2012 10:16 am     Reply with quote

NePe wrote:
Code:

void my_delay(int8 time) {
   set_timer0(0);
   while(get_timer0()!=time);
}


Its simply checks the timer value until its reach the value of the time variable.


Code:

void my_delay(int8 time)
{
   while(t1 != time); t1=0;
}



I'm not really understand your code. Where the t1 variable comes from?

Quote:

I'm using internal clock.


When you are using same clock for the cpu and the timer, no difference between accuracy of them. Why do you want to use timers for delay ?



"t1" is actually a micro second counter to count each timer0 overflow.

i just wanted to avoid using "delay" because it hold the CPU from doing anything unless the delay given is passed, so i was planing to use timer0 to handle this but instate it can do other task until given time is passed.
semmoor



Joined: 09 May 2012
Posts: 46
Location: KSA

View user's profile Send private message Send e-mail MSN Messenger

PostPosted: Mon Aug 13, 2012 10:23 am     Reply with quote

Mike Walne wrote:
You've got a rounding off error in your time generation.

You could lift something from this code which solves the problem.

http://www.ccsinfo.com/forum/viewtopic.php?t=26177

Like DK says there are pros and cons. With an ISR you can have (within limits) as many timers going as you want, without your code getting locked up.

OK. So you don't actually need one for your simple clock, but you are obviously looking to do something more advanced in the future and can see the need to avoid delay_ms(xx).

Mike



Thanks Mike I saw the link and found it really valuable worth testing. I'm actually gonna modify it to use it in my timer project.

You were right about the rounding off error, when I compared my timer with my computer clock it's not accurate after like 6 sec.

But can the code in the link be used in my project since I'm using an 8bit timer?

Thanks again mike.
and thanks to everybody else.
Mike Walne



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

View user's profile Send private message

PostPosted: Tue Aug 14, 2012 1:58 am     Reply with quote

Quote:
But can the code in the link be used in my project since I'm using an 8bit timer?

Yes, of course it can.

There are posts in the thread which explain how to do it.

In your case you simply exchange the 65536 (the number of machine cycles per interrupt) with your value of 64*256 = 16384. The effect will be that the seconds count advances after 61 interrupts most times and occasionally after 62. There will be a small amount of jitter, which you're unlikely to notice.

Mike

EDIT
Quote:
You were right about the rounding off error, when I compared my timer with my computer clock it's not accurate after like 6 sec.

Even with the code you've got you should not be seeing such a gross error. Have a close look at your oscillator.

(1) Are you using a ceramic resonator or a crystal?
(2) Have you got all the recommended Rs and Cs fitted?
(3) Does it look stable on a 'scope?
semmoor



Joined: 09 May 2012
Posts: 46
Location: KSA

View user's profile Send private message Send e-mail MSN Messenger

PostPosted: Wed Aug 15, 2012 1:53 pm     Reply with quote

Mike Walne wrote:
Quote:
But can the code in the link be used in my project since I'm using an 8bit timer?

Yes, of course it can.

There are posts in the thread which explain how to do it.

In your case you simply exchange the 65536 (the number of machine cycles per interrupt) with your value of 64*256 = 16384. The effect will be that the seconds count advances after 61 interrupts most times and occasionally after 62. There will be a small amount of jitter, which you're unlikely to notice.

Mike

EDIT
Quote:
You were right about the rounding off error, when I compared my timer with my computer clock it's not accurate after like 6 sec.

Even with the code you've got you should not be seeing such a gross error. Have a close look at your oscillator.

(1) Are you using a ceramic resonator or a crystal?
(2) Have you got all the recommended Rs and Cs fitted?
(3) Does it look stable on a 'scope?


Sorry Mike, I was busy.

I did the code with an 8bit timer0 as you suggested, and it worked Smile

Thank you Mike.

By the way I'm using 4M crystal and I put 22Pf capacitor and it's working fine, I tested it.
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