PDA

View Full Version : 12F675 A/D and GPIO sleep interrupt



macinug
- 29th August 2008, 11:21
Hi,
This project opens a valve if it's closed and has 5V at the A/D input, and closes it if it is open and has a 0V at the A/D input, going to sleep after 10s. It wakes if the GP5 input goes high. This is OK except that it hangs if powered up in the closed position. Could anyone advise if my logic in the code is wrong or if the A/D reading is set up wrong? The ADCON0.0 = 0 doesn't seem to deactivate the A/D converter either. Here is the code: Thanks


@ device pic12F675, intrc_osc_noclkout, wdt_off, pwrt_on, mclr_on, protect_off, bod_off
CMCON = %00000111 'CMCON = 7 comparators off
trisio = %00101001 'INPUTS =1 OUTPUTS=0 (GP3 always i/p)
DEFINE OSCCAL_1K 1 'Set OSCCAL for 1K device (tunes to exactly 4MHz)
ANSEL = %01010001 '16tosc, gpio0 analogue input
ADCON0 = %10000000 'right just , Vref=Vdd , ch.0 , A/D off
INTCON=%10001000 'Interrupt Control Register
ioc = %00100000 'Set interrupt on change to GP5

'variables
POTVALUE VAR word 'POTENTIOMETER VALUE VARIABLE
ValveState var bit 'ValveState: 0 = Valve closed 1 = Valve open
TimeOut var byte 'variable to countup timeout

'Start up procedure
pause 1000
GPIO = %00010100 'IN1 and enable Dir1 (close) for start condition
pause 2000
GPIO = %00000000
let valvestate = 0
let timeout = 0

'loop
START:
pause 1000 'loop time (determines timeout)
GPIO = %00000000 'keeps o/ps off, also clears interrupt GPIF
adcon0.0 = 1 'turn on a/d
pause 10
ADCON0.1 = 1 'start A/D
while ADCON0.1 = 1 'do until A/D finished (use GO/DONE bit?)
wend
potvalue.highbyte = adresh 'high byte of 10bit value
potvalue.lowbyte = adresl 'low byte of 10bit value
'Is this formatting the result correctly?

If (POTvalue < 250) and (valvestate = 1) THEN
GPIO = %00010100 'IN1 and enable Dir1 (close)
pause 3000
valvestate = 0
adcon0.0 = 0 'turn off a/d until next loop
endif

IF (POTvalue >= 250) and (valvestate = 0) THEN
GPIO = %00000110 'IN2 and enable Dir (open)
pause 3000
valvestate = 1
adcon0.0 = 0 'turn off a/d until next loop
endif

if (valvestate = 0) then timeout = timeout +1
if (valvestate = 1) then timeout = 0
if (timeout > 10) then goto SLEEP_IT 'timeout value * loop time
goto start

'subroutines
SLEEP_IT: 'use asm code for sleep as pbp has a fixed period
GPIO = %00000000
pause 1000
INTCON.0 = 0 'clear interrupt flag if set (GPIO should do this)
@ sleep
@ nop
goto start

end

Archangel
- 29th August 2008, 22:34
Maybe I'm not seeing the big picture . . .


SLEEP_IT: 'use asm code for sleep as pbp has a fixed period
<font color=red>GPIO = %00000000</font color>
pause 1000
INTCON.0 = 0 'clear interrupt flag if set (GPIO should do this)
@ sleep
@ nop
goto start

in your sub routine you command all GPIOs as outputs, how will it receive
the wake up?

Bruce
- 30th August 2008, 01:05
With global interrupts enabled it will wake up and jump to location 4 expecting an interrupt
handler.

Disable global interrupts. Interrupt on change will wake the PIC from sleep, then execute
the instruction after sleep without vectoring to location 4.

Read the section on Power-Down Mode (SLEEP) for details on why this happens.

macinug
- 2nd September 2008, 14:19
Thanks Joe.S and Bruce.
The SLEEP routine does actually work!!

Doesn't the GPIO = %00000000 command set all pins which are outputs to 0?
TRISIO configures them as either inputs or outputs?
It could be that the GPIO commands are causing my problem though.

The problem is that the system stays in closed position if it is started in the closed position.
If the system is started in the open position it closes it (as in the start-up routine) then opens closes and sleeps as intended.

Any chance of a 2nd look?
Cheers

Bruce
- 2nd September 2008, 15:12
Can you post a schematic?

macinug
- 3rd September 2008, 15:32
Hi Bruce,
Here it is. Basically driving a H-Bridge with 2 inputs and an enable.
Hope this helps. The analog input and sleep interrupt is derived from one 0/12V signal, hence stepped down.
Thanks

Bruce
- 3rd September 2008, 16:29
It would help if you hard part values and part descriptions along with voltage levels at
various nodes in your schematic, but what is connected to the center node entering R1?

Which state change are you expecting to wake the PIC from sleep? If you're not testing for
this before entering sleep, you have no idea what level transition causes a wake-up. May
or may not be important. Just curious.

Also, if you're just testing for 0-5V why not just use a digital input VS an A/D?

With 10-bit resolution testing for potvalue >=250 is testing for >=~1.22V. Is the voltage in
on GPIO.0 and GPIO.5 below the input threshold levels?

Note: You still need to disable global interrupts. It will jump to location 4 on the 1st wake-
up so you'll be executing code from somewhere unexpected after the 1st wake-up. If it
does make it through that somehow global interrupts will be disabled on the 2nd pass, but
it's still not going to be working like you expect.

macinug
- 4th September 2008, 09:19
Bruce,
Thanks for looking and for some good points.

The bridge voltage (R1/R2) is either 0V or 4V. I used analog as I may need to be flexible on the voltage values later on.

The sleep operation does work fine, but I have disabled global interrupt at the start now.

The problem is that GP4 sometimes goes high of its own accord on switching on. The length of time it stays on varies, after that operation is as I intended. Is this a boot up procedure I have not reckoned with?

Also, have I assembled the bytes of the 10bit A/D correctly?

Cheers

Bruce
- 4th September 2008, 14:29
Your A/D part looks fine. If GPIO.4 is going high on power-up, it's most likely due to you
not initializing the port latches before writing to the tris register. Port latches are unknown
at power-up so it's a good idea to set the port to whatever you want 1st then write to the
tris register.

I.E. GPIO = 0 followed by TRISIO = whatever. Then you know the pins that are outputs will
be at a certain logic level at POR.

You have trisio = %00101001, a few other init lines, a pause 1000, then you write to the
port. You have no idea what value is on the output pins until you write to the port after the
pause 1000. Which may not be good with your outputs controlling a motor!

Note: Reading or writing to a port does not clear the interrupt on-change flag. This will just
end the miss-match condition, which then allows you to manually clear the flag.

Read the port, then clear the flag, then enter sleep. That may help.

Archangel
- 4th September 2008, 20:11
If GPIO.4 is going high on power-up, it's most likely due to you
not initializing the port latches before writing to the tris register. Port latches are unknown
at power-up so it's a good idea to set the port to whatever you want 1st then write to the
tris register.

I.E. GPIO = 0 followed by TRISIO = whatever. Then you know the pins that are outputs will
be at a certain logic level at POR.



That is really good to know, logic would seem to indicate the opposite which is to say, It would appear that you would set I/O so as to know if ports are outputs or not.<b> YOUR explanation makes good sense.</b>. Another tidbit for your book?
Thanks for that BRUCE,
JS

macinug
- 8th September 2008, 14:39
Thanks Bruce, thanks Joe.S.
The project is now working. I hope this is useful to others too.
It's a good forum.
Cheers
macinug