PDA

View Full Version : CCP Module How to ?



capitano
- 25th January 2005, 16:53
I have a problem with CCP module, i must to measure a period from 1ms to 5 ms.
This is my program using CCP interrupt but it don't work fine. Can you help me please
Thank you in advance.



DEFINE OSC 20



T1CON=%00000000
CCP1CON=%00000000

Speed var word

state var bit


TMR1L=0 ' Reset Timer
TMR1H=0 ' Remember Timer is OFF
pir1.2=0 ' Reset Capture Flag
pir1.0=0
CCP1CON = %00000101





' Interrupt


INTCON = %11000000 'Global interrup enable -
PIE1=%00101111
ON INTERRUPT GoTo interr



mainloop:

GoTo mainloop




'Gestione di Interrupt

Disable

interr:





'************************************
'Interrupt Speed

If pir1.2=1 then

If state=0 then

T1CON.0=1 ' Enable Timer
pir1.2=0 ' Reset Capture Flag
state =1


else

Speed.lowbyte = CCPR1L
Speed.highbyte = CCPR1H
' Store the captured value in period variable
T1CON.0=0 ' Timer is OFF
CCP1CON=0 ' Capture is OFF
TMR1L=0 ' Reset Timer
TMR1H=0 ' Remember Timer is OFF
pir1.2=0 ' Reset Capture Flag
CCP1CON = %00000100
state=0

endif





endif


Resume
Enable

mister_e
- 25th January 2005, 23:53
I've never give a try with CCP module but...

Are you going to measure external pulses ??!?!?

Have a look to T1CON.1=1 for external clock
Case T1CON.1=0 internal clock (fosc/4)=5MHZ

In this case timer will overflow (1/5MHZ)*65536=13.1 msec

Darrel Taylor
- 30th January 2005, 01:01
Hi capitano,

Could be a simple problem.

You're starting off with the Capture triggering on the rising edge, and State = 0
CCP1CON = %00000101

On the first interrupt, it starts the timer and changes the State to 1. But I think at this point you also need to change the capture mode to trigger on the Falling edge.
CCP1CON = %00000100

On the next time through the interrupt, take the reading, clear the timer and State, then set it to trigger on the Rising edge again.

This would measure a HIGH pulse. To measure the LOW pulse just reverse the Rising/Falling edges.

Something like this:
interr:
'************************************
'Interrupt Speed

If pir1.2=1 then
If state=0 then
T1CON.0=1 ' Enable Timer
CCP1CON = %00000100 ' Next trigger is Falling edge
pir1.2=0 ' Reset Capture Flag
state =1
else
Speed.lowbyte = CCPR1L
Speed.highbyte = CCPR1H
' Store the captured value in period variable
T1CON.0=0 ' Timer is OFF
CCP1CON=0 ' Capture is OFF
TMR1L=0 ' Reset Timer
TMR1H=0 ' Remember Timer is OFF
pir1.2=0 ' Reset Capture Flag
CCP1CON = %00000101 ' Next trigger is Rising edge
state=0
endif
endif
ResumeHTH,
   Darrel

atomski
- 7th February 2005, 07:40
Darrel, guys,

Could you take a look at this thread:

http://www.picbasic.co.uk/forum/showthread.php?s=&threadid=695&highlight=CAPTURE

and tell me if using the CCP module as you have described
above could cure some of my headaches ;) Thanks!

Darrel Taylor
- 8th February 2005, 07:54
atomski,

The example given above uses PBP's ON INTERRUPT GOTO type of interrupts. Since the exact time that the interrupt is serviced is not known, it's not a good choice for timing both high and low pulses consecutively.

However, it can be done relatively easily with ASM using 1 of 2 possible methods.

1. CCP module in CAPTURE mode using Timer1 and CCPIF interrupt.

2. INT external interrupt using Timer1.

The first thing to point out here is that both methods use Timer1. So, the question is, Which one do you want to use. Do you use the INT pin and save the CCP module for something else? Or, use the CCP module and save the RB0 (INT) pin?

The second thing to mention is that these interrupts will interfere with any "Software Timed commands" like SEROUT, PULSOUT/IN, and most importantly FREQOUT. I say that because you had mentioned in the other thread that the chip would also be using FREQOUT. The degree to which it affects those commands is dependant on the time it takes to process the interrupt. Trying to capture and decode your pulse stream in real time might take enough time to make the problem noticable. But that's just a guess at this point.

The idea is pretty much the same for both techniques.

On each interrupt, immediately save the values in TMR1H:TMR1L, and then reset TMR1. Now at this point, simply change the "Edge" that causes an interrupt. For INT it's OPTION.6 (16F628). The first time through will give a Bad value. Then on the next interrupt is does the same thing, but this time the value will correspond to the last pulse width. Since you are just looking for the widths of either high or low pulses, theres no need to keep track of which one it actually was.

Actually decoding the stream will only take a few subtractions to determine if it's a START, 0 or 1. Shift the results through a register and you should have it. Also, if Timer1 overflows. it's either in-between bytes, or an error. It should scrap any bits that have already come in and wait for the next Start bit.

The only diference when using the CCP module is that you'll get the value from CCPR1H:CCPR1L instead of TMR1H:TMR1L. And, the "Edge" selection for the CCP module is CCP1CON = %101 (rising) and CCP1CON = %100 for falling edge.

-------------

It may or may not be apparent from that, but when measuring both high and low pulses consecutively, the CCP module doesn't really do anything for you. With only one exeption, it frees up RB0. Well, OK it does do one other thing. It introduces a small error, equal to the time it takes to enter the interrupt and reset the timer.

If you don't need RB0, I would suggest using option 2.

HTH,
   Darrel

atomski
- 8th February 2005, 08:08
Ok Darrel,

Thanks for the clarification. I thought pretty much along the
same tracks, however to be honest I wasn't sure 100%. I'll
post my code later on today, so you'll be able to see what's
bothering me for the past several weeks. Bare in mind that
I'm not an expert in PBP, but I manage.

TTYL