Continue to Site

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.

CCP2 Capture in PIC18F23F22

Status
Not open for further replies.

MaxHeadRoom78

Well-Known Member
Most Helpful Member
Anyone done any assembly programming with the p18f23k22 using the CCP2 module on capture mode, I get the interrupts and increment of TMR1 but no capture value in CCPR2H/L.
Max.
 
I could write a simple program in C and then look at the assembled code!!!

Its always very messy, but It may give you a hint!

That is a possibility that had crossed my mind, if you could it may help.
I am using a high priority interrupt on capture.
Max.
 
CCP2 capture using CCP2_PORTB (RB3).
TIMR1 running from SOSC0-SOSC1
First interrupt, Capture on rising edge, first edge clear and turn on TMR1, set first flag.
Second interrupt, capture TMR1 value, flag second capture, turn off CCP2 Interrupt Enable.
I attempt all this and do not get the second (TMR1) capture value, but correct value seen in TMR1 registers.
Thanks.
Max.
 
I was reluctant to post code until someone mention they had used the CCP capture using Assembly.
But this is the nuts and bolts of the capture part of the code.
Code:
;High priority interrupt routine.

HighIntCode:
        movff    FSR0H,FSR0H_SHADOW    ;save FSR0H register
        movff    FSR0L,FSR0L_SHADOW    ;save FSR0L register
        btfss    PIR2, CCP2IF    ;check CCP2 INT
        goto    NextINT
        btfsc    PIR1, TMR1IF    ;skip if TMR1 OVF
        goto    OverF
        btfsc    Flags, INTC        ;skip if first capture
        goto    Flag2    ;second capture
        clrf    TMR1H
        clrf    TMR1L
        clrf    CCPR2H
        clrf    CCPR2L
        bsf        T1CON, TMR1ON    ;Turn T1 on
        bcf        PIR1, TMR1IF    ;clr INT flag
        bsf        Flags, INTC    ;Record 1st Capture
        goto    EndHiInt2
Flag2:    ;Second int, capture value.
        btfsc    PIR1, TMR1IF    ;test if T1 OVF
        goto    OverF
        movff    CCPR2H, ACCbHI
        movff    CCPR2L, ACCbLO
        bsf        Flags, CAPT        ;indicate capture occured
        bcf        PIE2, CCP2IE    ;turn off CCP2 int
        bcf        TMR1, TMR1ON    ;turn off TMR1
        goto    EndHighInt1
NextINT:
        nop    ;Place other Hi Priority int here              
;        bra        Iserv     ;if so, go get timing pulses

;can do special error handling here - an unexpected interrupt occurred
OverF:
        bcf    Flags, INTC
        bcf    Flags, CAPT

EndHighInt1:
        bcf     PIR1,    TMR1IF    ;Clear T1 Int
        bcf        Flags, INTC
EndHiInt2:  
        bcf        PIR2, CCP2IF    ;Clr CCP2 INT  
        movff    FSR0L_SHADOW, FSR0L    ;restore FSR0L register
        movff    FSR0H_SHADOW, FSR0H    ;restore FSR0H register
        retfie    FAST            ;return and restore context

Setup:
        bcf        INTCON, GIE    ;disable global interrupts
        bcf        INTCON, PEIE    ;disable peripheral interrupts (enable for USART)
        bcf        PIE1, TMR1IE    ;disable timer 1 interrupts
        bcf        PIE2, CCP2IE    ;disable CCP2 interrupts
        bcf        PIR1, TMR1IF    ;clear TMR1 interrupt flag
        bcf        PIR2, CCP2IF    ;Clr CCP2 int Flag
        clrf    WREG
        movff    WREG, ANSELA    ;set all ports I/O
        movff    WREG, ANSELB
        movff    WREG, ANSELC
        bsf        TRISB, CCP2_PORTB    ;set CCP2 input
        movlw    0x05
        movwf    CCP2CON    ;set every rising edge cap
        clrf    CCPR2H    ;clear registers
        clrf    CCPR2L
        clrf    CCPTMRS0    ;Set for tmr 1
;        movlw      
        bsf        RCON,    IPEN ;enable priority int
;----

        clrf    Flags
;        incf    Flags
        movlw    0xbe     ;tmr1 prescaler /8 and TMR1 off,
        movwf    T1CON        ;and 32khz clk
        clrf    TMR1H    ;clear timer 1 high
        clrf    TMR1L    ;clear timer 1 low
    ;    clrf    PORTA    ;Sst PORTA for I/O
        bcf        ADCON0, 0  ;Set ADCON0 off
        movlw    0x0f
        bsf        INTCON, GIE
        bsf        PIE2, CCP2IE    ;enable CCP2 interrupts
        return
;
 
Last edited:
Code:
1:  #include <stdio.h>
2:  #include <p18f23k22.h>
3:   
4:  #pragma config WDTEN = OFF
5:  #pragma config LVP = OFF
6:  #pragma config FOSC = XT
7:   
8:  void InterruptHandlerHigh (void);
9:   
10:  void main()
11:     {
12:     
13:     TRISE = 0;
  00AC  6A96  CLRF 0xf96, ACCESS
14:     TRISB =0xff;
  00AE  6893  SETF 0xf93, ACCESS
15:     TRISC = 255;
  00B0  6894  SETF 0xf94, ACCESS
16:     PIE2bits.CCP2IE = 1;     // CCP2 interrupt on
  00B2  80A0  BSF 0xfa0, 0, ACCESS
17:     PIR2bits.CCP2IF = 0;
  00B4  90A1  BCF 0xfa1, 0, ACCESS
18:     CCPTMRS0 = 0;         // use timer 1
  00B6  010F  MOVLB 0xf
  00B8  6B49  CLRF 0x49, BANKED
19:     CCP2CON = 5;         // every rising edge
  00BA  0E05  MOVLW 0x5
  00BC  6E66  MOVWF 0xf66, ACCESS
20:     T1CONbits.T1RD16 = 1;     // 16 bit mode
  00BE  82CD  BSF 0xfcd, 0x1, ACCESS
21:     T1CONbits.TMR1ON = 1;     // timer 1
  00C0  80CD  BSF 0xfcd, 0, ACCESS
22:     PIE1bits.TMR1IE = 1;     // timer interrupt on
  00C2  809D  BSF 0xf9d, 0, ACCESS
23:     INTCONbits.PEIE = 1;
  00C4  8CF2  BSF 0xff2, 0x6, ACCESS
24:     INTCONbits.GIE = 1;       // off we go
  00C6  8EF2  BSF 0xff2, 0x7, ACCESS
25:   
26:     for(;;)
  00C8  D7FF  BRA 0xc8
27:       {
28:       }
29:     }
  00CA  0012  RETURN 0
30:   
31:  #pragma code InterruptVectorHigh = 0x08
32:   
33:  void
34:  InterruptVectorHigh (void)
35:  {
36:  _asm
37:  goto InterruptHandlerHigh //jump to interrupt routine
  0008  EF66  GOTO 0xcc
  000A  F000  NOP
38:  _endasm
39:  }
  000C  0012  RETURN 0
40:   
41:  #pragma code
42:  #pragma interrupt InterruptHandlerHigh
43:   
44:  void InterruptHandlerHigh ()
  00CC  CFDA  MOVFF 0xfda, 0xfe4
  00CE  FFE4  NOP
  00D0  CFE2  MOVFF 0xfe2, 0xfda
  00D2  FFDA  NOP
  00D4  52E6  MOVF 0xfe6, F, ACCESS
45:     {
46:     if(PIR2bits.CCP2IF)       // capture!!!
  00D6  B0A1  BTFSC 0xfa1, 0, ACCESS
47:       {
48:       PIR2bits.CCP2IF = 0;   // CCP pair are loaded
  00D8  90A1  BCF 0xfa1, 0, ACCESS
49:       }
50:     if(PIR1bits.TMR1IF)       // timer overrun!!
  00DA  B09E  BTFSC 0xf9e, 0, ACCESS
51:       {
52:       PIR1bits.TMR1IF = 0;
  00DC  909E  BCF 0xf9e, 0, ACCESS
53:       }
54:     }
  00DE  52E5  MOVF 0xfe5, F, ACCESS
  00E0  CFE5  MOVFF 0xfe5, 0xfda
  00E2  FFDA  NOP
  00E4  0011  RETFIE 0x1

Like I said... Probably is nonsensical!!

Here is the code I wrote to test!!!

C:
#include <stdio.h>
#include <p18f23k22.h>

#pragma config WDTEN = OFF
#pragma config LVP = OFF
#pragma config FOSC = XT

void InterruptHandlerHigh (void);

void main()
   {
   
   TRISE = 0;
   TRISB =0xff;
   TRISC = 255;
   PIE2bits.CCP2IE = 1;     // CCP2 interrupt on
   PIR2bits.CCP2IF = 0;
   CCPTMRS0 = 0;         // use timer 1
   CCP2CON = 5;         // every rising edge
   T1CONbits.T1RD16 = 1;     // 16 bit mode
   T1CONbits.TMR1ON = 1;     // timer 1
   PIE1bits.TMR1IE = 1;     // timer interrupt on
   INTCONbits.PEIE = 1;
   INTCONbits.GIE = 1;       // off we go

   for(;;)
     {
     }
   }

#pragma code InterruptVectorHigh = 0x08

void
InterruptVectorHigh (void)
{
  _asm
  goto InterruptHandlerHigh //jump to interrupt routine
  _endasm
}

#pragma code
#pragma interrupt InterruptHandlerHigh

void InterruptHandlerHigh ()
   {
   if(PIR2bits.CCP2IF)       // capture!!!
     {
     PIR2bits.CCP2IF = 0;   // CCP pair are loaded
     }
   if(PIR1bits.TMR1IF)       // timer overrun!!
     {
     PIR1bits.TMR1IF = 0;
     }
   }
 
I have done capture on a 12F683 both by starting and stopping TMR1 and by letting TMR1 run continuously and dealing with the arithmetic later. I much prefer the latter method. I did not use an interrupt in either case. I did monitor the interrupt flag, however. I was also triggering alternately on the rising and falling edge. In other words, I wanted to capture a full PWM cycle. I wanted to see your code to find out whether you are alternating or just capturing rising edges, which I assumed was the case from your posts. Also have same code code for a 12F1840, counting 1, 2, and multiple cycles.

Your earlier posts seemed to emphasize a need for an interrupt. I did not use an interrupt, and so felt my code might not be applicable. Now I sensed that may not be so critical to your project. Here is the relevant part of the code from the 12F683, including the arithmetic. Signal input is at GP2 (pin5).

Code:
Controller = 12F683
Oscillator = internal at 8 MHz

     bsf       T1CON,TMR1ON   ;turn TMR1 on
Start
     movlw     b'00000101'    ;
     movwf     CCP1CON        ;CCP1 rising edge capture                         |B0
      clrf        TMR1H
    clrf        TMR1L       

_Data                         ;TMR1 runs continuously                           |B0

     bcf       PIR1,CCP1IF    ;flag must be cleared after mode change           |B0
     btfss     PIR1,CCP1IF    ;test CCP1 interrupt flag (interrupt not enabled)
     goto      $-1
     movf      CCPR1H,w       ;start time high byte
     movwf     CCP_T1H        ;save value in shadow register
     movf      CCPR1L,w       ;start time low byte
     movwf     CCP_T1L        ;save value in shadow register
     bcf       CCP1CON,0      ;change interrupt flag to falling edge
     bcf       PIR1,CCP1IF    ;clear flag
     btfss     PIR1,CCP1IF    ;test CCP1 falling edge interrupt flag
     goto      $-1
     movf      CCPR1H,w       ;stop time high byte
     movwf     CCP_T2H        ;save value in shadow register
     movf      CCPR1L,w       ;stop time low byte
     movwf     CCP_T2L        ;save value in shadow register
     bsf       CCP1CON,0      ;change interrupt flag to rising edge
     bcf       PIR1,CCP1IF    ;clear flag
     call      Calc_hi        ;uncommented 01.23.14
     btfss     PIR1,CCP1IF    ;test for rising edge (end of period)
     goto      $-1
     movf      CCPR1H,w       ;start time high byte
     movwf     CCP_T3H        ;save value in shadow register
     movf      CCPR1L,w       ;start time low byte
     movwf     CCP_T3L        ;save value in shadow register
;     bcf       CCP1CON,0      ;change interrupt flag to falling edge
;     bcf       PIR1,CCP1IF    ;clear flag
;     bcf       T1CON, TMR1ON  ;stop TMR1
;     call      Calc_hi       ;commented 1.23.14 uncomment 1.24,commented
     call      Calc_tot

     goto      Start
;**************************************************************************************
;Subtraction
;Source: Rudy Wieser, PicList
;"Source" number to be subtracted
;"Dest" number to be subtracted from
;Result goes to Dest, Source is preserved, Carry is valid, Z flag is not valid
;CCP_T2L:H - CCP_T1L:H --> CCP_T2L:H = high period
;CCP_T3L:H - CCP_T1L:H --> CCP_T3L:H = total period
;**************************************************************************************

Calc_hi
     movf      CCP_T1L,w      ;SourceL,w
     subwf     CCP_T2L        ;DestL
     movf      CCP_T1H,w      ;SourceH,w
     btfss     STATUS,C       ;STATUS,0
     incfsz    CCP_T1H,w      ;SourceH,w
     subwf     CCP_T2H        ;DestH
     call      Out232H
     retlw     0
Calc_tot
     movf      CCP_T1L,w      ;SourceL,w
     subwf     CCP_T3L        ;DestL
     movf      CCP_T1H,w      ;SourceH,w
     btfss     STATUS,C
     incfsz    CCP_T1H,w      ;SourceH,w
     subwf     CCP_T3H        ;DestH
     call      Out232T                 
     retlw     0

John

Sorry about the brief screw-up. Some days I can't tell a parenthesis from a bracket.

Edit: Oops, just noticed "Call232." I am sending the results by serial at baud 9600. Call 232 is the routine for that. I have had a long day fighting groundhogs and weeds and will take a fresh look at this tomorrow early. Maybe the 12F1840 code, which is more polished, might be better help.
 
Last edited:
I will end up using multiple interrupts as I am doing a few more tasks and I don't want them held up watching an input and waiting for an input to occur.
Max.
 
Makes sense, but you still might want to consider leaving TMR1 running. You don't lose any counts that way.

John
 
Yes but the system Clk is running at 20Mhz and I am measuring per 1 rpm pulse for a motor running <6000rpm, so any error in turning TMR1 on should be inconsequential to the end result.
Also I don't have to worry about TMR1 over running, if it does, the motor is stopped or almost, which I do not have to worry about and ignore.
TMR1 is clocked by a 32Khz crystal.
Max.
 
TMR1 over running is not a problem with unsigned math. The subtraction handles it. For example, assume 30,000 (0x7530) counts per interval. Name the timings To...Tn, and of course the interval is (Tn - Tn-1). The 16-bit hex values for a series of measurements of 30,000 counts each will be: 0, 7530, EA60, 5F90 (rollover), and D4C0. If you subtract those pairs, the answer in each case is hex 7530. Of course, two rollovers in a single interval screws it up, but that would screw up a start-stop method too.

John
 
Hi Max,
I have used capture mode (Not on a PIC18 but on a PIC16F628 ) to measure RPM. Basically it measures the time of a revolution (In units of 0.4 uS) It works in the way that John describes by leaving the timer running and then calculating the difference between the last captured value and the current captured value. The 16 bit timer is extended to 32 bits in software to allow for reading very low RPM values. If the time of a revolution is less than about 0.5 seconds (120 RPM) then it waits for the next revolution after 0.5 second has elapsed and divides the elapsed time by the number of revolutions thus averaging over between 0.5 and 1 second. The source code is here. https://lesjhobbies.weebly.com/simple-tachometer-for-1-to-99-pulses-per-rev.html

Les.
 
You are using the dedicated internal 32KHz clock for TMR1 source, right?

Code:
movlw    0xbe     ;tmr1 prescaler /8 and TMR1 off,
movwf    T1CON        ;and 32khz clk

While bit 3 allows that for TMR1 operation, will it work with capture mode? The datasheet seems to say that mode must use the instruction clock or and external oscillator:

Capture.PNG


A simple test might be to set your system clock slower, say 250 KHz, use the instruction clock from that for TMR1, and test whether TMR1 counts are then transferred to the capture registers.

John
 
You are using the dedicated internal 32KHz clock for TMR1 source, right?

John

No, the TMR1 is running off of an external 32Khz crystal on SOSC0/SOSC1 the main system is running on 20Mhz crystal.
The TMR1 value is not a problem, the correct value appears at the second CCP2 interrupt, the problem is that the CCPR2H/L remain zero.
IOW, no capture of TMR1 appears to occur.
Max.
 
Last edited:
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top