Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

Help me with a code for PIC16F87A pulse counter design

Status
Not open for further replies.

HeiFelix

Member level 1
Joined
Apr 1, 2004
Messages
32
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,286
Activity points
357
Pulse Counter

I am useing PIC16F87A to detect the frequncy change on RA4 by counting the input pulse of TMR0. The frequency is around 80KHz depending on the sensor and the OSC is 8MHz. In every 160ms, the number of pulses is 0x36B5 or 0x36B6 which means the frequency is stable.
I want to detect one or two more pulses in this period as quick as possible. So, I set FIFO to record the number of the pulse in 16(X10ms) consectutive periods. In the end of each period, I get the sum of FIFO and compare it with the standard. I believe in this way I can detect the change in 10ms. But, I the sum of last 160ms is fluctuated from 0x36B3-0x36B6 which means that I can not get a standard to check. Some pulse should be lost when I record it. How can I get the expected sum as 0x35B5 or 0x35B6 in such 16X10ms period? The code is as following:
Code:
..........

;;;;;;;;;;;;;;;;;; Interrupt Service ;;;;;;;;;;;;;;;;;;;;;
IntService
	movwf	W_Temp
	swapf	w,STATUS_Temp				
	movwf	STATUS_Temp
	bcf	STATUS,RP0
	btfsc	INTCON,T0IF
	call	IntServiceTimer0				
	swapf	STATUS_Temp,w				
	movwf	STATUS
	swapf	W_Temp,f					
	swapf	W_Temp,w
	retfie

;;;;;;;;;;;;;;;;;; Interrupt Service for Timer0 ;;;;;;;;;;;;;;;;;;;;;
IntServiceTimer0
	bcf	INTCON,T0IF
	incf	TMR0_High,f	
	return

;;;;;;;;; Main Program;;;;;;;;
Mainline
	call	InitialPIC
	call	InitialDetector
	movlw	CounterLength
	movwf	CounterCounter
MainLoop
	btfss	PIR1,TMR2IF	          :10ms overfloe	
	goto	MainLoop
	bcf	PIR1,TMR2IF
	movf	TMR0,w
	clrf	TMR0
	movwf	TMR0_TempL				
	movf	TMR0_High,w				
	movwf	TMR0_TempH				
	clrf	TMR0_High
  ............ use TMR0_TempL and TMR0_TempH to get the sum in 16x10ms period .......
  ............. detect the change of frequncy and do certain operation .........	
	goto	MainLoop
Thanks!
 

Re: Pulse Counter

maybe your interupt service needs called from somewhere
by adding gosub IntService
instead of call but i also see no call to this routine
so it will run one time then not again so if there is no interupt it will do as the result you get???
:roll:

**broken link removed**

here is a realy good expo of interupt routines
and how to call them
 

Re: Pulse Counter

The Interrupt Service is called for TMR0 interrupt. TMR0 is an 8-bit register and the it may overflow during the 10ms period. The TMR0 and TMR2 are initailized in InitialDetector.
 

Re: Pulse Counter

You're trying to detect a change of about 1/16000, or 0.006%! I hope you're using a high-stability, low-tempco or oven-controlled 8MHz crystal because that's 60ppm change you're trying to detect, and a cheap crystal has 100ppm or worse stability.

You will have to read the counter without stopping it; you can't lose a single count.

The reason you lose counts is that you're resetting the counter; however, it will continue counting perfectly happily if you don't reset it, but instead of starting it at 0 you remember the 16-bit value at the start of the period and subtract it from the 16-bit value at the end of the period.

It looks like you've got the counter in 8-bit mode with the wrapover 255->0 causing the interrupt; does it have a 16-bit mode? (in 16-bit mode you won't need the interrupt routine, you just let the counter count input pulses.

Whichever mode, you'll have to do something like this:

// initialisation
startcount = 0
tmr0_low = 0; tmr0_high = 0
...
// every 10ms:
// read the counter, trying repeatedly until the low counter hasn't changed while reading the low and high bytes (will retry only very occasionally)
do {
countlow = tmr0_low
counthigh = tmr0_high
} until countlow == tmr0_low // reread the low byte to check it hasn't changed while reading the low then high byte
// work out the increments in this period
thiscount = ((counthigh<<8)|countlow)-startcount
// save the counter value used to subtract at the end of the next period
startcount = ((counthigh<<8)|countlow)
...use thiscount

You'll probably have to make sure that the first reading is discarded, i.e. until startcount is correctly tracking the count at the start of the 10ms periods.

Even when the counter isn't losing counts, the accuracy of the 10ms sampling of the counter is critical; it must be read very precisely, with jitter much less than one period of the 80kHz rate you're sampling, i.e. much less than 12.5us. You can't have *any* interrupts running which might together (in the worst case) take longer than 5-6us to execute.

Good luck!

HTH
Barny
 

Re: Pulse Counter

Barny451:
Yes, I am trying to detect a change of about 2/16000. The circuit make the frequency quite stable. I've test that with the crystal of 20ppm, The counter seems stable with 1 pulse difference of in 160ms period because the low-to-high transition just cut in or leg out from the beginning of the period.
You are absolutely right that the lose of some pulse by resetting and interrupt service. The first reading is discarded by going after some loops until startcount is correctly tracking the count at the start of the 10ms periods.
The only 16-bit timer is TIMER1 which I've used for other purpose. But without 16bit timer, there is no way to avoid interrupt. I surpose that the interrup service take same period of timer unless the Timer0 interrup and Timer2 overflow at the same time which is seldom happen.
Anyway, thank you your good idea! Is there any other suggestion? There is similar product which works at RA4 and quite stable and I must try to follow it.

Thanks
 

Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top