|
|
View previous topic :: View next topic |
Author |
Message |
mahdihir
Joined: 01 Dec 2013 Posts: 7 Location: Iran
|
sleep mode in 12f683 |
Posted: Tue Jan 13, 2015 3:55 am |
|
|
Hi
I’m working on project with 12f683, the purpose is to get sample from ADC every 10 sec and if the sample is bigger than X, do something.
The problem is I need to save energy as much as possible for battery life,
Is it possible to put MCU in sleep mode for 10 sec and after that wake up MCU for 10ms to get sample from ADC and go back to sleep?
thanks |
|
|
40inD
Joined: 30 Jul 2007 Posts: 112 Location: Moscow, Russia
|
|
Posted: Tue Jan 13, 2015 10:08 am |
|
|
Set WDT to closest round value and do sleep() so much times to get 10 s delay then reset cpu:
Example from my program:
Code: |
setup_wdt(WDT_2304MS);
.......
{
sleep(); // 2.3s
sleep(); // 4.6s
sleep(); // 6.9s
sleep(); // 9.2s
reset_cpu();
}
|
|
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9245 Location: Greensville,Ontario
|
|
Posted: Tue Jan 13, 2015 10:22 am |
|
|
just be aware that the WDT is run from the internal 31KHz osc and is NOT precise !! You'll have to experiment to get reasonable,repeatable operation.
VDD, temperature, initial calibration all affect the timing AND each PIC is different.
For a 'one-off' project , not a big deal , but for a 'commercial' product, you're best to use a proper xtal/caps.
Jay |
|
|
mahdihir
Joined: 01 Dec 2013 Posts: 7 Location: Iran
|
|
Posted: Wed Jan 14, 2015 2:32 am |
|
|
thanks a lot
but my problem is the sleep mode is in the middle of program, once WDT reset the MCU and goes to the first line of program and i want to continue after sleep instruction, the rest of program.
Code: | void main()
{ ...
while ()
{ ...
/////////// half of program/////////////
sleep();
///////////the rest of program//////////
...
}
} |
thanks |
|
|
40inD
Joined: 30 Jul 2007 Posts: 112 Location: Moscow, Russia
|
|
Posted: Thu Jan 15, 2015 2:13 am |
|
|
In SLEEP mode WDT does not reset cpu, just continue program. Read dataheet.
that's why I add reset_cpu() in my program above. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19549
|
|
Posted: Thu Jan 15, 2015 3:46 am |
|
|
First of all, don't reset the cpu.
It's bad practice. A reset should only happen when there is good cause.
What happens on a watchdog, changes between chips. Some of the very early PIC12's, will always physically restart on a watchdog. However most modern ones won't. Old line _read the data sheet_.....
Section 12.7 on the data sheet for your PIC, says:
"The device can wake-up from Sleep through one of the
following events:
1. External Reset input on MCLR pin.
2. Watchdog Timer wake-up (if WDT was
enabled).
3. Interrupt from GP2/INT pin, GPIO change or a
peripheral interrupt.
The first event will cause a device Reset. The two latter
events are considered a continuation of program
execution. The TO and PD bits in the STATUS register
can be used to determine the cause of a device Reset.
The PD bit, which is set on power-up, is cleared when
Sleep is invoked. TO bit is cleared if WDT wake-up
occurred."
Now, see how an external MCLR causes a reset, but "the two latter events are considered a continuation of program execution". Exactly what you need to know.
So your code structure should be something like:
Code: |
#include <12F683.h>
#fuses NOMCLR, NOWDT //wake up without watchdog.
#device ADC=10
#use delay(internal=4000000) //4MHz internal clock
#use rs232 (XMIT=PIN_A2, baud=9600) //minimum RS232 setup for debugging
void main()
{
int16 adc_val;
setup_adc(ADC_CLOCK_DIV_8); //correct ADC clock for 4MHz
setup_adc_ports(sAN0); //sampling on A0, Vss to Vdd as ref
while(TRUE)
{
delay_us(10); //ensure ADC has acquired
adc_val=read_adc(); //read the value
//Now for debug, just send to RS232 as voltage
printf("Reading %4.2lw\n\r",(adc_val*49)/100);
//gives an _integer_ conversion to 0-500 from 0-1023
//Now we want to sleep
restart_wdt(); //just ensure the WDT does not occur in the next couple of instructions
setup_wdt(WDT_2304MS | WDT_ON); //start the watchdog
sleep();
delay_cycles(1);
sleep();
delay_cycles(1); //each sleep will clear the watchdog when called
sleep();
delay_cycles(1);
//Now approximately 6.9 seconds have passed
setup_wdt(WDT_OFF); //stop the watchdog
//and loop back to read the ADC
}
}
|
You have to be careful that the watchdog does not trigger when you are not asleep, or the chip will reset. Since you don't know what count is in the watchdog register, I clear it _before_ starting the watchdog.
This is coded to run off the internal 4MHz clock, and send the ADC reading out as a 0 to 5.00 (will actually go to 5.01) value on the RS232, using integer maths for size/speed.
Hopefully gives you an idea of how to do what you want. |
|
|
mahdihir
Joined: 01 Dec 2013 Posts: 7 Location: Iran
|
|
Posted: Sun Jan 25, 2015 3:00 am |
|
|
thanks,
its working properly.
my another question is, i setup a ADC to get sample every 2.3 min, and if the value is bigger than MIN, do something,
is my code correct?
Code: |
#include <12F683.h>
#device ADC=10
#fuses LP,NOPUT,NOPROTECT,NOCPD,NOMCLR
#FUSES WDT //No Watch Dog Timer
#FUSES PUT //Power Up Timer
#FUSES PROTECT //Code protected from reads
#FUSES CPD //Data EEPROM Code Protected
#FUSES NOBROWNOUT //No brownout reset
#use delay(INTERNAL=31000)
#define GP0 PIN_A0
#define GP1 PIN_A1
#define GP2 PIN_A2
#define GP3 PIN_A3
#define GP4 PIN_A4
#define GP5 PIN_A5
#define BUTTON PIN_A3
#define BUTTON_PRESSED input(BUTTON)
int16 i, value, n, m, j, o;
float32 min, max;
void init()
{
setup_wdt(WDT_2304MS);
set_tris_a( 0b00000001 ); // set GP0 input, GP1 output, GP2 output, GP3 output GP4 output, GP5 output
setup_comparator( NC_NC_NC_NC ); // disable comparators
setup_adc_ports( AN0_ANALOG ); // enable analog inputs
setup_adc(ADC_CLOCK_INTERNAL); // Built-in A/D setup function
set_adc_channel(0); // Built-in A/D setup function
// setup_vref(VREF_HIGH | 8);//sets 3.6(vdd * value/32 + vdd/4) if vdd is 5.0V
// setup_timer_0(off)
// setup_timer_1(T1_DISABLED);
value = read_adc();
}
void main()
{
while(TRUE) {
output_high (PIN_A1);
setup_adc_ports(sAN0);
setup_adc(ADC_CLOCK_DIV_4);
value=0;
value = read_adc();
setup_adc(ADC_OFF);
if(value<min)
{
goto loop1;
}
delay_ms(30);
output_low(PIN_A1);
restart_wdt();
sleep();
}
loop1
...
} |
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19549
|
|
Posted: Sun Jan 25, 2015 4:26 am |
|
|
1) Move the setup_adc_ports outside the loop.
There must always be Tacq, between using the setup_adc_ports, and reading the adc. This is what the delay_us at the start of my loop, is there for.
2) Forget float. Unless you absolutely 'have to', FP should not be used when an integer will do. FP, is bulky, slow, and inaccurate. For things like financial calculations they are never used because of the errors. Remember the value from the ADC, is just an integer count. int16 is what you should be using. If you want to work with a 'number' that has some direct relevance to volts, then consider multiplying, so that the integer, gets scaled to represent mV.
3) You have the watchdog enabled in hardware. Again look at how I do it. The watchdog is _not_ enabled, till it is to be used. You have a very high risk now of a watchdog occurring while you are awake. Particularly because of 4 below.
4) You are now using a very slow clock. Slightly 'pointless', since all it does is makes the time spent awake, longer. The effect on consumption, will actually be to make it worse!. At 3v, the chip draws typically 500uA at 4MHz, and 16uA at 31KHz. 31.25* as much, _but_ it executes code 129*faster. So you end up drawing more power running at the slower speed (4* as much to execute the same code....). Use the slower speed, if you are wanting to keep the chip awake. If you are sleeping, look at which processor speed gives the best performance per uA. The slow clock will make things take an age. The FP comparison, will take nearly 1/10th second at 31KHz. If your routine reached after the comparison does anything more than sneeze, you will end up having a watchdog restart in this - since you are leaving the watchdog running. Because you have it enabled in the fuses _it cannot be turned off_. Read the data sheet. Look at what the WDTE bit does.
5) Don't 'goto'. Using goto, in some computer courses is treated as a 'capital' offence. You should really never need to use it (there are a few situations in embedded programming, primarily related to interrupts/recovery, where it may be used), but otherwise treat this instruction as if it doesn't exist. It is _not_ a primary part of C, but is only there for those odd occasions. As it stands, depending on whether you want to get back into the loop, you may well end up with the processor stack becoming unbalanced. It is a very easy way to shoot yourself in the foot.
6) At your slow clock, the ADC will take over 6mSec to perform the conversion. A very long way outside it's recommended operating range (57* slower than the recommended slowest operation). This will degrade it's accuracy appallingly. |
|
|
guy
Joined: 21 Oct 2005 Posts: 297
|
|
Posted: Sun Jan 25, 2015 2:26 pm |
|
|
PIC12F683 also supports Ultra Low Power WakeUp (ULPWU). If you connect in series a 130 ohm resistor from GP0 - to a 10nF capacitor - to GND you can have the PIC charge and discharge the cap to keep track of time while in sleep mode. Power consumption is less than 1uA (much less than the WDT).
GP0 >-----/\/\/\/\----||--- GND
Another thing to look out for - disconnect the cap when programming in-circuit (GP0 is also ICSPDAT).
Let me know if you want me to post the code - I don't think the feature is supported by the compiler. It also requires calibration using the internal oscillator - the code takes care of everything. |
|
|
mahdihir
Joined: 01 Dec 2013 Posts: 7 Location: Iran
|
|
Posted: Mon Jan 26, 2015 5:43 am |
|
|
My friend
thanks for your help.
I have done what you said from No 1 to 4.
But for No5 and 6, can you explain more? did you mean I should change [spam] from 31k to 4M?
The battery life is the most important factor in my project.
Thanks |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9245 Location: Greensville,Ontario
|
|
Posted: Mon Jan 26, 2015 6:35 am |
|
|
re: #5 xtal value.
yes, you should use the 4 MHz xtal instead of the 32KHz xtal. Although the PIC will consume more power at the higher frequency, it gets the program done and back to sleep a LOT faster than the 'slow'(32KHz) PIC will. Overall the 'fast' PIC will SAVE energy.
Microchip has an application note(AN606) you should read. It deals with 'low power design' and is well worth reading.
Jay |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19549
|
|
Posted: Mon Jan 26, 2015 8:14 am |
|
|
I'll elucidate just a bit.
Consumption, is power*time. Power is volts*current. Assume 3v.
Assume the 'awake' code is 1000 instructions long (the number doesn't matter). At 31KHz, this will take (4428ips), 0.226 seconds. At 4MHz (1mips), it'll take 1mSec. When awake at 4MHz, it'll draw 500uA. When awake at 31Khz, it'll draw 16uA. Total consumption to run the 'awake' code at 31KHz = 3*0.226*16uA = 10.8uW. At 4MHz, = 3*0.001*500uA = 1.5uW. Total battery consumption 7.2* _less_ running the code at 4MHz....
The chip runs less efficiently at the low clock rate. Where the low clock would be used, is if you were keeping the chip awake all the time, so that it could perhaps keep time. Given that the low clock also takes your ADC out of spec, it's a 'no brainer', to use the faster clock. |
|
|
|
|
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
|