PIC sleep mode

For Flowcode users to discuss projects, flowcharts, and any other issues related to Flowcode 2 and 3.

Moderators: Benj, Mods

Post Reply
echase
Posts: 429
Joined: Mon Jun 11, 2007 11:55 am
Has thanked: 49 times

PIC sleep mode

Post by echase »

To save power I want to put my 16F886 IC into sleep mode (or other low power mode if available) overnight and wake it up in morning. Problem is I need to keep counting time during the night. Is there a way with say a timer (or whatever the PIC has that is not completely turned off) of counting time so when I wake the PIC up I can correct the time clock that was running using the internal oscillator in daytime.

The datsheet says 'Timer1 Oscillator
A low-power 32.768 kHz crystal oscillator is built-in between pins T1OSI (input) and T1OSO (amplifier output). The oscillator is enabled by setting the T1OSCEN control bit of the T1CON register. The oscillator will continue to run during Sleep.' and also 'Timer1 can only operate during Sleep when setup in Asynchronous Counter mode. In this mode, an external
crystal or clock source can be used to increment the counter.'

Not clear though how much time it will count. I need about one hour.

So code is something like this:-

At midnight put PIC to sleep
One hour later wake it up to check light level with light meter connected to A/D, to see if it’s light yet.
If dark still, repeat cycle from first line
If light, read the number of hours elapsed in sleep mode and correct the clock.

Does not have to be very accurate at measuring time, +/- 5% is OK. If it can't do as much as one hour it can simply be set to whatever max it can do but means wake up is more frequent so power saving is less.

And can all this be done with Flowcode or will it be lots of lines of C?

User avatar
Steve
Matrix Staff
Posts: 3433
Joined: Tue Jan 03, 2006 3:59 pm
Has thanked: 114 times
Been thanked: 422 times

Post by Steve »

I think the majority of the program can be done in Flowcode, with just a few lines of C code to set certain registers and to send the device to sleep.

echase
Posts: 429
Joined: Mon Jun 11, 2007 11:55 am
Has thanked: 49 times

Post by echase »

So is that a ‘yes’ to Timer 1 being a suitable way to implement this?

In Flowcode when the delay function is used is it using a PIC Timer to generate this delay? Which one and how accurate is it? Is it as accurate as the PIC clock? I ask because my main time clock is based on the delay function, but if not that accurate maybe I should use a Timer 0 interrupt instead, as per http://matrixmultimedia.com/mmforums/vi ... php?t=4005

Or are you doing the delay by running around a dummy loop of instruction cycles?

User avatar
Steve
Matrix Staff
Posts: 3433
Joined: Tue Jan 03, 2006 3:59 pm
Has thanked: 114 times
Been thanked: 422 times

Post by Steve »

I would not suggest using the "delay" functions for accurate clock timing. Instead, use one of the in-built timers. The "delay" function does not use these.

I would suggest using an interrupt on Timer1 as the mechanism for incrementing your clock value. Your main routine would then be responsible for displaying the time and deciding when to go to sleep. Also, the time would be maintained even when the unit was asleep.

If you wake the PICmicro up periodically (say, every 10Hz) and keep the interrupt routine to a minimum, that should have a massive power saving.

Also, rather than use an A/D to determine light level, why not use a comparator. Or even use a transistor circuit to create a digital signal for the light threshold which turns the clock on.

echase
Posts: 429
Joined: Mon Jun 11, 2007 11:55 am
Has thanked: 49 times

Post by echase »

Thanks, that explains why I have had trouble getting it to keep to any consistent timekeeping. I shall experiment with the Timers, although I have avoided them so far as I have never really understood them.

Assuming I use Timer 1 how in Flowcode do I implement the second line of this routine?


Display a temperature reading on LCD
Exactly 6 seconds after last loop display the new value
Go to macro that measures the temperatures
Loop for ever counting up time

I was putting a 5.xx second delay for the second line where 5.xx plus the time to process the other instructions = ‘exactly’ 6 seconds.
Last edited by echase on Fri Sep 14, 2007 10:06 am, edited 2 times in total.

User avatar
Steve
Matrix Staff
Posts: 3433
Joined: Tue Jan 03, 2006 3:59 pm
Has thanked: 114 times
Been thanked: 422 times

Post by Steve »

Assuming your Timer1 interrupt is handling the updating of the clock, you will have some global variables that contain the hour, minute and second values.

Choice 1: Use another variable that increments every six seconds within this interrupt routine. Then re-read the temperature in the main routine each time this variable changes value:

Code: Select all

if (SIX_SEC_TMR <> OLD_SIX_SEC_TMR)
  read temperature
end if
OLD_SIX_SEC_TMR = SIX_SEC_TMR
Choice 2: Use the global second variable to make a decision in your main routine:

Code: Select all

if (SECONDS = 0) || (SECONDS = 6) || (SECONDS = 12) || (SECONDS = 18) || (SECONDS = 24) || (SECONDS = 30) || (SECONDS = 36) || (SECONDS = 42) || (SECONDS = 48) || (SECONDS = 54)
  read temperature
end if

echase
Posts: 429
Joined: Mon Jun 11, 2007 11:55 am
Has thanked: 49 times

Post by echase »

Excellent. 4 questions

1) I managed to get timer 0 working but you suggested timer 1 as it runs in sleep mode. Problem is that Flowcode does not seem to implement Timer 1 for a 16F886. Do I have to use the custom interrupt function and set it to use Timer 1? Think that will be beyond me, but I don’t want to waste your time on giving me the C code for it now as I have not yet decided to go down that route

2) I will though use something like your Choice 2. To be clear, does the PIC execute line 1 and then sit at line 2 constantly looping some code until the 6 secs interrupt is reached? If that’s true then the small time that the other lines take won’t slow down the loop from 6 secs to 6 and a bit secs. I will use something similar on the minute, hour and day and need to make sure that any other code executed does not slow it down slightly.

3) Is your C code an expanded version of what the Flowcode ‘If’ diamond does?

4) Does ‘<>’ mean ‘either greater or less than but not equal to’ ?

Errata: the above routine should have said

Display a temperature reading on LCD
Go to macro that measures the temperatures
Exactly 6 seconds after last loop display a new value
Loop for ever counting up time

But this error does not really affect the discussion.

User avatar
Steve
Matrix Staff
Posts: 3433
Joined: Tue Jan 03, 2006 3:59 pm
Has thanked: 114 times
Been thanked: 422 times

Post by Steve »

echase wrote:1) I managed to get timer 0 working but you suggested timer 1 as it runs in sleep mode. Problem is that Flowcode does not seem to implement Timer 1 for a 16F886. Do I have to use the custom interrupt function and set it to use Timer 1? Think that will be beyond me, but I don’t want to waste your time on giving me the C code for it now as I have not yet decided to go down that route
The FCD file for the 16F877a implements timer1 - you should be able to modify your 886 file accordingly (make sure you retain a backup just in case).
echase wrote:2) I will though use something like your Choice 2. To be clear, does the PIC execute line 1 and then sit at line 2 constantly looping some code until the 6 secs interrupt is reached? If that’s true then the small time that the other lines take won’t slow down the loop from 6 secs to 6 and a bit secs. I will use something similar on the minute, hour and day and need to make sure that any other code executed does not slow it down slightly.
Because the timer interrupt is being used, the processing within the main loop should not affect the timing. This is because the interrupt is pretty much guaranteed to be fired every 20ms (or whatever period you set it to). As long as you kepp the processing quick within the interrupt, things should go smoothly.
echase wrote:3) Is your C code an expanded version of what the Flowcode ‘If’ diamond does?
Yes - this is my test-based version of Flowcode icons. Not ideal I know, but it should be fairly readable. I hope to update the forum soon to allow inline images and attachments.
echase wrote:4) Does ‘<>’ mean ‘either greater or less than but not equal to’ ?
It means "not equal to". You can use the C equivalent "!=" if you prefer.
echase wrote:Errata: the above routine should have said

Display a temperature reading on LCD
Go to macro that measures the temperatures
Exactly 6 seconds after last loop display a new value
Loop for ever counting up time

But this error does not really affect the discussion.
You should not need to wait 6 seconds within your main loop. The timer interrupot, once set up properly, will keep your clock variables up-to-date. If you are simply displaying the temperature every 6 seconds, your main routine should just wait until the time has changed by 6 seconds, then read the temperature value and then display it (and then loop back so it waits again).

echase
Posts: 429
Joined: Mon Jun 11, 2007 11:55 am
Has thanked: 49 times

Post by echase »

Sorry to be thick but presumably you are saying that this code block for choice 2 is not true lines of C that I need to enter as C, as I thought, but is implemented with Flowcode 'commands/symbols'.

In which case presumably it has to be implemented with 10 diamonds as each one can only do one variable comparison?



You said "your main routine should just wait until the time has changed by 6 seconds". The code has to complete this loop 10 times (exactly 60Secs) with each time taking 6 secs

What is the Flowcode for that? Is it:

a) Loop about every 6 seconds (using delay function) around the 'read sensors and display results' LOOP UNTIL a flag is detected as set, that flag being set at 60 secs in the interrupt macro by the 6 seconds passing 10 times. So it’s done using Flowcode’s standard loop command.

Or

b) Loop around the 'read sensors and display results' loop and have some command in there that is waiting for the 6 secs to pass which will skip to the next of the 10 times. What is this command?

Or

c) Loop about every 6 seconds around the 'read sensors and display results' loop and when the timer gets to 60 secs have a standard Flowcode ‘jump to new place’ command in the interrupt macro that terminates the loop by jumping beyond it to the next code block (the minute loop).

Or d) Ditch the looping command and just have

if time =0 seconds read temp
If temp =6 read temp
.
.
.

If temp =54 read temp
Call macro that does other stuff that needs to be done every minute(completes in <1 second)
Jump back to if time = 0 seconds AND increment the minute count by one.

User avatar
Steve
Matrix Staff
Posts: 3433
Joined: Tue Jan 03, 2006 3:59 pm
Has thanked: 114 times
Been thanked: 422 times

Post by Steve »

The "choice 2" code can be implemented with a single decision icon with the following in its "if" box:

Code: Select all

(SECONDS = 0) || (SECONDS = 6) || (SECONDS = 12) || (SECONDS = 18) || (SECONDS = 24) || (SECONDS = 30) || (SECONDS = 36) || (SECONDS = 42) || (SECONDS = 48) || (SECONDS = 54) 
The main routine will be something like this:

Code: Select all

loop forever

  if SECONDS is a factor of 6 (i.e. the decision above)

    if SECONDS <> OLD_SECONDS
  
      read the temperature and update the display

      OLD_SECONDS = SECONDS

    end if

  end if

end loop
The use of "OLD_SECONDS" will prevent the ADC reading being taken continually for each second that is a multiple of 6.

Obviously you will need a mechanism for sending the PICmicro to sleep and waking it up - I'm not sure how you'd do that.

The Timer 1 interrupt would be something like this:

Code: Select all

if FRACTION = 20  (or whatever is appropriate to get seconds from the interrupt frequency)

  SECONDS = SECONDS + 1

  If SECONDS >= 60

    MINUTE = MINUTES + 1

    If MINUTES >= 60

      HOURS = HOURS + 1

      If HOURS >= 24

        HOURS = 0

      End if

    End if

  End if

End if

echase
Posts: 429
Joined: Mon Jun 11, 2007 11:55 am
Has thanked: 49 times

Post by echase »

steve wrote:
Use the Timer0 interrupt set to say 75Hz. In the interrupt routine, increment a variable. If this variable reaches 75 (or whatever the interrupt frequemcy is), then you know that 1 second has elapsed and you will be able to increment the variables that represent the seconds, minutes and hours

The Timer 1 interrupt would be something like this:

Code: Select all

if FRACTION = 20  (or whatever is appropriate to get seconds from the interrupt frequency)

  SECONDS = SECONDS + 1

  If SECONDS >= 60

    MINUTE = MINUTES + 1

    If MINUTES >= 60

      HOURS = HOURS + 1

      If HOURS >= 24

        HOURS = 0

      End if

    End if

  End if

End if
That quote is a composite from 2 different threads. I am using Timer 0. I have implemented all this in ONE Timer 0 interrupt macro driven at 61Hz and it calculates days, hours, min, secs (in 6 sec blocks) fine. 6secs is a count of 61x6=366. Clock speed 125kHz and prescaler 1:2.

I have not implemented sleep mode yet. Need to get the code fully working before adding that complexity.

1) BUT several times a day the LCD goes blank or freezes up (whereas before I implemented this Timer 0 my code was stable). PIC still reacts to button presses when LCD frozen, albeit incorrectly, so the PIC is still running something. I suspect there is a timing issue in that this macro takes too long to run and so upsets the main code and other macros that tell the LCD what to display. Do you think that may be the case? I could put the minute/hour/day calcs in the main code instead to speed macro up.

2) What happens if it's in the middle of this macro and a button is pressed calling a Port B interrupt? Can the PIC react to 2 interrupts at same time or will PIC ‘crash’?

3) In the Flowcode simulation time sticks at 00:00:00 and no time variables increment. Why? It may be OK if I slow the simulation down to >100 simulated secs = 1 real seconds, but it’s incrementing so slowly then that I have not had time to run it long enough to really check it. Real PIC is fine.

User avatar
Steve
Matrix Staff
Posts: 3433
Joined: Tue Jan 03, 2006 3:59 pm
Has thanked: 114 times
Been thanked: 422 times

Post by Steve »

(1)
I think you are right. A prescaler of 1:2 for the timer interrupt might not be long enough to get the calculations done (the PIC will essentially interrupt every 512 instructions).

Can you use a faster clock? This would give more time for calculations and if you chose an appropriate clock you would get an accurate divide for the second count.

(2)
The interrupts should both occur.

(3)
The simulation of the timer interrupt is not very good at the moment. I am working on improving this for v4.

echase
Posts: 429
Joined: Mon Jun 11, 2007 11:55 am
Has thanked: 49 times

Post by echase »

1) When you talk about the calculations do you mean the ones that do minutes, hours etc within this interrupt macro? Or the main code?
Don't want to increase clock frequency as uses more power. But could change the prescaler to say 1:4 or 1:1; would that help? Which way does it need to go?

3) Any chance of adding a Timer 1 to 16F886 whilst you are doing v4?

User avatar
Steve
Matrix Staff
Posts: 3433
Joined: Tue Jan 03, 2006 3:59 pm
Has thanked: 114 times
Been thanked: 422 times

Post by Steve »

I mean the main code. Changing to 1:4 would be better (you would get twice as much time between interrupts).

I've not thoroughly tested the timer1 yet, so I did not roll it out to all FCD files. But I will. For now, you can simply copy the [TMR1] section from the 16F877a to the 16F886 FCD file. You also need to change the [Interrupts] section so it is the same as the one in the 877a FCD file.

echase
Posts: 429
Joined: Mon Jun 11, 2007 11:55 am
Has thanked: 49 times

Post by echase »

1) So are you saying that the length of code in my interrupt macro is not the problem (within some reasonable limits presumably) but rather it's the rate at which it is interrupting my main code?

User avatar
Steve
Matrix Staff
Posts: 3433
Joined: Tue Jan 03, 2006 3:59 pm
Has thanked: 114 times
Been thanked: 422 times

Post by Steve »

sorry - I meant to say it's the length of time taken by your interrupt code.

echase
Posts: 429
Joined: Mon Jun 11, 2007 11:55 am
Has thanked: 49 times

Post by echase »

[quote="steve(3)
The simulation of the timer interrupt is not very good at the moment. I am working on improving this for v4.[/quote]

If the simulation is not very good how are the guys in this thread getting it to work?

http://matrixmultimedia.com/mmforums/vi ... php?t=4005


When I try it no variables increment at all so my clock is always at 00:00:00. Without incrementing (even if erratic or inaccurate) my whole software can't run in simulation mode as it does not get past the first temperature reading at the beginning of the programme. So it’s very difficult to use Flowcode to write any software using Timer 0 interrupts. Any thoughts for a quick fix to get it going?

Time is OK on PIC though apart from the LCD freezing problem, which is probably fixable.

User avatar
Steve
Matrix Staff
Posts: 3433
Joined: Tue Jan 03, 2006 3:59 pm
Has thanked: 114 times
Been thanked: 422 times

Post by Steve »

I'm not sure they are using simulation. I don't when using the timer0 interrupt.

echase
Posts: 429
Joined: Mon Jun 11, 2007 11:55 am
Has thanked: 49 times

Post by echase »

echase wrote:[quote="steve(3)

When I try it no variables increment at all so my clock is always at 00:00:00.

Time is OK on PIC though .
Actually I now find it is incrementing but 25 times too slowly which is not useful. I can temporarily change the interrupt flag to 25 times less to aprox simulate the timing, but have to remember to reset it again before programming the PIC.

Is there a line in the 886.FCD file that I can change to correct out this timing error?

I am running the simulation 'as fast as possible' and the delays are the correct length but not this interrupt.

User avatar
Steve
Matrix Staff
Posts: 3433
Joined: Tue Jan 03, 2006 3:59 pm
Has thanked: 114 times
Been thanked: 422 times

Post by Steve »

Sorry, I don't think there is any way to correct it at the moment.

Post Reply