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.

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
		addlw	0x30
		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
Most Helpful Member
You are not clearing the interrupt flag. Try inserting bcf PIR1,TMR2IF in your ISR.

Mike.
 

ericgibbs

Well-Known Member
Most Helpful 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
Most Helpful 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
Most Helpful 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
Most Helpful Member
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
Most Helpful Member
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 :D
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Top