PDA

View Full Version : 16F1823 - Can't get RA3 (MCLR) to be a switch input (attached switch resets PIC).



HankMcSpank
- 9th January 2011, 01:27
Now I'm sure this is simple - but I've stared at it to the point where I now need to go for a shave, but I need to use PortA.3 (which can be a MCLR pin), as an 'input' for a tactile switch...I want to use an internal weak pullup on that pin too.

What I'm getting Is the PIC resetting everytime I press the switch attached to pin 4 (PortA.3)....so it looks like MCLR is not being disabled. I've checked the associated .inc file in my PC's MPASM directory for the necessary syntax - i think i've got it right.

I've slimmed my program down to the basics...just to get to the bottom of this. A simple loop, when either one of two switches are pressed, A DT interrupt happens & I get some syntax on screen - but it aint right, Sw1 doesn't interrupt at all, Sw2 does, but I just see "Interrupt Sw1" on my screen
...and it doesn't exit until I press Sw1 (which threw me, but then I put a litte trap at the top of my program & established that Sw1 was simply resetting the PIC)

Top tips warmly received.....



@ __CONFIG _CONFIG1, _FCMEN_OFF & _FOSC_INTOSC & _WDTE_OFF & _MCLRE_OFF & _CP_OFF & _IESO_OFF & _BOREN_OFF & _PWRTE_OFF

DEFINE OSC 4
INCLUDE "DT_INTS-14.bas" ' Base Interrupt System PO90OOO9
INCLUDE "ReEnterPBP.bas" ' Include if using PBP interrupts

RCSTA = $90 ' Enable serial port & continuous receive
TXSTA = $24 ' Enable transmit, BRGH = 1
SPBRG = 8 ' 115200 Baud @ 4MHz, -3.55%
SPBRGH = 0
BAUDCON.3 = 1 ' Enable 16 bit baudrate generator

'-------------------------------------------------------------------------

Osccon = %01101010 'sets the internal oscillator

APFCON.2 = 0 ;Hserout onto RC.4 Pin 6
ADCON0 = 0
ADCON1 = 0

CM1CON0 = 0 ' COMPARATORS OFF
CM2CON0 = 0 ' COMPARATORS OFF

ANSELA = %00010000
ANSELC = %00000100
TRISA = %11111111
TRISC = %00000100
OPTION_REG.7 = 0

WPUA = %00101000
IOCAN = %00101000

SW1 VAR PORTA.3
SW2 VAR PORTA.5
hserout ["reset", 13, 10]

ASM
INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler IOC_INT, _Switch_Interrupt, PBP, YES
endm
INT_CREATE ; Creates the interrupt processor
ENDASM

IOCAF = 0

@ INT_ENABLE IOC_INT ; Enable 'Int On Change' interrupts


Loop1:
hserout ["Waiting", 13, 10]
pause 500
GOTO Loop1
'ENDIF


'+++++++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++++++++++++
Switch_Interrupt:
@ INT_DISABLE IOC_INT ; Disable further IOC interrupts

pause 10
IF sw1 = 0 THEN
HSEROUT ["INTERRUPT Sw1", 13, 10]
goto interrupt_end
endif

IF sw2 = 0 THEN
HSEROUT ["INTERRUPT Sw2", 13, 10]
goto interrupt_end
endif

interrupt_end:
@ INT_ENABLE IOC_INT
@ INT_RETURN


end

Bruce
- 9th January 2011, 14:00
Make sure you include _LVP_OFF in CONFIG2 and test/clear IOCAF.3 and IOCAF.5 in your interrupt handler. The IOCAF bits will indicate which switch was pressed so you don't need to have a switch being held down or test for it.

The /MCLR bit in CONFIG1 is ignored when LVP is enabled so it remains the reset input. LVP is enabled by default when you don't specifically clear it in CONFIG2.

It never exits your interrupt because you're not clearing the IOCAF int flags in your int handler, so it's a continuous loop until reset by SW1 on /MCLR.

HankMcSpank
- 9th January 2011, 14:15
Make sure you include _LVP_OFF in CONFIG2 and test/clear IOCAF.3 and IOCAF.5 in your interrupt handler. The IOCAF bits will indicate which switch was pressed so you don't need to have a switch being held down or test for it.

Excellent stuff Bruce, the following line - containing the changes you siuggested - sorted my problem....


@ __CONFIG _CONFIG2, _LVP_OFF


My RA3 pin now works as a digital input! (I've spent hours on this puppy - what a relief ...a hearty thanks for chiming in!)

Now I'm sure you're going to say this snippet of (IMHO obscure!) info is in the datasheet?

Bruce
- 9th January 2011, 14:25
See REGISTER 4-1:CONFIGURATION WORD 1 in the datasheet.

If LVP = 1 the /MCLR bit is ignored and the pin remains the reset input. Since you didn't include CONFIG2 settings in your code, LVP defaulted to 1 ON and that caused the problem.

I would get rid of the 10mS pause in the int handler, then test & clear whatever IOCAF flag bits are set to determine which switch was pressed. This is a really nice feature on the 16F1s since IOC pins have individual flag bits now. I.E. you don't need to read the port when the IOC happens any more.

HankMcSpank
- 9th January 2011, 14:47
See REGISTER 4-1:CONFIGURATION WORD 1 in the datasheet.

If LVP = 1 the /MCLR bit is ignored and the pin remains the reset input. Since you didn't include CONFIG2 settings in your code, LVP defaulted to 1 ON and that caused the problem.

I would get rid of the 10mS pause in the int handler, then test & clear whatever IOCAF flag bits are set to determine which switch was pressed. This is a really nice feature on the 16F1s since IOC pins have individual flag bits now. I.E. you don't need to read the port when the IOC happens any more.

Thanks Bruce ....that 10ms pause has now gone (I can't recall why it was in there...obviously been dabbling at one point & it's remained!)

Re testing for an IOCAF flag (to establish which switch has been pressed)...is there a win over vs checking for a 'Low'/0V as I'm doing presently? (if so, then I'll work out what needs to be done....but all the new registers on this IC are scrambling my head!)

Bruce
- 9th January 2011, 15:00
You can test the input for 0, but any interrupt flag bits that get set should always be cleared before re-enabling the interrupt.

HankMcSpank
- 9th January 2011, 15:26
You can test the input for 0, but any interrupt flag bits that get set should always be cleared before re-enabling the interrupt.

Thanks once again Bruce, here's my interrupt handler now (complete with a clear flag at the end!)...



Switch_Interrupt:
@ INT_DISABLE IOC_INT ; Disable further IOC while handling an IOC interrupt

IF Sw1 = 0 AND Sw2 = 1 THEN
HSEROUT ["INTERRUPT Sw1", 13, 10]
goto interrupt_end
endif

IF Sw1 = 1 AND Sw2 = 0 THEN
HSEROUT ["INTERRUPT Sw2", 13, 10]
goto interrupt_end
endif

IF Sw1 = 0 AND Sw2 = 0 THEN
HSEROUT ["INTERRUPT Sw3", 13, 10]
goto interrupt_end
endif

interrupt_end:
IOCAF = 0
@ INT_ENABLE IOC_INT

@ INT_RETURN