Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

SETUP AN INTERRUPT IN 16f690

Status
Not open for further replies.
I haven't tried on the hardware because I was considering to make what Eric had suggested but, now it seems you have an easier idia but, I don't understand what do you mean by WPUs (WPUA=2 and OPTION.7 = 0)
 
You can enable internal resistor on the pic chip, these are referred to as weak pullups (WPU). You turn them on by clearing bit 7 of the OPTION (0x81) register and setting the appropriate bit in the WPUA (0x95) register.

Mike.
 
Well, I tried what you have suggested check the codes:

Code:
  		list	p=16f690 
		#include <p16f690.inc>
		__CONFIG -_MCLRE_ON & _CP_OFF & _WDT_OFF & _INTRC_OSC_NOCLKOUT
		ERRORLEVEL -302

	cblock	0x20
		temp	
		display	
		count	
	endc

;**************************STEUP THE CONSTANTS*******************************  

		org	0x00		;this is where we come on power up and reset
		goto	Main

;**************************INTRUPT ROUTINE************************************  

		org	0x04

		movwf	temp   		;this and the lable Loop will run simultenously
					;move w into f in case to there was someting in  
					;count(see first step of Loop) 

		incf	count,f  	;increase count by 1 and put result in count
		movlw	.10   		;load w with decimal 10
		subwf	count,w  	;subtract count from w and place result in w
		btfss	STATUS,C  	;if in above operation count<= w then carry bit 
					;is set, so check for that and skip next step 
					;if it is set 
		goto	carry_on
		goto	clear

carry_on:
		bcf	INTCON,0x01   	;clear the INTF, just in case(read tuto. 11)
		movfw	temp   		;move temp to w 
		retfie			;get out of intrupt loop (this will start over 
					; the whole INTRUPT LOOP again 
clear:
		clrf	count   	;set count to 0
		bcf	INTCON,0x01  	;clear INTF
		retfie
;*****************************MAIN PROGRAMME************************  
Main:

;*****************************SET UP THE INTRUP REGISTERS***********  

		bsf	INTCON,0x07  	; set globel intrupt (tell PIC that we will use intrupts)
		bsf	INTCON,0x04  	;
		bcf	INTCON,0x01

;******************************SET UP THE PORTS**********************  
		bsf	STATUS,RP0
		movlw	b'10000000'
		movwf	TRISC
		movlw	b'00000100'
		movwf	TRISA	;set RA2 as input (for interrupt)
		bcf 	STATUS,RP0
		bsf	STATUS,RP1
		[COLOR="Red"]bcf	OPTION_REG,0x07
		bsf	WPUA,0x02[/COLOR]		             
                         clrf 	     ANSEL
	             bcf           STATUS,RP1
;******************************NOW SEND THE VALUE OF COUNT TO PORTC**  

Loop:
		movf	count,w
		movwf	PORTC
		goto	Loop
		END

but, that is also not working I think something wrong with hardware, any way I have a spare16f628 and will try some simpler code on that, there is just one problem with 16f628 and that is it does'nt have any ANSEL register so how can I set the PORTS to work for digital ckt?
 
The 628 doesn't have an ADC module and so no ANSEL. It does have comparators and these have to be turned of by writing 0x07 to CMCON. You turn the WPUs on by just clearing bit 7 of the OPTION register and the int pin is RB0.

Mike.
 
Here is the code for 628, pin 0 of port a will be HIGH and on interrupt pin 7 will also be high, running it in simmulation with F9 still hangs MPLAB and animation takes too much time, kindly check the code and tell me it is right or not then I'll move to hardware.

Code:
list p=16f628
		#include<p16f628.inc>
		__CONFIG  _MCLRE_ON & _CP_OFF & _WDT_OFF & _INTRC_OSC_NOCLKOUT
		ERRORLEVEL   -302
		cblock	0x20
			temp       
  		endc
;******************************************************************
	org 0x00
	goto main
;***********************************INTERRUPT LOOP*****************
	org 0X04
inter:
	movlw b'10000000'
	movwf PORTA				;set pin 7 of port a HIGH
	goto	inter
main:
	bsf	INTCON,0x07
	bsf INTCON,0x03
	bcf	INTCON,0x00
;**********************************SET UP THE PORTS *****************
	bsf	STATUS,RP0			;switch to BANK 1
	movlw b'00000001'	
	movwf TRISB				;set RB0 as input
	movlw b'00000000'
	movwf TRISA                                               ;set PORT A all output
	bcf OPTION_REG,0x07			
	bcf STATUS,RP0			;back to BANK 0
	movlw 0x07
	movwf CMCON				

Loop:
	movlw b'00000001'		
	movwf PORTA				;set pin 0 of port a HIGH
	goto Loop
	END

thanks a lot for all help!:)
 

Attachments

  • image 3.png
    image 3.png
    15.9 KB · Views: 237
Last edited:
I just noticed that your accessing Option_reg and WPUA in bank 2, they are in bank 1.

Edit, in reference to 690 code.

Mike.
 
Last edited:
The RB0 interrupt is enabled by setting INTCON,4 not 3.

Edit, in reference to 628 code.

Mike.
 
:)Thank you so much it works on hardware for 628 but only it responds to interuupt only one time. First when I turn on the power LED #1 lights up and then when I close the switch LED # 2 lights up (LED # 1 turns off), this happen even when I don't close the switch and just touch the RB0 side of the resistor lead, now again when I open the switch or remove my fingure from RB0 side of thr resistor lead LED # 1 should light up and LED # 2 should be turned off but this doen't happen, I tried resetting the INTCON,0x01 bit but, that did'nt work, though I think now I'm not too far.


Code:
	list p=16f628
		#include<p16f628.inc>
		__CONFIG  _MCLRE_ON & _CP_OFF & _WDT_OFF & _INTRC_OSC_NOCLKOUT
		ERRORLEVEL   -302
		cblock	0x20
			temp       
  		endc
;******************************************************************
	org 0x00
	goto main
;***********************************INTERRUPT LOOP*****************
	org 0X04
inter:
	movlw b'10000000'
	movwf PORTA				;set pin 7 of port a HIGH
	goto	inter
main:
	bsf	INTCON,0x07
	bsf INTCON,0x04
	bcf	INTCON,0x01
;**********************************SET UP THE PORTS *****************
	bsf	STATUS,RP0			;switch to BANK 1
	movlw b'00000001'	
	movwf TRISB				;set RB0 as input
	movlw b'00000000'
	movwf TRISA				;setPORT A all output
	bcf OPTION_REG,0x07
	bsf OPTION_REG,0x06		
	bcf STATUS,RP0			;back to BANK  0
	movlw 0x07
	movwf CMCON				

Loop:
	bcf INTCON,0x01
	movlw b'00000001'		
	movwf PORTA				;set pin 0 of port a HIGH
	goto Loop
	END
 

Attachments

  • PIC1.jpg
    PIC1.jpg
    16.5 KB · Views: 226
Your interrupt cannot end with goto inter. Try changing it to,

Code:
		list	p=16f628
		#include<p16f628.inc> 
		__CONFIG _MCLRE_ON & _CP_OFF & _WDT_OFF & _INTRC_OSC_NOCLKOUT
		ERRORLEVEL -302
		cblock	0x20
		temp	 
		endc
;******************************************************************  
		org	0x00
		goto	main
;***********************************INTERRUPT LOOP*****************  
		org	0X04
inter:		
		btfss	PORTA,7
		goto	TurnOn
		bcf	PORTA,7
		bsf	PORTA,0
		goto	ExitISR
TurnOn		bsf	PORTA,7
		bcf	PORTA,0
ExitISR		bcf	INTCON,1
		retfie


main:
		bsf	INTCON,0x07
		bsf	INTCON,0x04
;**********************************SET UP THE PORTS *****************  
		bsf	STATUS,RP0   	;switch to BANK 1
		movlw	b'00000001'
		movwf	TRISB    	;set RB0 as input
		movlw	b'00000000'
		movwf	TRISA         	;set PORT A all output
		bcf	OPTION_REG,0x07
		bcf	STATUS,RP0   	;back to BANK 0
		movlw	0x07
		movwf	CMCON

Loop:
		goto	Loop
		END

The above toggles bit 7 whenever an interrupt occurs. Edit, made it toggle between 7 and 0.

Note, this is not very good code. If the main program happened to be in bank 1 when the interrupt occurs then it wouldn't work correctly. The normal way to start and end an interrupt service routine is,
Code:
		ORG	0x004         	; interrupt vector location
		movwf	w_temp        	; save off current W register contents
		movf	STATUS,w      	; move status register into W register
		movwf	status_temp   	; save off contents of STATUS register


; isr code can go here or be located as a call subroutine elsewhere  


		movf	status_temp,w 	; retrieve copy of STATUS register
		movwf	STATUS        	; restore pre-isr STATUS register contents
		swapf	w_temp,f
		swapf	w_temp,w      	; restore pre-isr W register contents
		retfie			; return from interrupt

The above is out of the template file supplied by Microchip. You can find it at C:\Program Files\Microchip\MPASM Suite\Template\Code and it's called 16F628temp.asm

Mike.
 
Last edited:
I don't want to toggle the 7th bit but, I want to make it constant HIGH when interrupt occur and 1st bit to be LOW during that period and as the interrupt is removed 1st bit should be constant HIGH and 7th bit should be constant LOW.I mean the whole programme completely stoped (not halted or paused )and an LED indicates that an interrupt has occured.Thank you for correcting "retfie" mistake.:)
 
I think you are confused about how interrupts work. The int0 interrupt is triggered whenever RB0 goes from 0 to 1. It then executes the Interrupt Service Routine (ISR) before returning to the previous task. Your ISR took approx 3uS to execute before it returned to the previous task (assuming you removed the goto). The LED on RA7 will have been illuminated for around 10uS before your main code changed it again. The human eye cannot see 10uS.

I posted the code above as an example for you to learn from. You should study it and work out how it operates. You should then be able to make it do anything you like.

Mike.
 
Thank you Mike you have tought me so much very patiently, I realy appreciate that. As you said the delay is very small for human eyes to realize now I understand that why I can't see RA0 being LOW, I will follow your advice of studying you code and try to make my own.
Edit: I don't understand why you said this:

Note, this is not very good code. If the main program happened to be in bank 1 when the interrupt occurs then it wouldn't work correctly.

Why so ?
 
Last edited:
Edit: I don't understand why you said this:

Note, this is not very good code. If the main program happened to be in bank 1 when the interrupt occurs then it wouldn't work correctly.

Why so ?

When an interrupt comes along we have to ensure two things:

First, when the interrupt finishes we need to make sure the processor is in the same state as when it started. We do this by saving the value that is in W, STATUS and when we have more complex code FSR, PCLATH and any other special function registers that may be altered by the ISR.

Second, we have to ensure that the code in the ISR executes correctly and so we have to ensure that various things are correct, the bank selection bits, the indirect register bit, PCLATH etc.

In the example above, if an interrupt came along while the main code was in bank 1 then instead of testing and changing PORTA it would test and change TRISA.

Mike.
 
Thanks Mike! now the PIC is doing exactly what I wanted, now I'll try my hands on a line follower, Thanks again for all help:)

Edit:

Is this now O.K. ?

Code:
list p=16f628
		#include<p16f628.inc>
		__CONFIG  _MCLRE_ON & _CP_OFF & _WDT_OFF & _INTRC_OSC_NOCLKOUT
		ERRORLEVEL   -302
		cblock	0x20
			temp 
			temp_s      
  		endc
;******************************************************************
	org 0x00
	goto main
;***********************************INTERRUPT LOOP*****************
	org 0X04
inter:
		[COLOR="Red"]movwf temp
		movf STATUS,w
		movwf temp_s
		movlw b'10000000'
		movwf PORTA
		btfsc PORTB,0x00
		goto inter
		bcf INTCON,0x01
		movf temp_s,w
		movwf STATUS
		movf temp,w
		retfie[/COLOR]
main:
	bsf	INTCON,0x07
	bsf INTCON,0x04
	bcf	INTCON,0x01
;**********************************SET UP THE PORTS *****************
	bsf	STATUS,RP0			;switch to BANK 1
	movlw b'00000001'	
	movwf TRISB				;set RB0 as input
	movlw b'00000000'
	movwf TRISA				;setPORT A all output
	bcf OPTION_REG,0x07
	bsf OPTION_REG,0x06		
	bcf STATUS,RP0			;back to BANK  0
	movlw 0x07
	movwf CMCON				

Loop:

	movlw b'00000001'		
	movwf PORTA				;set pin 0 of port a HIGH
	goto Loop
	END
 
Last edited:
As 628 has only one external interrupt (RB0) how can I use it for two phototransistors for a line follower ?
 
Last edited:
The way you are restoring the W register at the end of the interrupt will cause it to set/clear the Zero flag in the status register. If your main code is about to test the Zero flag when an interrupt occurs, it may end up being set incorrectly when it returns from the interrupt - this is a bad thing that you don't want to do.

Code:
org 0X04
inter:
         movwf temp
         movf STATUS,w
         movwf temp_s
         movlw b'10000000'
         movwf PORTA
         btfsc PORTB,0x00
         goto inter
         bcf INTCON,0x01
         movf temp_s,w
         movwf STATUS
         [COLOR=red]movf temp,w     ;<- This will affect the Z flag in the status register[/COLOR]
         retfie




You need to do it like this. The swapf instructions restore the value into W without affecting the Z flag in the status register

Code:
org 0X04
inter:
          movwf        temp
          swapf        STATUS,W
          clrf           STATUS
          movwf        temp_s
 
          movlw b'10000000'
          movwf PORTA
          btfsc PORTB,0x00
          goto inter
          bcf INTCON,0x01
 
          swapf         temp_s,W
          movwf         STATUS
          swapf         temp,F
          swapf         temp,W
          retfie
 
Last edited:
Thanks Mike and Pete !
edit:
Mike why it is :

swapf temp,F ; move whatever in temp to temp ???????
swapf temp,W ; move whatever in temp to W
 
Last edited:
swapf temp,F ; move whatever in temp to temp ???????
swapf temp,W ; move whatever in temp to W


If you use a MOVF instruction to get the value in temp back into W it will always set/clear the Zero flag in the STATUS register so you need a way to do that without affecting the flags.

SWAPF doesn't affect any flags in the STATUS register however it does swap the high and low nibbles in the byte so you need to do a "double swap" to recover the W register without affecting the STATUS register and with the nibbles the right way round.

SWAPF temp,F ; swaps the high and low nibbles in temp
SWAPF temp,W ; swaps the high and low nibbles back the right way and puts the result into W
 
Last edited:
Thanks Pete ! I tried your advice of using RB4-7 as interrupts but, that's not working here is the code:

Code:
	list p=16f628
		#include<p16f628.inc>
		__CONFIG  _MCLRE_ON & _CP_OFF & _WDT_OFF & _INTRC_OSC_NOCLKOUT
		ERRORLEVEL   -302
		cblock	0x20
			temp 
			temp_s      
  		endc
;******************************************************************
	org 0x00
	goto main
;***********************************INTERRUPT LOOP*****************
	org 0X04
inter:
		movwf temp
		swapf STATUS,w
		clrf  STATUS
		movwf	temp_s		
		movlw b'10000000'
		movwf PORTA
		btfsc PORTB,0x04
		goto inter
		bcf INTCON,0x01
		swapf temp_s,w
		movwf STATUS
		swapf temp,w
		retfie

main:
	bsf	INTCON,0x07			;Globel interrupt enable(we are using interr.)
	bsf INTCON,0x04			;RB0 enabled as external interrupt
	bsf INTCON,0x03			;RB4-RB7 interrupt on change is enabled/ in other words these pins will also work as
							;interrupts and interrupt will occur every time any of these pin changes state
							; i.e.:HIGH to LOW or LOW to HIGH, we can not set it to be on eather one state change  		
	bcf	INTCON,0x01			;Clear RB0 interuupt flag, in case it is set so 
							; that another interrupt can occur
	bcf INTCON, 0x00		;Clear RB4-RB7 interrupt flag so, that another interr. can occur.
;**********************************SET UP THE PORTS *****************
	bsf	STATUS,RP0			;switch to BANK 1
	movlw b'00010001'	
	movwf TRISB				;set RB0 & RB4 as input
	movlw b'00000000'
	movwf TRISA				;setPORT A all output
	bcf OPTION_REG,0x07		; enable weak pull ups on port b/ pull ups mean internal resistors
	bsf OPTION_REG,0x06		;interuupt on rising age/this is by defoult set
	bcf STATUS,RP0			;back to BANK  0
	movlw 0x07				;turn comparators off, so HIGH will be simple
							; HIGH rather than +5V (compared to supply) so with the LOW
	movwf CMCON				

Loop:

	movlw b'00000001'		
	movwf PORTA				;set pin 0 of port a HIGH
	goto Loop
	END

What I want to do is to light LED # 1 and when interr. occur LED # 1 turns off and LED # 2 lights up and these remains so until interr. presents, it did work with RB0 but not working with RB4-7. Please help me.


EDIT: IN CKT DIAGRAM IGNORE THAT IT RB0, TAKE IT AS RB4
 

Attachments

  • PIC1.jpg
    PIC1.jpg
    16.5 KB · Views: 238
Last edited:
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top