PDA

View Full Version : Wierd sleep issue



orca
- 12th March 2006, 00:34
I apologize if this topic has been previously covered but I could not find after searching for alitte while.

I am using a PIC 16F676, ICD2, PICBASIC Pro, internal 4Mhz RC osc.

Basically I am using the PIC to measure temperature and pressure, display them to an Optrex LCD and then place the PIC in sleep mode to conserve battery power.

The problem is the first pass through the code the sleep command is either skipped (highly unlikely) or somehow times out instantly prior to one of the two wake-up methods and continues on to the next pass. The two methods are 1) WTD based on the PBP sleep command or 2) an external interrupt which can wake up the PIC before the WDT exits the sleep command. After the first pass it works fine, i.e. it goes to sleep, if I only allow the wake-up to be WDT based. If I wake it up with the ext int it exhibits the same behavior as the first pass and will then work on the next pass. This is very strange.

I have also tried using only the ext int, turning off the WDT and using @sleep only to get the same results: does not go to sleep in the first pass but will after the second pass. Code is below. Any assistance will be greatly appreciated.

' Set LCD data port to PORTC
DEFINE LCD_DREG PORTC

'Set starting data bit to 4
DEFINE LCD_DBIT 0

'Set LCD register select bit to PORTC
DEFINE LCD_RSREG PORTC

'Set LCD register select bit to bit 4
DEFINE LCD_RSBIT 4

'Set LCD enable port
DEFINE LCD_EREG PORTC

'Set enable bit
DEFINE LCD_EBIT 5

TRISA.5 = 0 'Set PORTA BIT 5 to output, Voltage reg enable/disable
PORTA.5 = 0

TRISA.4 = 0 'Set PORTA BIT 4 to output to be on/off for LCD and temp sensor power
PORTA.4 = 1

'Set clock speed
'DEFINE OSC 4

TEMP VAR word
t0 VAR TEMP.byte0
t1 VAR TEMP.byte1
w0 VAR word
w1 VAR word
w2 var word

DEPTH VAR word
d0 VAR DEPTH.byte0
d1 VAR DEPTH.byte1
RA2 var bit
i var byte

TRISA.1 = 1 'Set PORTA BIT 1 to input
ANSEL.1 = 1 'Select PORTA bit 1 to analog input for Temp Sensor

TRISA.0 = 1 'Set PORTA BIT 0 to input
ANSEL.0 = 1 'Select PORTA bit 0 to analog input for Pressure Sensor

TRISA.2 = 1 'Set PORTA BIT 2 to input
ANSEL.2 = 0 'Be sure PORTA BIT 2 is a digital input for Ext Int Wake Up

option_reg.6 = 0 ' set interrupt to occur on falling edge
intcon.4 = 1 ' enable external interrupt

ADCON1 = %01010000 'Set A/D clock source to 16Tosc
'to ensure sufficient conversion time

MAIN:

for i = 1 to 20
pause 1000
' Temperature measurement
ADCON0 = %10000101 'result is right justified, Vref = external (using 1.024V at present)
'select RA1, enable but not start A/D.

PAUSEUS 25 'A/D acquisition time for sample and hold circuit

ADCON0.1 = 1 'Start A/D conversion

WHILE PIR1.6 == 0 'wait for A/D conversion to finish
WEND

ADCON0.0 = 0 'disable A/D converter to save power
PIR1.6 = 0 'reset interrupt flag

' Place results into TEMP variable
t0 = ADRESL
t1 = ADRESH

' approximate resolution is 4.86mV/ct. Since no floating point
' routines in PBP use fixed point math and keep track of decimal
TEMP = TEMP *54 ' Want to multiply by 486 but too many issues arrise from PBP inability to have variables longer than 16-bits

w0 = TEMP / 10000
w1 = TEMP // 10000

w0 = w0 * 9
w1 = (w1 / 10) * 9 'Remainder seems to be 4 places so divide by 10 first to keep the *9 confined to a 16-bit number

w0 = w0 + w1 DIG 3 ' Whole number plus most significant digit of remainder hand waving
w1 = w1 DIG 2 ' Next significant digit of remainder as the temths decimal place

Lcdout $fe, 1 'Clear LCD screen
Lcdout "T= ", DEC w0,".",DEC w1,"C"

' Pressure or Depth measurement
ADCON0 = %10000001 'result is right justified, Vref = Vdd
'select RA0, enable but not start A/D.

PAUSEUS 25 'A/D acquisition time for sample and hold circuit

ADCON0.1 = 1 'Start A/D conversion

WHILE PIR1.6 == 0 'wait for A/D conversion to finish
WEND

ADCON0.0 = 0 'disable A/D converter to save power
PIR1.6 = 0 'reset interrupt flag
d0 = ADRESL
d1 = ADRESH

'DEPTH = DEPTH - 38 'Subtract offset ~0.183v = ~38 counts
'DEPTH = DEPTH * 44
'DEPTH = DEPTH / 128
'DEPTH = DEPTH *110
'w0 = DEPTH / 169
'w1 = DEPTH // 169

Lcdout $fe, $C0 'Clear LCD screen
Lcdout "D= ", DEC d0 ',".",DEC w1

next i

Lcdout $fe, 1 'Clear LCD screen
Lcdout "ENTERING"
Lcdout $fe, $C0 'Clear LCD screen
Lcdout "SLEEP"

PAUSE 500

' PORTA.5 = 0 'Turn off power to pressure sensor

PORTA.4 = 0 'Turn off power to temp sensor and LCD

TRISC = %000000
PORTC = 0 'Place all output to zero for zero current draw

sleep 300

intcon.1 = 0
PORTA.4 = 1
' PORTA.5 = 1

CLEAR 'Clear all RAM including system RAM. This is important
'because it clears the FLAGS register that includes the
'LCDINITFLAG. The LCDINITFLAG is SET to indicate that
'the LCD has been initialized by the LCDOUT command. But since exiting SLEEP is a
'WatchDog timeout reset which just resumes normal operation
'the LCDINITFLAG is still SET so that when power is restored
'to the LCD the program thinks its initialized and LCDOUT does
'not attempt to re-initialize, which is not good!

asm

clrf 32h

endasm

pause 1000

Lcdout $fe, 1 'Clear LCD screen
Lcdout "End Loop"


GOTO MAIN

mister_e
- 12th March 2006, 10:15
you should consider reading the whole datasheet or at least Section 9.7. Be sure you understand it with your current project configuration, config fuses, and it should be OK. Oh well i didn't read and analyse the whole thing as now so i can be wrong.

Also...


asm

clrf 32h

endasm


i don't like it... and what do you expect it will do?

Maybe i'm now also blind but i don't see any register in that specific address. AND MORE, it's not a valid way to write clrf instruction.

clrf h'32' OR clrf 0x32 are valid

PS: help us a little bit when posting your code, use the VB code click here (http://www.picbasic.co.uk/forum/misc.php?do=bbcode). that way it will be a little bit easier to read.. Even better if some of your code lines are indented.

orca
- 14th March 2006, 21:51
Thank you Mister e,

It never occurred to me to read the data sheet, especially any part of section 9. I have since found the problem. Although I'm not sure why yet, somehow on power-up intcon<1> gets set even thought the data sheet indicates that the intcon register 'should' power up to all zeros. Anyway, if I place the clear intcon<1> , ext int flag bit, code just before the sleep command rather than after the problem goes away.

However, I do appreciate the code help with the assembler code:

asm
clrf 32h
endasm

The misuse of that explains why I needed the CLEAR statement just prior to the snipet of code as they should be redundant statements, I think. Anyway the reason for that is when exiting sleep the LCD would not work properly. After days of haed wracking I finally took a look at the PBP commands for the LCD, i.e. LCDOUT, LCDIN etc. What I found was when the LCDOUT command is issued it looks at a flag bit called LCDINIT and if the bit is clear it then initializes the LCD, if set it does not go through the initialize routine. So, since exiting sleep is a just a continuation of the code the LCDINIT flag is still set so subsequent calls to LCDOUT ignore the initialization routine even though the LCD was turned off. Therefore the LCDINIT flag needs to be cleared after exiting sleep. Guess where the LCDINIT flag bit, among others, is stored by PBP, 0x32.

Thanks for your assistance!

mister_e
- 14th March 2006, 22:06
O.K.. so now go on the PBP manual, scroll the page and you'll discover
FLAGS=0.

Always trust yourself. All those POR default... may sometimes be true, sometimes not. I always set them myself.

Great to know it's workinf for you now.