PIC running too fast?

Status
Not open for further replies.

bananasiong

New Member
Hi,
I'm using PIC16F628A for displaying the LCD clock. I've just started and I'm using timer2 interrupt for counting the real time. I've set the interrupt rate to be 40 ms. So I need to count for 25 times to get 1 second accurate.
Postscale 10
Prescale 16
4 MHz crystal = 1 us per instruction
PR2 249
So, 10 * 16 * 250 * 1 us = 40 ms
When I turn on the power, the clock is running, faster than as expected which is almost 2 to 3 times faster.
This is the code I have:
Code:
	LIST	P=16F628A
#include <P16F628A.inc>
ERRORLEVEL	0,	-302
__config	0x3101

cblock	0x20
count
count1
counta
countb
templcd
CountL1
CountL2
count1sec
HourTen
HourOne
MinTen
MinOne
SecTen
SecOne

L1C0                 ;line1, column 0, and so on..
L1C1
L1C2
L1C3
L1C4
L1C5
L1C6
L1C7
L1C8
L1C9
L1C10
L1C11
L1C12
L1C13
L1C14
L1C15

L2C0
L2C1
L2C2
L2C3
L2C4
L2C5
L2C6
L2C7
L2C8
L2C9
L2C10
L2C11
L2C12
L2C13
L2C14
L2C15

w_temp
s_temp
p_temp

endc

LCD_PORT	Equ	PORTA
LCD_TRIS	Equ	TRISA
LCD_RS		Equ	0x04			;LCD handshake lines
LCD_E		Equ	0x00

org	0x0000
goto	Initialize

org	0x0004

Interrupt
movwf   w_temp
swapf   STATUS,   w
clrf	STATUS
movwf   s_temp
movf	PCLATH,   w
movwf   p_temp
clrf	PCLATH

Check1sec
decf	count1sec,	f
btfss	STATUS,	Z                 ;interrupt happens 25 times?
goto	Display                      ;if no display with the same value
movlw	d'25'                         ;if yes count for 1 second
movwf	count1sec

StartCount
movf	SecOne,	w
xorlw	d'9'
btfss	STATUS,	Z
goto	ISO
goto	ReSO

ISO
incf	SecOne,	f
goto	CValue

ReSO
clrf	SecOne
movf	SecTen,	w
xorlw	d'5'
btfss	STATUS,	Z
goto	IST
goto	ReST

IST
incf	SecTen,	f
goto	CValue

ReST
clrf	SecTen
movf	MinOne,	w
xorlw	d'9'
btfss	STATUS,	Z
goto	IMO
goto	ReMO

IMO
incf	MinOne,	f
goto	CValue

ReMO
clrf	MinOne
movf	MinTen,	w
xorlw	d'5'
btfss	STATUS,	Z
goto	IMT
goto	ReMT

IMT
incf	MinTen,	f
goto	CValue

ReMT
clrf	MinTen
movf	HourTen,	w
btfss	STATUS,	Z
goto	CHO
movf	HourOne,	w
xorlw	d'9'
btfss	STATUS,	Z
goto	IHO
goto	ReHO

IHO
incf	HourOne,	f
goto	CValue

ReHO
clrf	HourOne
incf	HourTen,	f
goto	CValue

CHO
movf	HourOne,	w
xorlw	d'2'
btfss	STATUS,	Z
goto	IHO
clrf	HourOne
decf	HourOne,	f
goto	CValue

CValue
movf	HourTen,	w
movwf	L2C4
movf	HourOne,	w
movwf	L2C5
movlw	0x0A
movwf	L2C6
movf	MinTen,	w
movwf	L2C7
movf	MinOne,	w
movwf	L2C8
movlw	0x0A
movwf	L2C9
movf	SecTen,	w
movwf	L2C10
movf	SecOne,	w
movwf	L2C11

Display
movf	CountL2,	w
xorlw	d'12'
btfsc	STATUS,	Z
call	RestoreCL2
movf	CountL2,	w
call	LCD_Line2
movf	INDF,	w
call	ILCD_Char
incf	CountL2,	f
incf	FSR
call	LCD_Line1
goto	Int_Re

RestoreCL2
movlw	d'4'
movwf	CountL2
movlw	L2C4
movwf	FSR
return

ILCD_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 0
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 0
call	Pulse_e			;Pulse the E line high
call	Delay5
return

ILCD_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	Delay5
return

Int_Re
movf	p_temp,   w
movwf   PCLATH
swapf   s_temp,   w
movwf   STATUS
swapf   w_temp,   f
swapf   w_temp,   w
retfie

Initialize
movlw	0x07
movwf	CMCON
bsf	STATUS,	RP0		;bank1
movlw	0x00
movwf	TRISA
movwf	TRISB
bcf	STATUS,	RP0		;bank0
call	Delay100

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	0x0C			;Set display on and cursor off
call	LCD_Cmd
call	LCD_Clr			;clear display

clrf	PORTA
movlw	d'25'		;interrupt for 25 times = 1 second
movwf	count1sec
movlw	d'4'
movwf	CountL2

movlw	HourTen
movwf	FSR
NEXT
clrf	INDF
movf	FSR,	w
xorlw	L2C15
btfsc	STATUS,	Z
goto	$+3 incf FSR, f goto NEXT movlw L2C4 movwf FSR movlw 0x0A movwf L2C6 movwf L2C9 movlw b'01001111' ;postscale 10, prescale 16, tmr2 on movwf T2CON bsf STATUS, RP0 movlw d'249' ;1 us x 10 x 16 x 250 = 40 ms interrupt rate movwf PR2 bsf PIE1, TMR2IE bcf STATUS, RP0 bsf INTCON, PEIE bsf INTCON, GIE Start ;main program here . . LCD_Line1 movlw 0x80 ;move to 1st row, first column call LCD_Cmd return LCD_Line2 addlw 0xc0 ;move to 2nd row, first column call LCD_Cmd 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 (4 MHz clock) goto d0 Delay4 movlw 0x04 goto d0 d0 movwf count1 d1 movlw 0xC7 ;delay 1mS movwf counta movlw 0x01 movwf countb Delay_0 decfsz counta, f goto$+2
decfsz	countb, f
goto	Delay_0

decfsz	count1	,f
goto	d1
return

Pulse_e		bsf	PORTB, LCD_E
nop
bcf	PORTB, LCD_E
return

LCD_Clr		movlw	0x01			;Clear display
call	LCD_Cmd
return

end

Besides, I've found that the content of the general purpose registers are not zero as default. I thought that they are I have to clear them in initialize.

Thanks

mcs51mc

Member
Can you complement an output pin at each interrupt?
Place a scope on that pin and check if you really have 40ms.
That way you are sure about your timer setting.
If you have 40 ms the problem is your code and since I don't know PIC I can't help you further

Pommie

Well-Known Member
You are not clearing the interrupt flag. Try inserting bcf PIR1,TMR2IF in your ISR.

Mike.

ericgibbs

Well-Known Member
hi,
There seems to be labelling error, LCD_ and ILCD , which is it?

If I correct this error and run it thru PIC sim, I get 'stack under flow' error

Also in MPLAB IDE the program keeps dropping thru the ISR and keeps on re-initialising, thats probably why its running fast.

Also as Mike says, Try inserting bcf PIR1,TMR2IF in your ISR.

Pommie

Well-Known Member
ericgibbs said:
hi,
There seems to be labelling error, LCD_ and ILCD , which is it?

If I correct this error and run it thru PIC sim, I get 'stack under flow' error

Also in MPLAB IDE the program keeps dropping thru the ISR and keeps on re-initialising, thats probably why its running fast.

Also as Mike says, Try inserting bcf PIR1,TMR2IF in your ISR.

Just looked again at the code and the stack underflow is caused by the lack of code where there is a comment saying ";main program here". The OP needs to put a line after the comment something like,
Code:
hang     goto   hang

I can't see why it would drop through the ISR. It is messy though having subroutines embedded inside the ISR code.

Mike.

ericgibbs

Well-Known Member
hi mike,
>>
I can't see why it would drop through the ISR. It is messy though having subroutines embedded inside the ISR code.

I agree its messy, the drop thru 'seemed' to happen in simulation.

One point IIRC, he refreshes the display even when there is no change in the data?..
Some of the delays in the LCD write module I'm sure total out to more that his 40mSec Intr???

Hope he reworks the code and re-posts, like to see run OK.
Regards

Nigel Goodwin

Super Moderator
It all seems a bit confused?, calling subroutines within an interrupt routine isn't a good idea, and you should really keep ISR's as short and fast as possible - it's a seriously bad idea to have the display routines called from with in an ISR.

I've posted timer2 clock code (with alarm as well) in this forum a couple of times in the past - my ISR routine updates the clock registers and NOTHING else. The display is updated in the main routine, this is by far the best way to do it!.

Speakerguy

Active Member
ditto what Nigel said. Keep interrupts as simple as possible, deal with only what you absolutely have to deal with and process everything else in the main program. This is one of the things they really hammer home in embedded systems courses in college.

bananasiong

New Member
Pommie said:
You are not clearing the interrupt flag. Try inserting bcf PIR1,TMR2IF in your ISR.

Mike.
Yes, by referring to the codes of my previous program, I missed out this part. After adding it, it runs as expected.

I know that it isn't a good idea especially calling a delay routine in the ISR. I have just started and this is my first program on LCD. If the display routine is not in the same as where the clock register is updated, when there is any changes to the clock register, and at the same time, the program is not running in the display routine (delay routine maybe), then the clock will not be updated correctly.

Nigel Goodwin

Super Moderator
You simply update the clock in the main program, either check to see if the seconds counter has changed, and if so then update the clock. Or, even simpler, set a flag in the interrupt routine every time the seconds are incremented - the main routine checks this flag, and updates when it's set - it then resets the flag ready for the next time. Any other operations (such as adjusting the clock) are also done in the same main loop, something like this:

Code:
Main:
Call Check_Flag             ;check flag, update display if required
Call Check_Keys            ;check if any keys pressed, and service them
Call Check_Alarm           ;check if alarm should be triggered
Call Check_Anythingelse ;whatever you need to do
Goto Main

bananasiong

New Member
Oh... seems I'm starting from the wrong direction. I will post up once I finish modifying the program.

Thanks all

Status
Not open for further replies.

Replies
4
Views
3K
Replies
24
Views
2K
Replies
3
Views
2K
Replies
0
Views
3K
Replies
4
Views
1K