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.

PIC16F628A Reset?

Status
Not open for further replies.

marting

New Member
Hi,

I have strange issue with a 16F628A. Its running a LCD display with a clock on it, and for some reason after a few days (time varies) it does a reset. I know this, because when I change the time, I store it in EEPROM, so after a reset, it reads the stored time..

Anyone an idea why this could be.. I've tried running it with MPASM debuger for over a day or two, but i got no errors..

Its powered by a small (400mA transformer) dc circuit with a 2200uf capicitor before a 7805..

I also tried another PIC, but same problem. Could it be caused by powerdips in the 230v? (would surprise me, because the capicitor is quite large..)
 
Obviously it could be many things, with the most probable being a bug in your program?, if your program runs past the end of used memory it will count right through back to the reset vector and run from the beginning.

What reset circuit are you using?, if any at all?.
 
Hi nigel,

I thought about a bug in the program, thats why I left it running for a few days with MPASM.. no luck there..

the program is rather large though, its about 1.3Kb (thats why I had to use a 628a, for the 2K memory). It does the same loops every time, updating display, checking timers, and so on.. no strange stuff after 2 days orso..

But again, I am afraid there is a bug, but how can one debug this when something is happening randomly..;)

And with reset circuit? you mean a 3k3 to 5v and a switch to grnd at the MCRLE pin?
 
marting said:
But again, I am afraid there is a bug, but how can one debug this when something is happening randomly..;)

With GREAT difficulty!.

Are you using interrupts at all?, that adds a much greater chance of random problems.

And with reset circuit? you mean a 3k3 to 5v and a switch to grnd at the MCRLE pin?

Yes, try setting it for internal reset instead, and see what happens then?.
 
Yes I am using interrupts. TMR0 interrupt for the clock.

And I am using your LCD routines (including the conversion routines).

I am not clear with what you mean as an internal reset? do you mean set the config MLCRE_OFF?
 
marting said:
Yes I am using interrupts. TMR0 interrupt for the clock.

TMR0 is the lowest spec, poorest, timer a PIC has, the 16F628 has far better timers you can use, personally I usually use TMR2 for a clock.

Do you call any subroutines within your interrupt routine, this is generally a BAD thing - a PIC has only very limited stack space, so if your main program is a few subroutines down and an interrupt is called, the interrupt subroutines could cause the stack to overflow - this ISN'T a good thing to happen 8)

And I am using your LCD routines (including the conversion routines).

I am not clear with what you mean as an internal reset? do you mean set the config MLCRE_OFF?

Yes, it then uses an internal reset circuit - obviously you can't use a reset button though!.
 
Yes, understand the reset thing, I can try it..

And no I am absolute not jumping from within the ISR ! I learned that leason long ago..;)

Any chance you have an example for TMR2 interrupt for a accurate clock.
I've searched a long while before I found the TMR0 in assembly.

below is the Interrupt routine, for your information


Code:
;==========================================================================
;
;       INTERUPT ROUTINE STARTS HERE
;
;==========================================================================
	
	ORG	0X04
	
	MOVWF	SAVE_W			; SAVE W REGISTER
	SWAPF	STATUS,W		; SWAP STATUS TO BE SAVED INTO W
	MOVWF	SAVE_S			; SAVE STATUS REGISTER
	SWAPF	PCLATH,W
	MOVWF	SAVE_P			; SAVE PCLATH 



	TSTF	BRES_MID		; FIRST TEST FOR MID==0
	SKPNZ				; NZ = NO UNDERFLOW NEEDED
	DECF	BRES_HI,F		; Z, SO IS UNDERFLOW, SO DEC THE MSB

	DECFSZ	BRES_MID,F		; DEC THE MID BYTE (SUBTRACT 256)
					; NOW THE FULL 24BIT OPTIMISED SUBTRACT IS DONE!
					; THIS IS ABOUT 4 TIMES FASTER THAN A "PROPER"
					; 24BIT SUBTRACT.

	GOTO	INT_EXIT		; NZ, SO DEFINITELY NOT ONE SECOND YET.
					; IN MOST CASES THE ENTIRE 'FAKE" INT TAKES
					; ONLY 9 INSTRUCTIONS.
					;------------------------
					; * TEST IF WE HAVE REACHED ONE SECOND.
					; ONLY GETS HERE WHEN MID==0, IT MAY BE ONE SECOND.
					; ONLY GETS TO HERE 1 IN EVERY 256 TIMES.
					; (THIS IS OUR BEST OPTIMISED TEST)
					; IT GETS HERE WHEN BRES_MID ==0.

	TSTF	BRES_HI			; TEST HI FOR ZERO TOO
	SKPZ				; Z = BOTH HI AND MID ARE ZERO, IS ONE SECOND!
	GOTO 	INT_EXIT		; NZ, SO NOT ONE SECOND YET.

					;-------------------------------------------------
					; ONLY GETS TO HERE IF WE HAVE REACHED ONE SECOND.
	
					; NOW WE CAN GENERATE OUR ONE SECOND EVENT, LIKE ADD
					; ONE SECOND TO OUR CLOCK OR WHATEVER.
					; (IN THIS EXAMPLE WE TOGGLE A LED)
		
					; THE OTHER THING WE NEED TO DO IS ADD 1,000,000 COUNTS
					; TO OUR 24BIT VARIABLE AND START ALL OVER AGAIN.
					;-------------------------------------------------
					; ADD THE 1,000,000 COUNTS FIRST.
					; ONE SECOND = 1,000,000 = 0F 42 40 (IN HEX)
					; AS WE KNOW HI==0 AND MID==0 THIS MAKES IT VERY FAST.
					; THIS IS AN OPTIMISED 24BIT ADD, BECAUSE WE CAN
					; JUST LOAD THE TOP TWO BYTES AND ONLY NEED TO DO
					; A REAL ADD ON THE BOTTOM BYTE. THIS IS MUCH QUICKER
					; THAN A "PROPER" 24BIT ADD.

	MOVLW 	0X0F			; GET MSB VALUE -> 0x0F
	MOVWF 	BRES_HI			; LOAD IN MSB

	MOVLW 	0X42			; GET MID VALUE -> 0x42
	MOVWF 	BRES_MID		; LOAD IN MID (0X82 FOR INTERNAL CLOCK)

	MOVLW 	0X40			; LSB VALUE TO ADD -> 0x40
	ADDWF 	BRES_LOW,F		; ADD IT TO THE REMAINDER ALREADY IN LSB
	SKPNC				; NC = NO OVERFLOW, SO MID IS STILL OK

	INCF 	BRES_MID,F		; C, SO LSB OVERFLOWED, SO INC MID
					; THIS IS OPTIMISED AND RELIES ON MID BEING KNOWN
					; AND THAT MID WON'T OVERFLOW FROM ONE INC.

					; THAT'S IT! OUR OPTIMISED 24BIT ADD IS DONE,
					; THIS IS ROUGHLY TWICE AS QUICK AS A "PROPER"
					; 24BIT ADD.
					;-------------------------
					; NOW WE DO THE "EVENT" THAT WE DO EVERY ONE SECOND.
					; NOTE! FOR THIS EXAMPLE WE TOGGLE A LED, WHICH
					; WILL GIVE A FLASHING LED WHICH IS ON FOR A SECOND
					; AND OFF FOR A SECOND.
					; ADD YOUR OWN CODE HERE FOR YOUR ONE SECOND EVENT.
	
					; ADD 1 SEC AND UPDATE THE TIME
TIME_UPDATE
	MOVLW	0X01
	XORWF	SECINT,1		; TOGGLE THE SECOND UPDATE

	MOVLW	0X01			; ADD ONE SECOND
	ADDWF	SECOND,F
	MOVLW	0X3C			; PASSED 60 SEC?
	SUBWF	SECOND,0		
	BTFSS	STATUS,0
	GOTO	T_END

ADDMIN
	INCF	TIMEOUT,F
	MOVLW	0X00
	MOVWF	SECOND			; SECONDS TO ZERO
	MOVLW	0X01			; ADD 1 MIN
	ADDWF	MINUTE,F
	MOVLW	0X3C			; PASSED 60 MIN?
	SUBWF	MINUTE,0
	BTFSS	STATUS,0
	GOTO	T_END

ADDHOUR

	MOVLW	0X00			; MINUTE TO ZERO
	MOVWF	MINUTE			; ADD 1 HOUR
	MOVLW	0X01			
	ADDWF	HOUR,F
	MOVLW	0X18			; PASSED 23 HRS?
	SUBWF	HOUR,W
	BTFSS	STATUS,0
	GOTO	T_END

	MOVLW	0X00			; HOURS TO ZERO
	MOVWF	HOUR

T_END						
					; END OF TIME UPDATE 

					;-------------------------------------------------
					; NOW OUR ONE SECOND EVENT IS ALL DONE, WE CAN EXIT THE
					; INTERRUPT HANDLER.
					;-------------------------------------------------
					; FINALLY WE RESTORE W AND STATUS REGISTERS.
					; ALSO CLEARS TMRO INT FLAG NOW WE ARE FINISHED.
INT_EXIT

	BCF	INTCON,2
	
	SWAPF	SAVE_P,W
	MOVWF	PCLATH			; RESTORE PCLATH
	SWAPF	SAVE_S,W	
	MOVWF	STATUS			; RESTORE STATUS REGISTER - RESTORES BANK
	SWAPF	SAVE_W,F
	SWAPF	SAVE_W,W		; RESTORE W REGISTER
					
	BCF	STATUS,RP0

	RETFIE
 
OK on the no-subroutines in interrupt routines :lol:

Here's some code for a clock I was playing with a while back, this is actually 20MHz code for a 16F876 - it was originally for a 4MHz 628, and I simply added a five count to the interrupt routine rather than changing the timing, so removing that will revert to 4MHz (the original 628 code isn't to hand at the moment - it's on a different hard drive, which isn't connected).

Code:
; Generate interrupts every 10mS, display count of hours, minutes, seconds, and hundreths.

	LIST	p=16F876		;tell assembler what chip we are using
	include "P16F876.inc"		;include the defaults for the chip
	ERRORLEVEL	0,	-302	;suppress bank selection messages
	__CONFIG    0x393A		;sets the configuration settings (oscillator type etc.)



;***** VARIABLE DEFINITIONS

        cblock 0x20             ; define a series of variables.
		w_temp		; variable used for context saving 
                status_temp	; variable used for context saving
		Hours		; hours counter
		Mins            ; minutes counter
                Secs            ; seconds counter
		MSecs		; 10's of millisconds counter
                count0          ; Interrupt counter
                flagsecs        ; Contains a 0 unless 500 1-ms Timer 2
                                ; interrupts have been processed.
		flag10s		; ten second flag
		flag60s		; sixty second flag
		HoursA		; alarm hours register
		MinsA           ; alarm minutes register
                SecsA           ; alarm seconds register
		count		;used in looping routines
		count1		;used in delay routine
		counta		;used in delay routine
		countb		;used in delay routine
		tmp1		;temporary storage
		tmp2
		templcd		;temp store for 4 bit mode
		templcd2

        	NumL		;Binary inputs for decimal convert routine
	        NumH	

        	TenK		;Decimal outputs from convert routine
	        Thou	
        	Hund	
	        Tens	
        	Ones
		MaxDigit1
		MaxDigit2
        endc

; Bits within PORTA
ToggleBit       equ     1       ; An output bit, toggled every 500 ms.
TenSecBit	equ	2
MinuteBit	equ	4
PortAMask       equ     B'00000000' ;  We'll make all of PORT A an output.

LCD_PORT	Equ	PORTB	;LCD on PortB
LCD_TRIS	Equ	TRISB
LCD_RS		Equ	0x04	;LCD handshake lines
LCD_RW		Equ	0x06
LCD_E		Equ	0x07
SW_PORT		Equ	PORTC
SW_TRIS		Equ	TRISC
LED1		Equ	0x00
LED2		Equ	0x01
LED3		Equ	0x02
LED4		Equ	0x03
BUT1		Equ	0x04
BUT2		Equ	0x05
BUT3		Equ	0x06
BUT4		Equ	0x07

;**********************************************************************
                ORG     0x000             ; processor reset vector
                clrf    PCLATH            ; ensure page 0 is used
                goto    main              ; go to beginning of program


                ORG     0x004           ; interrupt vector location
                movwf   w_temp          ; save off current W register contents
                swapf   STATUS,W        ; move status register into W register
                clrf    STATUS          ; select Bank 0
                movwf   status_temp     ; save off contents of STATUS register
                                        ; There's no need to save PCLATH since
                                        ; we'll stick to Bank 0 of program memory.

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


                btfsc   PIR1,TMR2IF     ; If Timer 2 caused the interrupt, handle it.
                call    Timer2


                swapf   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

; *********************************************
;       Timer 2 Interrupt handler.
;       Timer 2 has overflowed
;
Timer2

        incf    count0,F	; increment interrupt counter
        movlw   d'5'          	; Is count0 5 yet?
        subwf   count0,W
        btfss   STATUS,Z        ; If count0 is not 5, end ISR.
        goto    EndTimer2Interrupt
; Reinitialize count0
        clrf    count0

        incf    MSecs,F		; increment milli second counter
        movlw   d'100'          ; Is MSecs 100 yet?
        subwf   MSecs,W
        btfss   STATUS,Z        ; If MSecs is not 100, end ISR.
        goto    EndTimer2Interrupt
        movlw   H'FF'
        movwf   flagsecs
; Reinitialize Secs
        clrf    MSecs

        incf    Secs,F		; increment 10 second counter
        movlw   d'60'           ; Is Secs 60 yet?
        subwf   Secs,W
        btfss   STATUS,Z        ; If Secs is not 60, end ISR.
        goto    EndTimer2Interrupt
        movlw   H'FF'
        movwf   flag10s
; Reinitialize Secs
        clrf    Secs

        incf    Mins,F		; increment 60 second counter
        movlw   d'60'           ; Is Mins 60 yet?
        subwf   Mins,W
        btfss   STATUS,Z        ; If Mins is not 60, end ISR.
        goto    EndTimer2Interrupt
        movlw   H'FF'
        movwf   flag60s
; Reinitialize Mins
        clrf    Mins

        incf    Hours,F		; increment hour counter
        movlw   d'24'           ; Is Mins 24 yet?
        subwf   Hours,W
        btfss   STATUS,Z        ; If Hours is not 24, end ISR.
        goto    EndTimer2Interrupt
        movlw   H'FF'
        movwf   flag60s
; Reinitialize Hours
        clrf    Hours		; reset hours to zero

EndTimer2Interrupt

        bcf PIR1,TMR2IF 	; Clear flag and continue.
        return

; HEX conversion table for LCD routines.

HEX_Table  	ADDWF   PCL       , f
            	RETLW   0x30
            	RETLW   0x31
            	RETLW   0x32
            	RETLW   0x33
            	RETLW   0x34
            	RETLW   0x35
            	RETLW   0x36
            	RETLW   0x37
            	RETLW   0x38
            	RETLW   0x39
            	RETLW   0x41
            	RETLW   0x42
            	RETLW   0x43
            	RETLW   0x44
            	RETLW   0x45
            	RETLW   0x46

main
; ***********************************************************************************
; START OF CODE to initialize the processor
; The initialization code goes here since we'll end up here shortly after a reset.
; ***********************************************************************************

; ***********************************************************************************
; Most Bank 0 initializations are done here and they come first.
; ***********************************************************************************

        bcf     STATUS,RP0      ; Select Bank 0
        bcf     STATUS,RP1

	BANKSEL ADCON1		;disable A2D for 16F876/7
    	movlw   0x06
    	movwf   ADCON1
    	BANKSEL PORTA

        clrf    PORTA           ; Initialize Port A by clearing the output latches.

        clrf    count0
	clrf	MSecs
        clrf    Secs
        clrf    Mins
	clrf	Hours

        clrf    flagsecs       ; Turn off the flag which, when set, says 500 ms has elapsed.
	clrf    flag10s
	clrf    flag60s
	
	clrf	HoursA		;clear alarm registers
        clrf    SecsA
        clrf    MinsA

; ***********************************************************************************
; Most Bank 1 initializations come next.
; ***********************************************************************************

        bsf     STATUS,RP0      ; Select Bank 1

        movlw   PortAMask       ; Initialize direction pins for Port A using TRISA.
        movwf   TRISA
        movlw	0xF0
        movwf	SW_TRIS		;set inputs for buttons
       	movlw	0x00		;make all LCD pins outputs
	movwf	LCD_TRIS

        bcf     STATUS,RP0      ; Revert to Bank 0
        
        movlw	b'00000000'
        movwf	SW_PORT		;clear LED's
        
        			;test alarm values
        
        movlw	0x01		;set 1 hour
        movwf	HoursA
        
        movlw	0x02
        movwf	MinsA		;set 2 minute
        
        movlw	0x1E		;set 30 seconds
        movwf	SecsA

; ***********************************************************************************
; START OF CODE to initialize Timer 2
; These come next only because it's convenient to group them together, not because
; it's a necessity.

; Set up Timer 2 to generate interrupts every 1 ms.  Since we're assuming an instruction
; cycle consumes 1 us, we need to cause an interrupt every 1000 instruction cycles.
; We'll set the prescaler to 4, the PR2 register to 25, and the postscaler to 10.  This
; will generate interrupts every 4 x 25 x 10 = 1000 instruction cycles.  
; ***********************************************************************************

        clrf    TMR2            ; Clear Timer2 register

        bsf     STATUS, RP0     ; Bank1
        bsf     INTCON,PEIE     ; Enable peripheral interrupts
        clrf    PIE1            ; Mask all peripheral interrupts except
        bsf     PIE1,TMR2IE     ; the timer 2 interrupts.
        bcf     STATUS, RP0     ; Bank0

        clrf    PIR1            ; Clear peripheral interrupts Flags
        movlw   B'01001001'     ; Set Postscale = 10, Prescale = 4, Timer 2 = off.
        movwf   T2CON

        bsf     STATUS, RP0     ; Bank1
        movlw   D'250'-1         ; Set the PR2 register for Timer 2 to divide by 250.
        movwf   PR2
        bcf     STATUS, RP0     ; Bank0

        bsf     INTCON,GIE      ; Global interrupt enable.
        bsf     T2CON,TMR2ON    ; Timer2 starts to increment

; ***********************************************************************************
; END OF CODE to initialize Timer 2
; ***********************************************************************************

	call	LCD_Init		;setup LCD

; ***********************************************************************************
; main()
; This is the main program.  It does only one thing:  check to see if it's time to
; toggle PORTA<togglebit> and do so if it is time.  Otherwise it's busily engaged
; in using up all the instruction cycles not required by the interrupt handlers.

loop
        call	Check_Keys
        movf    flagsecs, W     ; Has the flagsecs been set?
        btfsc   STATUS,Z
        goto    loop            ; Not yet.  Keep looking.
        
        call	Check_Alarm	; check alarm every LCD update

	call	LCD_Line1

	movlw	'T'
	call	LCD_Char
	movlw	'i'
	call	LCD_Char
	movlw	'm'
	call	LCD_Char
	movlw	'e'
	call	LCD_Char
	movlw	' '
	call	LCD_Char
	movlw	' '
	call	LCD_Char

	movf	Hours,	w
	movwf	NumL
	call	Display
	movlw	':'
	call	LCD_Char
	movf	Mins,	w
	movwf	NumL
	call	Display
	movlw	':'
	call	LCD_Char
	movf	Secs,	w
	movwf	NumL
	call	Display
	movlw	' '
	call	LCD_Char
	
	call	LCD_Line2
	
	movlw	'A'
	call	LCD_Char
	movlw	'l'
	call	LCD_Char
	movlw	'a'
	call	LCD_Char
	movlw	'r'
	call	LCD_Char
	movlw	'm'
	call	LCD_Char
	movlw	' '
	call	LCD_Char
	
	movf	HoursA,	w
	movwf	NumL
	call	Display
	movlw	':'
	call	LCD_Char
	movf	MinsA,	w
	movwf	NumL
	call	Display
	movlw	':'
	call	LCD_Char
	movf	SecsA,	w
	movwf	NumL
	call	Display
	movlw	' '
	call	LCD_Char

        goto loop               ; Now wait for the next occurence.

; ***********************************************************************************

Check_Keys
		btfss	SW_PORT, BUT1
		goto	Clear_Clk
		btfss	SW_PORT, BUT2
		bcf     T2CON,TMR2ON    ; stop Timer2
		btfss	SW_PORT, BUT3
		bsf     T2CON,TMR2ON    ; start Timer2
		btfss	SW_PORT, BUT4
		goto	Edit_Hours
		return

Edit_Hours
		movlw	0x07		;set cursor position
		call	LCD_Line2W
		call	LCD_CurOn
		movlw	d'24'
		movwf	MaxDigit1
		movlw	d'23'
		movwf	MaxDigit2
Butt_Loop	btfss	SW_PORT, BUT2
		call	Increment
		btfss	SW_PORT, BUT3
		call	Decrement
		btfsc	SW_PORT, BUT1	;exit routine
		goto	Butt_Loop
		goto	Edit_Mins

Increment	incf	HoursA, f	; increment HoursA
        	movf   	MaxDigit1, w    ; Is Hours 24 yet?
        	subwf   HoursA,W
        	btfss   STATUS,Z        ; If Hours is not 24, carry on
        	goto    $+3
		movlw	0x00		; else zero hours
		movwf	HoursA
		movlw	0x06		; set cursor position
		call	LCD_Line2W
		movf	HoursA, w
		movf	HoursA,	w
		movwf	NumL
		call	Display
		movlw	0x07		; set cursor position
		call	LCD_Line2W
		call	Delay255
		return

Decrement	decf	HoursA, f	; increment HoursA
		movlw   d'255'          ; Is hours 255 yet?
        	subwf   HoursA,W
        	btfss   STATUS,Z        ; If Hours is not 255, carry on
        	goto    $+3
		movf	MaxDigit2, w	; else hours = 23
		movwf	HoursA
		movlw	0x06		; set cursor position
		call	LCD_Line2W
		movf	HoursA, w
		movf	HoursA,	w
		movwf	NumL
		call	Display
		movlw	0x07		; set cursor position
		call	LCD_Line2W	
		call	Delay255
		return

Edit_Mins
		call	Delay255	;delay for contact bounce
		btfss	SW_PORT, BUT1	;exit routine
		goto	$-1		;loop until button released		
		movlw	0x0A		;set cursor position
		call	LCD_Line2W
		call	LCD_CurOn
		movlw	d'60'
		movwf	MaxDigit1
		movlw	d'59'
		movwf	MaxDigit2
Butt_Loop2	btfss	SW_PORT, BUT2
		call	IncrementM
		btfss	SW_PORT, BUT3
		call	DecrementM
		btfsc	SW_PORT, BUT1	;exit routine
		goto	Butt_Loop2
		goto	Edit_Secs

IncrementM	incf	MinsA, f	; increment MinssA
        	movf   	MaxDigit1, w    ; Is MinsA 60 yet?
        	subwf   MinsA,W
        	btfss   STATUS,Z        ; If MinsA is not 60, carry on
        	goto    $+3
		movlw	0x00		; else zero MinsA
		movwf	MinsA
		movlw	0x09		; set cursor position
		call	LCD_Line2W
		movf	MinsA, w
		movf	MinsA,	w
		movwf	NumL
		call	Display
		movlw	0x0A		; set cursor position
		call	LCD_Line2W
		call	Delay255
		return

DecrementM	decf	MinsA, f	; increment MinsA
		movlw   d'255'          ; Is MinsA 255 yet?
        	subwf   MinsA,W
        	btfss   STATUS,Z        ; If MinsA is not 255, carry on
        	goto    $+3
		movf	MaxDigit2, w	; else MinsA = 59
		movwf	MinsA
		movlw	0x09		; set cursor position
		call	LCD_Line2W
		movf	MinsA, w
		movf	MinsA,	w
		movwf	NumL
		call	Display
		movlw	0x0A		; set cursor position
		call	LCD_Line2W
		call	Delay255
		return

Edit_Secs
		call	Delay255	;delay for contact bounce
		btfss	SW_PORT, BUT1	;exit routine
		goto	$-1		;loop until button released		
		movlw	0x0D		;set cursor position
		call	LCD_Line2W
		call	LCD_CurOn
		movlw	d'60'
		movwf	MaxDigit1
		movlw	d'59'
		movwf	MaxDigit2
Butt_Loop3	btfss	SW_PORT, BUT2
		call	IncrementS
		btfss	SW_PORT, BUT3
		call	DecrementS
		btfsc	SW_PORT, BUT1	;exit routine
		goto	Butt_Loop3
		call	Delay255	;delay for contact bounce
		btfss	SW_PORT, BUT1	;exit routine
		goto	$-1		;loop until button released
		return

IncrementS	incf	SecsA, f	; increment SecsA
        	movf   	MaxDigit1, w    ; Is SecsA 60 yet?
        	subwf   SecsA,W
        	btfss   STATUS,Z        ; If SecsA is not 60, carry on
        	goto    $+3
		movlw	0x00		; else zero SecsA
		movwf	SecsA
		movlw	0x0C		; set cursor position
		call	LCD_Line2W
		movf	SecsA, w
		movf	SecsA,	w
		movwf	NumL
		call	Display
		movlw	0x0D		; set cursor position
		call	LCD_Line2W
		call	Delay255
		return

DecrementS	decf	SecsA, f	; decrement SecsA
		movlw   d'255'          ; Is SecsA 255 yet?
        	subwf   SecsA,W
        	btfss   STATUS,Z        ; If SecsA is not 255, carry on
        	goto    $+3
		movf	MaxDigit2, w	; else SecsA = 59
		movwf	SecsA
		movlw	0x0C		; set cursor position
		call	LCD_Line2W
		movf	SecsA, w
		movf	SecsA,	w
		movwf	NumL
		call	Display
		movlw	0x0D		; set cursor position
		call	LCD_Line2W
		call	Delay255
		return

Clear_Clk
		bcf     T2CON,TMR2ON    ; stop Timer2
		clrf	Hours
		clrf	Mins
		clrf	Secs
		clrf	MSecs
		clrf	count0
		clrf    flagsecs
		clrf    flag10s
		clrf    flag60s
		clrf	SW_PORT		; turn off and LED's
		bsf     T2CON,TMR2ON    ; start Timer2
		return	
		
Check_Alarm
		movf	Hours, w	;check hours
		subwf	HoursA, w
		btfss	STATUS, Z
		return	
		movf	Mins, w		;check minutes
		subwf	MinsA, w
		btfss	STATUS, Z
		return	
		movf	Secs, w		;check seconds
		subwf	SecsA, w
		btfsc	STATUS, Z
		bsf	SW_PORT, LED1
		return			

Display		clrf	NumH
		call	Convert			;convert to decimal		
		movf	Tens,	w
		call	LCD_CharD
		movf	Ones,	w
		call	LCD_CharD
		return

;LCD routines

;Initialise LCD
LCD_Init	call 	LCD_Busy		;wait for LCD to settle

		movlw	0x20			;Set 4 bit mode
		call	LCD_Cmd

		movlw	0x28			;Set display shift
		call	LCD_Cmd

		movlw	0x06			;Set display character mode
		call	LCD_Cmd

		movlw	0x0c			;Set display on/off and cursor command
		call	LCD_Cmd			;Set cursor off

		call	LCD_Clr			;clear display

		retlw	0x00

; command set routine
LCD_Cmd		movwf	templcd
		swapf	templcd,	w	;send upper nibble
		andlw	0x0f			;clear upper 4 bits of W
		movwf	LCD_PORT
		bcf	LCD_PORT, LCD_RS	;RS line to 1
		call	Pulse_e			;Pulse the E line high

		movf	templcd,	w	;send lower nibble
		andlw	0x0f			;clear upper 4 bits of W
		movwf	LCD_PORT
		bcf	LCD_PORT, LCD_RS	;RS line to 1
		call	Pulse_e			;Pulse the E line high
		call 	LCD_Busy
		retlw	0x00

LCD_CharD	addlw	0x30			;add 0x30 to convert to ASCII
LCD_Char	movwf	templcd
		swapf	templcd,	w	;send upper nibble
		andlw	0x0f			;clear upper 4 bits of W
		movwf	LCD_PORT
		bsf	LCD_PORT, LCD_RS	;RS line to 1
		call	Pulse_e			;Pulse the E line high

		movf	templcd,	w	;send lower nibble
		andlw	0x0f			;clear upper 4 bits of W
		movwf	LCD_PORT
		bsf	LCD_PORT, LCD_RS	;RS line to 1
		call	Pulse_e			;Pulse the E line high
		call 	LCD_Busy
		retlw	0x00

LCD_Line1	movlw	0x80			;move to 1st row, first column
		call	LCD_Cmd
		retlw	0x00

LCD_Line2	movlw	0xc0			;move to 2nd row, first column
		call	LCD_Cmd
		retlw	0x00

LCD_Line1W	addlw	0x80			;move to 1st row, column W
		call	LCD_Cmd
		retlw	0x00

LCD_Line2W	addlw	0xc0			;move to 2nd row, column W
		call	LCD_Cmd
		retlw	0x00

LCD_CurOn	movlw	0x0d			;Set display on/off and cursor command
		call	LCD_Cmd
		retlw	0x00

LCD_CurOff	movlw	0x0c			;Set display on/off and cursor command
		call	LCD_Cmd
		retlw	0x00

LCD_Clr		movlw	0x01			;Clear display
		call	LCD_Cmd
		retlw	0x00

LCD_HEX		movwf	tmp1
		swapf	tmp1,	w
		andlw	0x0f
		call	HEX_Table
		call	LCD_Char
		movf	tmp1, w
		andlw	0x0f
		call	HEX_Table
		call	LCD_Char
		retlw	0x00

Pulse_e		bsf	LCD_PORT, LCD_E
		nop
		bcf	LCD_PORT, LCD_E
		retlw	0x00

LCD_Busy
		bsf	STATUS,	RP0		;set bank 1
		movlw	0x0f			;set Port for input
		movwf	LCD_TRIS
		bcf	STATUS,	RP0		;set bank 0
		bcf	LCD_PORT, LCD_RS	;set LCD for command mode
		bsf	LCD_PORT, LCD_RW	;setup to read busy flag
		bsf	LCD_PORT, LCD_E
		swapf	LCD_PORT, w		;read upper nibble (busy flag)
		bcf	LCD_PORT, LCD_E		
		movwf	templcd2 
		bsf	LCD_PORT, LCD_E		;dummy read of lower nibble
		bcf	LCD_PORT, LCD_E
		btfsc	templcd2, 7		;check busy flag, high = busy
		goto	LCD_Busy		;if busy check again
		bcf	LCD_PORT, LCD_RW
		bsf	STATUS,	RP0		;set bank 1
		movlw	0x00			;set Port for output
		movwf	LCD_TRIS
		bcf	STATUS,	RP0		;set bank 0
		return

Delay255	movlw	0xff		;delay 255 mS
		goto	d0
Delay100	movlw	d'100'		;delay 100mS
		goto	d0
Delay50		movlw	d'50'		;delay 50mS
		goto	d0
Delay20		movlw	d'20'		;delay 20mS
		goto	d0
Delay5		movlw	0x05		;delay 5.000 ms (20 MHz clock)
d0		movwf	count1
d1		movlw	0xE7		;delay 1mS
		movwf	counta
		movlw	0x04
		movwf	countb
Delay_0
		decfsz	counta, f
		goto	$+2
		decfsz	countb, f
		goto	Delay_0

		decfsz	count1	,f
		goto	d1
		retlw	0x00

;end of LCD routines

Convert:                        ; Takes number in NumH:NumL
                                ; Returns decimal in
                                ; TenK:Thou:Hund:Tens:Ones
        swapf   NumH, w
	iorlw	B'11110000'
        movwf   Thou
        addwf   Thou,f
        addlw   0XE2
        movwf   Hund
        addlw   0X32
        movwf   Ones

        movf    NumH,w
        andlw   0X0F
        addwf   Hund,f
        addwf   Hund,f
        addwf   Ones,f
        addlw   0XE9
        movwf   Tens
        addwf   Tens,f
        addwf   Tens,f

        swapf   NumL,w
        andlw   0X0F
        addwf   Tens,f
        addwf   Ones,f

        rlf     Tens,f
        rlf     Ones,f
        comf    Ones,f
        rlf     Ones,f

        movf    NumL,w
        andlw   0X0F
        addwf   Ones,f
        rlf     Thou,f

        movlw   0X07
        movwf   TenK

                    ; At this point, the original number is
                    ; equal to
                    ; TenK*10000+Thou*1000+Hund*100+Tens*10+Ones
                    ; if those entities are regarded as two's
                    ; complement binary.  To be precise, all of
                    ; them are negative except TenK.  Now the number
                    ; needs to be normalized, but this can all be
                    ; done with simple byte arithmetic.

        movlw   0X0A                             ; Ten
Lb1:
        addwf   Ones,f
        decf    Tens,f
        btfss   3,0
        goto   Lb1
Lb2:
        addwf   Tens,f
        decf    Hund,f
        btfss   3,0
        goto   Lb2
Lb3:
        addwf   Hund,f
        decf    Thou,f
        btfss   3,0
        goto   Lb3
Lb4:
        addwf   Thou,f
        decf    TenK,f
        btfss   3,0
        goto   Lb4

        retlw	0x00



                END                       ; directive 'end of program''
 
marting said:
Code:
	SWAPF	SAVE_P,W
	MOVWF	PCLATH			; RESTORE PCLATH
	SWAPF	SAVE_S,W	
	MOVWF	STATUS			; RESTORE STATUS REGISTER - RESTORES BANK
	SWAPF	SAVE_W,F
	SWAPF	SAVE_W,W		; RESTORE W REGISTER
					
	BCF	STATUS,RP0    <<<<<<<<-------------------------

	RETFIE

I think the highlighted instruction may be your problem. This will cause a random crash as you describe. Just delete it unless there is a reason you have it there.

Mike.
 
Also,
A simple way to generate accurate timing is to use the special events trigger.

This sets up timer 1 and the special events trigger so that an interrupt occurs 100 times per second (with a 4Meg clock).
With 100Hz interrupts your counter can be 8 bit and so greatly simplifies your code.

The interrupt thats generated is NOT the timer1 one but the CCP1 interrupt.

Code:
                movlw   B'00000001'
                movwf   T1CON;          enable timer 1
                movlw   low(10000-1);   Lets interupt every 1/100th of a second
                movwf   CCPR1L;         using the special event trigger on timer 1
                movlw   high(10000-1)
                movwf   CCPR1H
                movlw   B'00001011';    enable special event trigger on CCP1
                movwf   CCP1CON;	
                bsf     STATUS,RP0
                bsf     PIE1,CCP1IE;    enable CCP1 interupt
                bcf     STATUS,RP0
                movlw   0C0h
                movwf   INTCON;         enable Peripheral interupts

In your ISR, you need to reset the CCP1 interrupt flag.
I.E.
Code:
                bcf     PIR1,CCP1IF;   reset special event trigger interupt

If your using a higher crystal then change to 10,000 to how often you want the interupt. In this case 4Meg = 1Meg instructions. 1,000,000/100 = 10,000.

HTH

Mike.
 
Pommie said:
marting said:
Code:
	SWAPF	SAVE_P,W
	MOVWF	PCLATH			; RESTORE PCLATH
	SWAPF	SAVE_S,W	
	MOVWF	STATUS			; RESTORE STATUS REGISTER - RESTORES BANK
	SWAPF	SAVE_W,F
	SWAPF	SAVE_W,W		; RESTORE W REGISTER
					
	BCF	STATUS,RP0    <<<<<<<<-------------------------

	RETFIE

I think the highlighted instruction may be your problem. This will cause a random crash as you describe. Just delete it unless there is a reason you have it there.

Mike.

Well spotted Mike, it's certainly a VERY bad idea to have that there!.
 
akg said:
Code:
	BCF	STATUS,RP0    <<<<<<<<-------------------------

	RETFIE

could u explain why ?? we shouldn't BCF inside an ISR

Because at the start of the ISR you save the STATUS register (because it must be EXACTLY as it was before the ISR was called), and at the exit you restore the STATUS register. This line changes the STATUS register AFTER it's been restored.

So you can use BCF inside an ISR, but NOT to alter a register that must not be changed.
 
Pommie/Nigel,

Jast was about to ask that.. I will remove it and leave it running for a while.

Thanks for all the input!
 
Nigel Goodwin said:
Because at the start of the ISR you save the STATUS register (because it must be EXACTLY as it was before the ISR was called), and at the exit you restore the STATUS register. This line changes the STATUS register AFTER it's been restored.
So you can use BCF inside an ISR, but NOT to alter a register that must not be changed.
Thanks Nigel
 
delay on time

hello
I have made same changes to the code that nigel have post.
My LCD is in portA
But every 4 second it have a delay of 1 second aproximatly...
Could anyone explain me why?
the code is below:

LIST p=16F628 ;tell assembler what chip we are using
include "P16F628.inc" ;include the defaults for the chip
ERRORLEVEL 0, -302 ;suppress bank selection messages
__config 0x0118 ;sets the configuration settings (oscillator type etc.)



;***** VARIABLE DEFINITIONS

cblock 0x20 ; define a series of variables.
w_temp ; variable used for context saving
status_temp ; variable used for context saving
Hours ; hours counter
Mins ; minutes counter
Secs ; seconds counter
MSecs ; 10's of millisconds counter
count0 ; Interrupt counter
flagsecs ; Contains a 0 unless 500 1-ms Timer 2
; interrupts have been processed.
flag10s ; ten second flag
flag60s ; sixty second flag
HoursA ; alarm hours register
MinsA ; alarm minutes register
SecsA ; alarm seconds register
count ;used in looping routines
count1 ;used in delay routine
counta ;used in delay routine
countb ;used in delay routine
tmp1 ;temporary storage
tmp2
templcd ;temp store for 4 bit mode
templcd2

NumL ;Binary inputs for decimal convert routine
NumH

TenK ;Decimal outputs from convert routine
Thou
Hund
Tens
Ones
MaxDigit1
MaxDigit2
endc

ORG 0x00 ; processor reset vector
clrf PCLATH ; ensure page 0 is used
goto main ; go to beginning of program


ORG 0x04 ; interrupt vector location
movwf w_temp ; save off current W register contents
swapf STATUS,W ; move status register into W register
clrf STATUS ; select Bank 0
movwf status_temp ; save off contents of STATUS register
; There's no need to save PCLATH since
; we'll stick to Bank 0 of program memory.

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


btfsc PIR1,TMR2IF ; If Timer 2 caused the interrupt, handle it.
call Timer2


swapf 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

; *********************************************
; Timer 2 Interrupt handler.
; Timer 2 has overflowed
;
Timer2

incf MSecs,F ; increment milli second counter
movlw d'100' ; Is MSecs 100 yet?
subwf MSecs,W
btfss STATUS,Z ; If MSecs is not 100, end ISR.
goto EndTimer2Interrupt
movlw H'FF'
movwf flagsecs
; Reinitialize Secs
clrf MSecs

incf Secs,F ; increment 10 second counter
movlw d'60' ; Is Secs 60 yet?
subwf Secs,W
btfss STATUS,Z ; If Secs is not 60, end ISR.
goto EndTimer2Interrupt
movlw H'FF'
movwf flag10s
; Reinitialize Secs
clrf Secs

incf Mins,F ; increment 60 second counter
movlw d'60' ; Is Mins 60 yet?
subwf Mins,W
btfss STATUS,Z ; If Mins is not 60, end ISR.
goto EndTimer2Interrupt
movlw H'FF'
movwf flag60s
; Reinitialize Mins
clrf Mins

incf Hours,F ; increment hour counter
movlw d'24' ; Is Mins 24 yet?
subwf Hours,W
btfss STATUS,Z ; If Hours is not 24, end ISR.
goto EndTimer2Interrupt
movlw H'FF'
movwf flag60s
; Reinitialize Hours
clrf Hours ; reset hours to zero

EndTimer2Interrupt

bcf PIR1,TMR2IF ; Clear flag and continue.
return

main
; ***********************************************************************************
; START OF CODE to initialize the processor
; The initialization code goes here since we'll end up here shortly after a reset.
; ***********************************************************************************
SetPorts
bsf STATUS, RP0 ;select bank 1
movlw b'00010000'
movwf TRISA ;all pins outputs
movlw b'00001111'
movwf TRISB ;B0-B3 IN B4-B7 Out
movlw b'11111000' ; 1:1 TMR0, counter, falling edge RA4.
movwf OPTION_REG
movlw b'00000000' ; disable interrupts.
movwf INTCON
movlw b'00000000' ; disable TMR1 overflow interrupt.
movwf PIE1
bcf STATUS, RP0 ;select bank 0

movlw b'00000111'
movwf CMCON ;turn comparators off

clrf PORTA
clrf PORTB

clrf count0
clrf MSecs
clrf Secs
clrf Mins
clrf Hours

clrf flagsecs ; Turn off the flag which, when set, says 500 ms has elapsed.
clrf flag10s
clrf flag60s

movlw 0x01 ;set 1 hour
movwf HoursA

movlw 0x02
movwf MinsA ;set 2 minute

movlw 0x1E ;set 30 seconds
movwf SecsA

; ***********************************************************************************
; START OF CODE to initialize Timer 2
; These come next only because it's convenient to group them together, not because
; it's a necessity.

; Set up Timer 2 to generate interrupts every 1 ms. Since we're assuming an instruction
; cycle consumes 1 us, we need to cause an interrupt every 1000 instruction cycles.
; We'll set the prescaler to 4, the PR2 register to 25, and the postscaler to 10. This
; will generate interrupts every 4 x 25 x 10 = 1000 instruction cycles.
; ***********************************************************************************

clrf TMR2 ; Clear Timer2 register

bsf STATUS, RP0 ; Bank1
bsf INTCON,PEIE ; Enable peripheral interrupts
clrf PIE1 ; Mask all peripheral interrupts except
bsf PIE1,TMR2IE ; the timer 2 interrupts.
bcf STATUS, RP0 ; Bank0

clrf PIR1 ; Clear peripheral interrupts Flags
movlw B'01001001' ; Set Postscale = 10, Prescale = 4, Timer 2 = off.
movwf T2CON

bsf STATUS, RP0 ; Bank1
movlw D'250' ; Set the PR2 register for Timer 2 to divide by 250.
movwf PR2
bcf STATUS, RP0 ; Bank0

bsf INTCON,GIE ; Global interrupt enable.
bsf T2CON,TMR2ON ; Timer2 starts to increment

; ***********************************************************************************
; END OF CODE to initialize Timer 2
; ***********************************************************************************

call Delay100 ;wait for LCD to settle
call LCD_Init ;setup LCD

; ***********************************************************************************
; main()
; This is the main program. It does only one thing: check to see if it's time to
; toggle PORTA<togglebit> and do so if it is time. Otherwise it's busily engaged
; in using up all the instruction cycles not required by the interrupt handlers.

loop
call Check_Keys
movf flagsecs, W ; Has the flagsecs been set?
btfsc STATUS,Z
goto loop ; Not yet. Keep looking.

call Check_Alarm ; check alarm every LCD update

call LCD_Line1

movlw ' '
call LCD_Char
movlw 'H'
call LCD_Char
movlw 'o'
call LCD_Char
movlw 'r'
call LCD_Char
movlw 'a'
call LCD_Char
movlw ' '
call LCD_Char

movf Hours, w
movwf NumL
call Display
movlw ':'
call LCD_Char
movf Mins, w
movwf NumL
call Display
movlw ':'
call LCD_Char
movf Secs, w
movwf NumL
call Display
movlw ' '
call LCD_Char

call LCD_Line2

movlw 'A'
call LCD_Char
movlw 'l'
call LCD_Char
movlw 'a'
call LCD_Char
movlw 'r'
call LCD_Char
movlw 'm'
call LCD_Char
movlw ' '
call LCD_Char

movf HoursA, w
movwf NumL
call Display
movlw ':'
call LCD_Char
movf MinsA, w
movwf NumL
call Display
movlw ':'
call LCD_Char
movf SecsA, w
movwf NumL
call Display
movlw ' '
call LCD_Char

goto loop ; Now wait for the next occurence.

; ***********************************************************************************

Check_Keys
btfss PORTB, 0
goto Clear_Clk
btfss PORTB, 1
bcf T2CON,TMR2ON ; stop Timer2
btfss PORTB, 2
bsf T2CON,TMR2ON ; start Timer2
btfss PORTB, 3
goto Edit_Hours
return


Edit_Hours
movlw 0x07 ;set cursor position
call LCD_Line2W
call LCD_CurOn
movlw d'24'
movwf MaxDigit1
movlw d'23'
movwf MaxDigit2
Butt_Loop
btfss PORTB, 1
call Increment
btfss PORTB, 2
call Decrement
btfsc PORTB, 0 ;exit routine
goto Butt_Loop
goto Edit_Mins
Increment
incf HoursA, f ; increment HoursA
movf MaxDigit1, w ; Is Hours 24 yet?
subwf HoursA,W
btfss STATUS,Z ; If Hours is not 24, carry on
goto $+3
movlw 0x00 ; else zero hours
movwf HoursA
movlw 0x06 ; set cursor position
call LCD_Line2W
; movf HoursA, w
movf HoursA, w
movwf NumL
call Display
movlw 0x07 ; set cursor position
call LCD_Line2W
call Delay20
return
Decrement
decf HoursA, f ; increment HoursA
movlw d'255' ; Is hours 255 yet?
subwf HoursA,W
btfss STATUS,Z ; If Hours is not 255, carry on
goto $+3
movf MaxDigit2, w ; else hours = 23
movwf HoursA
movlw 0x06 ; set cursor position
call LCD_Line2W
; movf HoursA, w
movf HoursA, w
movwf NumL
call Display
movlw 0x07 ; set cursor position
call LCD_Line2W
call Delay20
return


Edit_Mins
; call Delay20 ;delay for contact bounce
btfss PORTB, 0 ;exit routine
goto $-1 ;loop until button released
movlw 0x0A ;set cursor position
call LCD_Line2W
call LCD_CurOn
movlw d'60'
movwf MaxDigit1
movlw d'59'
movwf MaxDigit2
Butt_Loop2
btfss PORTB, 1
call IncrementM
btfss PORTB, 2
call DecrementM
btfsc PORTB, 0 ;exit routine
goto Butt_Loop2
goto Edit_Secs
IncrementM
incf MinsA, f ; increment MinssA
movf MaxDigit1, w ; Is MinsA 60 yet?
subwf MinsA,W
btfss STATUS,Z ; If MinsA is not 60, carry on
goto $+3
movlw 0x00 ; else zero MinsA
movwf MinsA
movlw 0x09 ; set cursor position
call LCD_Line2W
movf MinsA, w
; movf MinsA, w
movwf NumL
call Display
movlw 0x0A ; set cursor position
call LCD_Line2W
call Delay20
return
DecrementM
decf MinsA, f ; increment MinsA
movlw d'255' ; Is MinsA 255 yet?
subwf MinsA,W
btfss STATUS,Z ; If MinsA is not 255, carry on
goto $+3
movf MaxDigit2, w ; else MinsA = 59
movwf MinsA
movlw 0x09 ; set cursor position
call LCD_Line2W
movf MinsA, w
movf MinsA, w
movwf NumL
call Display
movlw 0x0A ; set cursor position
call LCD_Line2W
call Delay20
return


Edit_Secs
; call Delay255 ;delay for contact bounce
btfss PORTB, 0 ;exit routine
goto $-1 ;loop until button released
movlw 0x0D ;set cursor position
call LCD_Line2W
call LCD_CurOn
movlw d'60'
movwf MaxDigit1
movlw d'59'
movwf MaxDigit2
Butt_Loop3
btfss PORTB, 1
call IncrementS
btfss PORTB, 2
call DecrementS
btfsc PORTB, 0 ;exit routine
goto Butt_Loop3
call Delay255 ;delay for contact bounce
btfss PORTB, 0 ;exit routine
goto $-1 ;loop until button released
return
IncrementS
incf SecsA, f ; increment SecsA
movf MaxDigit1, w ; Is SecsA 60 yet?
subwf SecsA,W
btfss STATUS,Z ; If SecsA is not 60, carry on
goto $+3
movlw 0x00 ; else zero SecsA
movwf SecsA
movlw 0x0C ; set cursor position
call LCD_Line2W
movf SecsA, w
movf SecsA, w
movwf NumL
call Display
movlw 0x0D ; set cursor position
call LCD_Line2W
call Delay20
return
DecrementS
decf SecsA, f ; decrement SecsA
movlw d'255' ; Is SecsA 255 yet?
subwf SecsA,W
btfss STATUS,Z ; If SecsA is not 255, carry on
goto $+3
movf MaxDigit2, w ; else SecsA = 59
movwf SecsA
movlw 0x0C ; set cursor position
call LCD_Line2W
movf SecsA, w
movf SecsA, w
movwf NumL
call Display
movlw 0x0D ; set cursor position
call LCD_Line2W
call Delay20
return


Clear_Clk
bcf T2CON,TMR2ON ; stop Timer2
clrf Hours
clrf Mins
clrf Secs
clrf MSecs
clrf count0
clrf flagsecs
clrf flag10s
clrf flag60s
clrf PORTB ; turn off LED B4
bsf T2CON,TMR2ON ; start Timer2
return

Check_Alarm
movf Hours, w ;check hours
subwf HoursA, w
btfss STATUS, Z
return
movf Mins, w ;check minutes
subwf MinsA, w
btfss STATUS, Z
return
movf Secs, w ;check seconds
subwf SecsA, w
btfsc STATUS, Z
bsf PORTB, 4
return

Display
clrf NumH
call Convert ;convert to decimal
movf Tens, w
call LCD_CharD
movf Ones, w
call LCD_CharD
return

;LCD routines

;Initialise LCD
LCD_Init
movlw 0x20 ;Set 4 bit mode
call LCD_Cmd
movlw 0x28 ;Set display shift
call LCD_Cmd
movlw 0x06 ;Set display character mode
call LCD_Cmd
movlw 0x0d ;Set display on/off and cursor command
call LCD_Cmd
call LCD_Clr ;clear display
retlw 0x00

; command set routine
LCD_Cmd
movwf templcd
swapf templcd, w ;send upper nibble
andlw 0x0f ;clear upper 4 bits of W
movwf PORTA
bcf PORTA, 6 ;RS line to 0
call Pulse_e ;Pulse the E line high

movf templcd, w ;send lower nibble
andlw 0x0f ;clear upper 4 bits of W
movwf PORTA
bcf PORTA, 6 ;RS line to 0
call Pulse_e ;Pulse the E line high
call Delay5
retlw 0x00

LCD_CharD
addlw 0x30
LCD_Char
movwf templcd
swapf templcd, w ;send upper nibble
andlw 0x0f ;clear upper 4 bits of W
movwf PORTA
bsf PORTA, 6 ;RS line to 1
call Pulse_e ;Pulse the E line high

movf templcd, w ;send lower nibble
andlw 0x0f ;clear upper 4 bits of W
movwf PORTA
bsf PORTA, 6 ;RS line to 1
call Pulse_e ;Pulse the E line high
call Delay5
retlw 0x00

LCD_Line1
movlw 0x80 ;move to 1st row, first column
call LCD_Cmd
retlw 0x00

LCD_Line2
movlw 0xc0 ;move to 2nd row, first column
call LCD_Cmd
retlw 0x00

LCD_Line1W
addlw 0x80 ;move to 1st row, column W
call LCD_Cmd
retlw 0x00

LCD_Line2W
addlw 0xc0 ;move to 2nd row, column W
call LCD_Cmd
retlw 0x00

LCD_CurOn
movlw 0x0d ;Set display on/off and cursor command
call LCD_Cmd
retlw 0x00

LCD_CurOff
movlw 0x0c ;Set display on/off and cursor command
call LCD_Cmd
retlw 0x00

LCD_Clr
movlw 0x01 ;Clear display
call LCD_Cmd
retlw 0x00

LCD_HEX
movwf tmp1
swapf tmp1, w
andlw 0x0f
call HEX_Table
call LCD_Char
movf tmp1, w
andlw 0x0f
call HEX_Table
call LCD_Char
retlw 0x00

Pulse_e
bsf PORTA, 7
nop
bcf PORTA, 7
retlw 0x00

HEX_Table addwf PCL, f
RETLW 0x30
RETLW 0x31
RETLW 0x32
RETLW 0x33
RETLW 0x34
RETLW 0x35
RETLW 0x36
RETLW 0x37
RETLW 0x38
RETLW 0x39
RETLW 0x41
RETLW 0x42
RETLW 0x43
RETLW 0x44
RETLW 0x45
RETLW 0x46

;end of LCD routines

Delay255 movlw 0xff ;delay 255 mS
goto d0
Delay100 movlw d'100' ;delay 100mS
goto d0
Delay50 movlw d'50' ;delay 50mS
goto d0
Delay20 movlw d'20' ;delay 20mS
goto d0
Delay5 movlw 0x05 ;delay 5.000 ms (20 MHz clock)
d0 movwf count1
d1 movlw 0xE7 ;delay 1mS
movwf counta
movlw 0x04
movwf countb
Delay_0
decfsz counta, f
goto $+2
decfsz countb, f
goto Delay_0

decfsz count1 ,f
goto d1
retlw 0x00

;end of LCD routines

Convert: ; Takes number in NumH:NumL
; Returns decimal in
; TenK:Thou:Hund:Tens:Ones
swapf NumH, w
iorlw B'11110000'
movwf Thou
addwf Thou,f
addlw 0XE2
movwf Hund
addlw 0X32
movwf Ones

movf NumH,w
andlw 0X0F
addwf Hund,f
addwf Hund,f
addwf Ones,f
addlw 0XE9
movwf Tens
addwf Tens,f
addwf Tens,f

swapf NumL,w
andlw 0X0F
addwf Tens,f
addwf Ones,f

rlf Tens,f
rlf Ones,f
comf Ones,f
rlf Ones,f

movf NumL,w
andlw 0X0F
addwf Ones,f
rlf Thou,f

movlw 0X07
movwf TenK

; At this point, the original number is
; equal to
; TenK*10000+Thou*1000+Hund*100+Tens*10+Ones
; if those entities are regarded as two's
; complement binary. To be precise, all of
; them are negative except TenK. Now the number
; needs to be normalized, but this can all be
; done with simple byte arithmetic.

movlw 0X0A ; Ten
Lb1:
addwf Ones,f
decf Tens,f
btfss 3,0
goto Lb1
Lb2:
addwf Tens,f
decf Hund,f
btfss 3,0
goto Lb2
Lb3:
addwf Hund,f
decf Thou,f
btfss 3,0
goto Lb3
Lb4:
addwf Thou,f
decf TenK,f
btfss 3,0
goto Lb4

retlw 0x00



END ; directive 'end of program''
 
Dear all,
I am very new to Pics and so much happy to learn.recently I started with pic16f628a.And when I browse internet found a code that toggles
four LEDs with four switches.each LED has it's own switch.The code works fine.

;************************************************* ***************
;* Name of Project: Experiment 4 *
;* 4 push-buttons and 4 LEDs *
;************************************************* ***************

list P = 16F628 ;microcontroller identity
; e.g: 0x033 = hex value

__Config 3F18h

;************************************************* ***************
;Equates
;************************************************* ***************
status equ 0x03
cmcon equ 0x1F
rp1 equ 0x06 ;this is bit 6 in file 03
rp0 equ 0x05 ;this is bit 5 in file 03
portA equ 0x05 ;file 5 is Port A
portB equ 0x06 ;file 6 is Port B
flags equ 0x30 ;flag file
decrA equ 0x20 ;file to decrement
decrB equ 0x21 ;file to decrement


;************************************************* ***************
;Beginning of program
;************************************************* ***************
reset: org 0x00 ;reset vector address
goto SetUp ;goto set-up
nop
nop
nop
org 4 ;interrupts go to this location
goto isr1 ;goto to Interrupt Routine - not used
;isr1 must be written at address 004
; otherwise bcf status,rp1 will be
; placed at address 01 by assembler!

;************************************************* ***************
;* Port A and B initialisation *
;************************************************* ***************

SetUp bcf status,rp1 ;select bank 1 (must be = 0)
bsf status,rp0 ; also to select bank 1

movlw 0xFF ;make all Port A inputs
movwf portA
movlw 0x0F ; out out out out in in in in
movwf portB ;

bcf status,rp0 ;select programming area - bank0
movlw 0x07 ;turn comparators off and enable
movwf cmcon ; pins for I/O functions
goto Main

;************************************************* ***************
;* Interrupt Service Routine will go here (not used) *
;************************************************* ***************
isr1

;************************************************* ***************
;Delay sub-routine - approx 130mS
;************************************************* ***************
delay movlw 0x80 ;load 80h into w
movwf decrA ;shift 80h into the file for decrementing
delx nop
decfsz decrB,1 ;decrement the file
goto delx
decfsz decrA,1 ;decrement the file
goto delx
retlw 0x00 ;return

;************************************************* ***************
;* Main *
;************************************************* ***************

Main clrf flags
MainA call delay ;1/10 second delay
btfsc portB,0 ;file06, input bit 0 = red button pushed?
goto Main1 ;Yes
btfsc portB,1 ;file06, input bit 1 = green button pushed?
goto Main2 ;Yes
btfsc portB,2 ;file06, input bit 2 = yellow button pushed?
goto Main3 ;Yes
btfsc portB,3 ;file06, input bit 3 = orange button pushed?
goto Main4 ;Yes
clrf flags ;clear flag file
goto MainA ;No. Loop again

Main1 btfsc flags,0 ;test red flag
goto MainA ;return if flag is SET
movlw 0x10 ;set the bit for the red LED
xorwf portB,1 ;put answer into file 06 to toggle LED
bsf flags,0 ;set the red flag
goto MainA

Main2 btfsc flags,1 ;test green flag
goto MainA ;return if flag is SET
movlw 0x20 ;set the bit for the green LED
xorwf portB,1 ;put answer into file 06 to toggle LED
bsf flags,1 ;set the green flag
goto MainA

Main3 btfsc flags,2 ;test yellow flag
goto MainA ;return if flag is SET
movlw 0x40 ;set the bit for the yellow LED
xorwf portB,1 ;put answer into file 06 to toggle LED
bsf flags,2 ;set the yellow flag
goto MainA

Main4 btfsc flags,3 ;test orange flag
goto MainA ;return if flag is SET
movlw 0x80 ;set the bit for the orange LED
xorwf portB,1 ;put answer into file 06 to toggle LED
bsf flags,3 ;set the orange flag
goto MainA

END

Now Can anybody to help me to devolop this code to be able to go for six LEDs with six switches with toggle action and additional switch that can be pushed onece and all out puts go zero and when again pressed all out puts go high.

randy963@yahoo.com
 
Status
Not open for further replies.

Latest threads

Back
Top