View previous topic :: View next topic |
Author |
Message |
hmmpic
Joined: 09 Mar 2010 Posts: 314 Location: Denmark
|
On battery set freq to 1mhz? |
Posted: Thu Jan 20, 2011 12:12 pm |
|
|
Hi
I have a unit there normally run 16mhz on supply power, there are a feature in my hardware to detect power fail. If power fail the unit switch to battery power.
How to set the freq down to ex. 500khz or 1mhz.
My problem is the:
# use delay...
I have made a simple function to do it, but it won't work.
Code: |
void CPUChangeSpeed(int8 freq){
if (freq==1){
#use delay(clock=8M)
setup_oscillator( OSC_8MHZ );
setup_timer_0(T0_Internal|T0_DIV_128|T0_8_BIT);
} else
if (freq==0){
#use delay(clock=500000)
setup_oscillator( OSC_500KHZ );
setup_timer_0(T0_Internal|T0_DIV_8|T0_8_BIT);
}
delay_ms(100);
}
|
How to get this to work? |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9226 Location: Greensville,Ontario
|
|
Posted: Thu Jan 20, 2011 2:34 pm |
|
|
You'll have to post the PIC part number and your compiler type/version.
It can be done, easily on newer PICs, a bit more code for the older ones though.
Basically you have to have an interrupt on 'AC power fail', then execute a function that diddles the xtal dividers appropriately. |
|
|
hmmpic
Joined: 09 Mar 2010 Posts: 314 Location: Denmark
|
|
Posted: Thu Jan 20, 2011 2:58 pm |
|
|
The problem is _not_ interrupt or how to handle the code, but only about the #use delay(...) when switching on the fly to other freq. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Jan 20, 2011 2:59 pm |
|
|
If you just have one delay statement, the quick way is just to do this:
Quote: |
void CPUChangeSpeed(int8 freq)
{
if(freq==1)
{
setup_oscillator( OSC_8MHZ );
setup_timer_0(T0_Internal|T0_DIV_128|T0_8_BIT);
delay_ms(100);
}
else if (freq==0)
{
setup_oscillator( OSC_500KHZ );
setup_timer_0(T0_Internal|T0_DIV_8|T0_8_BIT);
delay_ms(100/16);
}
} |
Since 500 KHz is 16x slower than 8 MHz, just reduce the delay by a
factor of 16. |
|
|
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Thu Jan 20, 2011 4:40 pm |
|
|
Quote: | How to get this to work? |
What are you particularly asking for? Does the code not work?
I think, the information in the compiler help is clear and the method straightforward. And it works, as I can report.
Quote: | In multiple clock speed applications, this directive may be used more than once. Any timing routines
(delay_ms(), delay_us(), UART, SPI) that need timing information will use the last defined #USE DELAY |
Alternative #use delays can't work on other parts of the code, and for some peripherals, switching speed will all least disturb their operation, e.g. UARTs. |
|
|
andrewg
Joined: 17 Aug 2005 Posts: 316 Location: Perth, Western Australia
|
|
Posted: Thu Jan 20, 2011 9:26 pm |
|
|
Looking at the OP, the important point to stress is that #-anything instructions are basically compiler pre-processor instructions - they are processed and handled basically before any C code is even compiled. They aren't C functions that can be controlled via C if-else or other control structures.
As it turns out, the following *would* have worked: Code: | void CPUChangeSpeed(int8 freq){
if (freq==1){
#use delay(clock=8M)
setup_oscillator( OSC_8MHZ );
setup_timer_0(T0_Internal|T0_DIV_128|T0_8_BIT);
delay_ms(100);
} else
if (freq==0){
#use delay(clock=500000)
setup_oscillator( OSC_500KHZ );
setup_timer_0(T0_Internal|T0_DIV_8|T0_8_BIT);
delay_ms(100);
}
} | But note that all the code *after* this function would think the CPU speed is 500kHz, since that's the most recent #use delay instruction. _________________ Andrew |
|
|
hmmpic
Joined: 09 Mar 2010 Posts: 314 Location: Denmark
|
|
Posted: Fri Jan 21, 2011 7:57 am |
|
|
@andrewg
Hi
What you wrote about the #use statement is just what I cant figure out. If the latest #use statement is the working one, how then to make a freq. switch over, it the "delay" and "rs232" must still work?
Changing the freq. is not hard, but to get the delay and rs232 to work is my real problem.
My complete code is real big, therefore the solution from @PCM programmer wont, work in my situation.
any working solution? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19510
|
|
Posted: Fri Jan 21, 2011 9:45 am |
|
|
PCM_programmers solution is the easiest.
Just code a macro to handle the switch. and do a global replace for delay_ms/delay_us with the macro. So something like:
Code: |
int1 speed;
#define SLOW (0)
#define FAST (1)
#define switchable_delay_us(x) if(speed==SLOW)delay_us(x/16); \ delay_us(x)
|
Use a set_uart_speed statement before each serial operation, using the same test.
You _cannot_ switch the speed of software UART's. These are hard coded at compile time. If you need to use these, declare two. One perhaps 'stream=SLOW', and another 'stream=FAST', with the same /16 factor, and select the stream based on the same test.
I'd say with global search and replace, and a couple of macros, you should be able to do this in under 10 minutes work, on any project that will fit in a PIC....
Best Wishes |
|
|
hmmpic
Joined: 09 Mar 2010 Posts: 314 Location: Denmark
|
|
Posted: Fri Jan 21, 2011 10:08 am |
|
|
Thanks for the help to all:-)
I will test it out. |
|
|
|