Electronic Projects, forums and more.

Go Back   Electronic Circuits Projects Diagrams Free > Electronics Categories > Micro Controllers


Micro Controllers Discuss all aspects of micro controllers - building them, coding them, etc. All controllers are welcome - PIC, BASIC, Z8 Encore!, etc.

Reply
 
Thread Tools Display Modes
Old 5th January 2006, 02:41 PM   (permalink)
Default PIC16F628A Reset?

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..)
marting is offline   Reply With Quote
Old 5th January 2006, 02:48 PM   (permalink)
Default

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?.
__________________
PIC programmer software, and PIC Tutorials at:
http://www.winpicprog.co.uk
Nigel Goodwin is offline   Reply With Quote
Old 5th January 2006, 02:58 PM   (permalink)
Default

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 is offline   Reply With Quote
Old 5th January 2006, 03:08 PM   (permalink)
Default

Quote:
Originally Posted by marting
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.

Quote:

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?.
__________________
PIC programmer software, and PIC Tutorials at:
http://www.winpicprog.co.uk
Nigel Goodwin is offline   Reply With Quote
Old 5th January 2006, 05:37 PM   (permalink)
Default

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 is offline   Reply With Quote
Old 5th January 2006, 06:07 PM   (permalink)
Default

Quote:
Originally Posted by marting
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)

Quote:

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!.
__________________
PIC programmer software, and PIC Tutorials at:
http://www.winpicprog.co.uk
Nigel Goodwin is offline   Reply With Quote
Old 5th January 2006, 06:13 PM   (permalink)
Default

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
marting is offline   Reply With Quote
Old 5th January 2006, 06:52 PM   (permalink)
Default

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''
__________________
PIC programmer software, and PIC Tutorials at:
http://www.winpicprog.co.uk
Nigel Goodwin is offline   Reply With Quote
Old 5th January 2006, 08:55 PM   (permalink)
Default

Ok. nice one. I will have a look at it.. but that probably still doesn't explain the resets..
marting is offline   Reply With Quote
Old 5th January 2006, 08:59 PM   (permalink)
Default

Quote:
Originally Posted by marting
Ok. nice one. I will have a look at it.. but that probably still doesn't explain the resets..
No!, I'm afraid not.
__________________
PIC programmer software, and PIC Tutorials at:
http://www.winpicprog.co.uk
Nigel Goodwin is offline   Reply With Quote
Old 5th January 2006, 10:16 PM   (permalink)
Default

Quote:
Originally Posted by marting
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.
Pommie is online now   Reply With Quote
Old 5th January 2006, 10:55 PM   (permalink)
Default

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 is online now   Reply With Quote
Old 6th January 2006, 07:55 AM   (permalink)
Default

Quote:
Originally Posted by Pommie
Quote:
Originally Posted by marting
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!.
__________________
PIC programmer software, and PIC Tutorials at:
http://www.winpicprog.co.uk
Nigel Goodwin is offline   Reply With Quote
Old 6th January 2006, 08:41 AM   (permalink)
akg
Default

Quote:
Code:
					
	BCF	STATUS,RP0    <<<<<<<<-------------------------

	RETFIE
could u explain why ?? we shouldn't BCF inside an ISR
akg is offline   Reply With Quote
Old 6th January 2006, 10:48 AM   (permalink)
Default

Quote:
Originally Posted by akg
Quote:
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.
__________________
PIC programmer software, and PIC Tutorials at:
http://www.winpicprog.co.uk
Nigel Goodwin is offline   Reply With Quote
Reply

Bookmarks

Thread Tools
Display Modes




All times are GMT. The time now is 11:00 AM.


Electronic Circuits  |  Electronics Wiki
Powered by vBulletin® Version 3.7.0
Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.