![](templates/subSilver/images/CCSLogo.jpg) |
![CCS C Software and Maintenance Offers](templates/subSilver/images/forumAd6.jpg) |
View previous topic :: View next topic |
Author |
Message |
tojape
Joined: 14 Jan 2007 Posts: 20 Location: Hungary
|
Timer2 calculator runtime |
Posted: Sun Jun 23, 2013 12:03 pm |
|
|
Hi all,
I need to change timer2 interrupt frequency in runtime. The range is between 50Hz to 20 kHz. I quickly wrote this code which is actually working.
Due to lack of math backgound it is simple but terribly slow.
May be I did not use the right keywords hence I did not find any better example how experts do it.
Here it is a test code how I did:
Code: |
#include <16F1519.h>
#device adc=8
#FUSES NOWDT //No Watch Dog Timer
#FUSES HS //High speed Osc (> 4mhz for PCM/PCH) (>10mhz for PCD)
#FUSES WDT_SW //No Watch Dog Timer, enabled in Software
#FUSES PUT //Power Up Timer
#FUSES NOBROWNOUT //No brownout reset
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#define crystal 11059200
#use delay(clock=crystal)
#use rs232(baud=115200,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8,errors)
#define freq_pin PIN_C1
#int_TIMER2
void TIMER2_isr(void)
{
output_toggle(freq_pin);
}
void calculate_divisors(int32 desired_freq)
{
int1 not_found;
int32 calc_divider,t2_clock;
signed int32 freq_error;
int16 prsc,prescaler,div,divider,posc,postscaler;
int16 smallest_error,actual_error;
int16 best_divider,actual_divider;
t2_clock=crystal/8; //T2 clock is fosc/4, toggle divides by 2
calc_divider=t2_clock/desired_freq;
if(calc_divider>65536)
{
printf("freq is out of range\r\n");
return;
}
best_divider=t2_clock/desired_freq;
smallest_error=best_divider-1; //initializing smallest error found
if(best_divider<2)
{
prsc=1;
div=1;
posc=1;
}
else
{
prescaler=1;
not_found=1;
while(prescaler<17&¬_found) //prescaler max value is 16
{
postscaler=1;
while(postscaler<17&¬_found) //postscaler max value is 16
{
divider=1;
while(divider<257&¬_found) //divider max value is 256
{
actual_divider=prescaler*postscaler*divider;
if(actual_divider>best_divider) //to avoid abs() function in stdlib!
actual_error=actual_divider-best_divider;
else
actual_error=best_divider-actual_divider;
if(actual_error<smallest_error)
{
smallest_error=actual_error; //maintaining smallest error so far
prsc=prescaler; //preserving actual figures
div=divider;
posc=postscaler;
}
if(!actual_error) //test if error is 0 ->no need to continue
{
not_found=FALSE; //exiting from all three loops
}
divider++; //next divider value to try
}
postscaler++; //next postscaler value to try
}
prescaler*=4; //next prescaler value to try, only 1,4,16 allowed
}
}
switch(prsc)
{
case 1 : setup_timer_2(T2_DIV_BY_1,(div-1),posc); //div value must be decremented
break;
case 4 : setup_timer_2(T2_DIV_BY_4,(div-1),posc);
break;
default: setup_timer_2(T2_DIV_BY_16,(div-1),posc);
break;
}
freq_error=desired_freq-t2_clock/(prsc*(div)*posc);
//printing out the result
printf("d: %5LuHz a: %5LuHz presc %2Lu, div %3Lu, postsc %2Lu freq_error %5LdHz\r\n",desired_freq,t2_clock/(prsc*(div)*posc),prsc,div,posc,freq_error);
}
void main()
{
int32 freq=100;
char karcsi=0x55;
setup_timer_2(T2_DIV_BY_16,255,16); //1.4 ms overflow, 23.7 ms interrupt
enable_interrupts(INT_TIMER2);
enable_interrupts(GLOBAL);
setup_adc_ports(NO_ANALOGS);
setup_wdt(WDT_OFF);
delay_ms(1000);
printf(__filename__);
printf(__date__);
printf("\r\n");
while(1)
{
calculate_divisors(freq+=100);
if(freq>20000) freq=100;
}
}
|
Do you have any idea to speed up this function? _________________ The computer helps solving the problems which would have never arised without computers |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19367
|
|
Posted: Sun Jun 23, 2013 1:22 pm |
|
|
You are probably not going to get there. 20KHz, would require 40Kips. Each interrupt takes typically a minimum of about 60 instruction times to execute, so at your 11MHz (2.7mips), you have no time left to do anything else at all....
'Experts', don't do this.
They either use a PWM, or an external programmable frequency source (best solution).
Best Wishes |
|
![](templates/subSilver/images/spacer.gif) |
tojape
Joined: 14 Jan 2007 Posts: 20 Location: Hungary
|
|
Posted: Sun Jun 23, 2013 3:09 pm |
|
|
Ttelmah wrote: | You are probably not going to get there. 20KHz, would require 40Kips. Each interrupt takes typically a minimum of about 60 instruction times to execute, so at your 11MHz (2.7mips), you have no time left to do anything else at all....
'Experts', don't do this.
They either use a PWM, or an external programmable frequency source (best solution).
Best Wishes |
Thank you for your reply.
Experts don't do this - this might be the reason why I did not find what I looked for :-)
Using the pwm the lowest frequency seems to be 675Hz (the postscaler is not used in pwm mode) which is too high for me. (@Fosc=11059200Hz)
At 20KHz it's still able to get and calculate the next frequency setting and fortunately there's nothing else to do. Maybe I'll switch to using the internal 16MHz osc.
The whole thing isn't worth an external programmable frequency source. What can I get for less than $2 which is the price of a pic16f1519 micro?
Being just a hobbist I decided not to look for a better solution while this poor quality but still usable code works.
Thank you again :-)
Best wishes _________________ The computer helps solving the problems which would have never arised without computers |
|
![](templates/subSilver/images/spacer.gif) |
asmboy
Joined: 20 Nov 2007 Posts: 2128 Location: albany ny
|
|
Posted: Sun Jun 23, 2013 3:25 pm |
|
|
what you want is the NCO feature of the 16f1509
so
unless you want 1 hzfreq set resolution -
it will do what you want-
and
if you pick the right external frequency crystal
-with real simplicity
see my earlier post on this capability
http://www.ccsinfo.com/forum/viewtopic.php?t=50121 |
|
![](templates/subSilver/images/spacer.gif) |
tojape
Joined: 14 Jan 2007 Posts: 20 Location: Hungary
|
|
Posted: Sun Jun 23, 2013 3:51 pm |
|
|
asmboy wrote: | what you want is the NCO feature of the 16f1509
so
unless you want 1 hzfreq set resolution -
it will do what you want-
and
if you pick the right external frequency crystal
-with real simplicity
see my earlier post on this capability
http://www.ccsinfo.com/forum/viewtopic.php?t=50121 |
Thank you very much
this is exactly the feature I need. Cheap, simple, much better than my poor attempt with 16F1519. I am going to order several pieces of them.
Your posting is highly appreciated. _________________ The computer helps solving the problems which would have never arised without computers |
|
![](templates/subSilver/images/spacer.gif) |
|
|
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
|