CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

CCP / 24 bit timer / 1hz to 150 hz range
Goto page Previous  1, 2, 3, 4, 5, 6  Next
 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Mon Mar 22, 2010 11:46 am     Reply with quote

Somewhere else in the code you posted, you have changed something so that it doesn't work. Instead searching for the problem, I'm just going to post some working code. This code was tested with vs. 4.057 and vs. 4.105.

I set my function generator to give 10 Hz, and I got this output:
Quote:

9.99
10.00
10.00
10.00

I set it to put out approximately 20 Hz, and I got this output on the
terminal window:
Quote:

20.01
20.00
19.98
19.98
19.99
20.00
19.98
19.98
20.00

Then I set it for 150Hz, and I got this output. Even my scope's frequency
counter jumps around a little bit, so I don't think the B&K function
generator is perfectly stable. In other words, I don't think the variation
below is caused by the PIC program. It's the function generator.
But anyway, it's still very close to 150 Hz.
Quote:

149.86
149.94
149.88
149.96
149.92
149.90
150.01
149.96
149.97
149.91
149.97
150.08


Here is the test program:
Code:

#include <16F628.h>
#fuses HS, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock = 20000000)
#use rs232 (baud=9600,parity=N,xmit=PIN_B2,rcv=PIN_B1,bits=8)

#priority CCP1, TIMER1

#define BytePtr(var, offset) (char *)((char*)&var + offset)

#byte PIR1 = 0x0C
#bit  TMR1IF = PIR1.0

int8  gc_timer1_extension = 0;
int8  gc_capture_flag = FALSE;
int32 g32_ccp_delta;

//------------------------------------------------------
#int_timer1
void timer1_isr(void)
{
gc_timer1_extension++;
}

//------------------------------------------------------

#int_ccp1
void ccp1_isr(void)
{
char timer_ext_copy;
int32 current_ccp;
static int32 old_ccp = 0;

gc_capture_flag = TRUE;       

current_ccp = (int32)CCP_1;   

// Get local copy of the timer ext.
timer_ext_copy = gc_timer1_extension;


if(TMR1IF)
  {
   if(*BytePtr(current_ccp, 1) < 2)  // Was CCP captured after Timer1 wrapped?
      timer_ext_copy++;  // If so, inc the copy of the timer ext.

   // Since we know a timer interrupt is pending, let's just
   // handle it here and now.  That saves a little load off
   // the processor.
   gc_timer1_extension++;  // Increment the real timer extension
   TMR1IF = 0;     // Then clear the Timer1 interrupt
  }

// Insert the timer extension into the proper place in the 32-bit
// CCP value.
// ie.,  Insert it into location "EE" as follows: 0x00EEnnnn
// (nnnn = the CCP).
*BytePtr(current_ccp, 2) = timer_ext_copy;

g32_ccp_delta = (current_ccp > old_ccp) ? current_ccp - old_ccp : current_ccp + (0x1000000 - old_ccp);

// Save the current ccp value for next time.
old_ccp = current_ccp;

}

//=======================
void main()
{
float frequency;

int32 current_ccp_delta;

set_timer1(0);           
setup_timer_1(T1_INTERNAL | T1_DIV_BY_1);   

setup_ccp1(CCP_CAPTURE_RE);   

// Enable interrupts.
clear_interrupt(INT_TIMER1);
enable_interrupts(INT_TIMER1);

clear_interrupt(INT_CCP1);
enable_interrupts(INT_CCP1);

enable_interrupts(GLOBAL);


while(1)
 {
  if(gc_capture_flag == TRUE)
     {
      disable_interrupts(GLOBAL);
      current_ccp_delta = g32_ccp_delta;;
      enable_interrupts(GLOBAL);

      frequency =  (5000000L / (float)current_ccp_delta);
      printf("%4.2f\n\r", frequency);

      gc_capture_flag = FALSE;
     }
  else
    {
     printf("No signal\n\r");
    }

  delay_ms(500);
 }

}
Salenko



Joined: 08 Sep 2008
Posts: 84

View user's profile Send private message

PostPosted: Mon Mar 22, 2010 2:10 pm     Reply with quote

Hi PCM,

finally I got a working code ! Smile

the error in my code was the use of:

Code:
#byte CCPR1_REG = 0x15   // Adress of CCPR1L
current_ccp = (int32)CCPR1_REG; // Read the current CCP



instead of :

Code:
current_ccp = (int32)CCP_1;



thank you for making a hardware test. Wink
vsmguy



Joined: 13 Jan 2007
Posts: 91

View user's profile Send private message Visit poster's website

PostPosted: Thu Jul 08, 2010 4:51 am     Reply with quote

PCM programmer wrote:


Code:


// Get local copy of the timer ext.
timer_ext_copy = gc_timer1_extension; 


if(TMR1IF)
  {
   if(*BytePtr(current_ccp, 1) < 2)  // Was CCP captured after Timer1 wrapped?
      timer_ext_copy++;  // If so, inc the copy of the timer ext.

   // Since we know a timer interrupt is pending, let's just
   // handle it here and now.  That saves a little load off
   // the processor.
   gc_timer1_extension++;  // Increment the real timer extension
   TMR1IF = 0;     // Then clear the Timer1 interrupt
  }

// Insert the timer extension into the proper place in the 32-bit
// CCP value.
// ie.,  Insert it into location "EE" as follows: 0x00EEnnnn
// (nnnn = the CCP).
*BytePtr(current_ccp, 2) = timer_ext_copy;



I have a question:

I am assuming that CCS clears an interrupt flag ( IF ) *only* after the corresponding ISR has executed.

Hence, in your code ( I am putting only the comment )

Code:

// Check if a Timer1 interrupt is pending. If so, check if
// the CCP capture occurred before or after the Timer rolled
// over. We can tell if it occurred after it rolled over, if
// the CCP's MSB is zero. ie., if the CCP is somewhere between
// 0x0000 and 0x00FF.


Is not the check for overflow redundant as the Timer1 IF set inside the CPP1 ISR *implies* that the overflow was not accounted for?

Can there be cases when the ISR for an interrupt has been serviced but its IF is still set? ( only under these circumstances, if any, will your extra check above make sense )

I am sure my assumption is wrong as a lot of people have used your code, so this is really an effort to clear up my understanding :-)
alextee89



Joined: 01 Apr 2011
Posts: 2

View user's profile Send private message

PostPosted: Sat Apr 02, 2011 2:57 am     Reply with quote

Here is the test program:
Code:

#include <16F628.h>
#fuses HS, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock = 20000000)
#use rs232 (baud=9600,parity=N,xmit=PIN_B2,rcv=PIN_B1,bits=8)

#priority CCP1, TIMER1

#define BytePtr(var, offset) (char *)((char*)&var + offset)

#byte PIR1 = 0x0C
#bit TMR1IF = PIR1.0

int8 gc_timer1_extension = 0;
int8 gc_capture_flag = FALSE;
int32 g32_ccp_delta;

//------------------------------------------------------
#int_timer1
void timer1_isr(void)
{
gc_timer1_extension++;
}

//------------------------------------------------------

#int_ccp1
void ccp1_isr(void)
{
char timer_ext_copy;
int32 current_ccp;
static int32 old_ccp = 0;

gc_capture_flag = TRUE;

current_ccp = (int32)CCP_1;

// Get local copy of the timer ext.
timer_ext_copy = gc_timer1_extension;


if(TMR1IF)
{
if(*BytePtr(current_ccp, 1) < 2) // Was CCP captured after Timer1 wrapped?
timer_ext_copy++; // If so, inc the copy of the timer ext.

// Since we know a timer interrupt is pending, let's just
// handle it here and now. That saves a little load off
// the processor.
gc_timer1_extension++; // Increment the real timer extension
TMR1IF = 0; // Then clear the Timer1 interrupt
}

// Insert the timer extension into the proper place in the 32-bit
// CCP value.
// ie., Insert it into location "EE" as follows: 0x00EEnnnn
// (nnnn = the CCP).
*BytePtr(current_ccp, 2) = timer_ext_copy;

g32_ccp_delta = (current_ccp > old_ccp) ? current_ccp - old_ccp : current_ccp + (0x1000000 - old_ccp);

// Save the current ccp value for next time.
old_ccp = current_ccp;

}

//=======================
void main()
{
float frequency;

int32 current_ccp_delta;

set_timer1(0);
setup_timer_1(T1_INTERNAL | T1_DIV_BY_1);

setup_ccp1(CCP_CAPTURE_RE);

// Enable interrupts.
clear_interrupt(INT_TIMER1);
enable_interrupts(INT_TIMER1);

clear_interrupt(INT_CCP1);
enable_interrupts(INT_CCP1);

enable_interrupts(GLOBAL);


while(1)
{
if(gc_capture_flag == TRUE)
{
disable_interrupts(GLOBAL);
current_ccp_delta = g32_ccp_delta;;
enable_interrupts(GLOBAL);

frequency = (5000000L / (float)current_ccp_delta);
printf("%4.2f\n\r", frequency);

gc_capture_flag = FALSE;
}
else
{
printf("No signal\n\r");
}

delay_ms(500);
}

}


if i am using 16f877a, izit just change to #include <16F877a.h> ?
SergioGM17



Joined: 25 Apr 2019
Posts: 2

View user's profile Send private message

PostPosted: Thu Apr 25, 2019 9:01 pm     Reply with quote

Hi!! First of all, sorry to bump this old thread.

Im using this code (ver 5.0xx), almost the same posted above, just using a LCD instead of a rs232, internal clock (4Mhz), to measure low freqs (0-3hz):

Code:
#include <16F628A.h>

#FUSES NOWDT,NOBROWNOUT,NOLVP,PUT,NOPROTECT

#use delay(internal=4MHz)

//#priority CCP1, TIMER1


#define LCD_ENABLE_PIN PIN_B5
#define LCD_RS_PIN PIN_A4
#define LCD_RW_PIN PIN_B7
#define LCD_DATA4 PIN_B4
#define LCD_DATA5 PIN_B2
#define LCD_DATA6 PIN_B1
#define LCD_DATA7 PIN_B0

#include <LCD.C>

#define BytePtr(var, offset) (char*)((char*)&var + offset)
//#byte CCPR1_REG = 0x15
#byte PIR1 = 0x0c
#bit  TMR1IF = PIR1.0

int8  gc_timer1_extension = 0;
BOOLEAN  gc_capture_flag = FALSE;
int32 g32_ccp_delta;

//------------------------------------------------------
#int_timer1
void timer1_isr(void)
{
gc_timer1_extension++;
}

//------------------------------------------------------

#int_ccp1
void ccp1_isr(void)
{
char timer_ext_copy;
int32 current_ccp;
static int32 old_ccp = 0;

gc_capture_flag = TRUE;       

current_ccp = (int32)CCP_1;   

// Get local copy of the timer ext.
timer_ext_copy = gc_timer1_extension;


if(TMR1IF)
  {
   if(*BytePtr(current_ccp, 1) < 2)  // Was CCP captured after Timer1 wrapped?
      timer_ext_copy++;  // If so, inc the copy of the timer ext.

   // Since we know a timer interrupt is pending, let's just
   // handle it here and now.  That saves a little load off
   // the processor.
   gc_timer1_extension++;  // Increment the real timer extension
   TMR1IF = 0;     // Then clear the Timer1 interrupt
  }

// Insert the timer extension into the proper place in the 32-bit
// CCP value.
// ie.,  Insert it into location "EE" as follows: 0x00EEnnnn
// (nnnn = the CCP).
*BytePtr(current_ccp, 2) = timer_ext_copy;

g32_ccp_delta = (current_ccp > old_ccp) ? current_ccp - old_ccp : current_ccp + (0x1000000 - old_ccp);

// Save the current ccp value for next time.
old_ccp = current_ccp;

}

//=======================
void main()
{
float frequency;
int32 current_ccp_delta;

set_timer1(0);           
setup_timer_1(T1_INTERNAL | T1_DIV_BY_1);   

setup_ccp1(CCP_CAPTURE_RE);   
lcd_init();
// Enable interrupts.
clear_interrupt(INT_TIMER1);
enable_interrupts(INT_TIMER1);

clear_interrupt(INT_CCP1);
enable_interrupts(INT_CCP1);

enable_interrupts(GLOBAL);


while(1)
  {
   

   if(gc_capture_flag == TRUE)
     {
     
      disable_interrupts(GLOBAL);
      current_ccp_delta = g32_ccp_delta;;
      enable_interrupts(GLOBAL);
      frequency = ((1000000L + (current_ccp_delta >> 1)) / (float)current_ccp_delta);

      printf(lcd_putc,"%4.2f Hz\n\r", frequency);
//      printf("%lu Hz, delta = %lx \n\r", frequency, current_ccp_delta);

      gc_capture_flag = FALSE;
    }
 /* else
    {
     printf(lcd_putc,"No signal\n\r");
    }
*/
  delay_ms(500);
 }

}


I got it working, simulating on Proteus showed the variable freqs. But then I changed something that don't know what it was (apart from changing from int to float), making the simulation show a static value (10, and in float 10.79), and not working as expected. And if I activate the
Code:
 /* else
    {
     printf(lcd_putc,"No signal\n\r");
    }
*/

It jumps to that, even with a signal Confused
Any guess of what it could be?

Thx in advance
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Fri Apr 26, 2019 12:43 am     Reply with quote

To find the differences between your code and the forum's code:

1. Download ExamDiff from: https://www.prestosoft.com/edp_examdiff.asp
I have been using vs. 1.8 for years. I notice they are now up to vs. 1.9.

2. Make a new folder on your Windows desktop.
3. Copy the forum's code into a text editor and save it as "working.c"
in that folder.
4. Save your code into the same folder as problem.c or whatever you call it.
5. Run Examdiff and select those two files in the new folder to compare.
6. Examdiff will load both and show differences highlighted in yellow.
You can go to the View menu and have it show differences only, if you want.

Now start to undo the changes you made in your program, as you test
which one is causing the problem.
temtronic



Joined: 01 Jul 2010
Posts: 9229
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Fri Apr 26, 2019 5:08 am     Reply with quote

Couple of comments, possible shortcuts to save time and pots of coffee..

Sounds like you always edit the same program, over and over again.
What I do with every PIC project is 1st, create a '1Hz LED' program, get it working then save it. I then copy the source, naming it 'pictype_program_v2.c', where pictype is the type of PIC, program is then name of the project. V2 means version 2.
I then edit the V2 version, compile, burn, test. I then copy v2 --> v3.
I then edit the V3 version,compile,burn, test. I then copy v2 --> v4.
Yes, it mkes for a LOT of files on the harddrive BUT I can go back to any previous version and not lose a day wondering which of the 3 or 4 or ?? changes I made didn't work. I have 1,000s of PIC files on this HD, but tons of room, have yet to 'clean up'.
I do something similar with 'fuses'. Since today's PIC have more fuses than instructions, I create a #INCLUDE file that has EVERY fuse in it, ONE per line, WITH a comment. Once I have the 1Hz LED program running, I save the 'fuses' file as 'pictype_1HZ_fuses.c'. This does 2 things. One, I have a set of known WORKING fuses for basic PIC operation. I copy/edit/save this for project specific requirements. Two, it 'cleans up' the main project. Just one #INCLUDE line not 20-30 lines of fuses information. 3rd, It saves me a LOT of typing AND retyping ! Say you decide to not use the WDT but you forget to type in 'no'WDT. You could spend hours not seeing why 'it worked before but not now'........

Jay
SergioGM17



Joined: 25 Apr 2019
Posts: 2

View user's profile Send private message

PostPosted: Thu May 02, 2019 8:52 am     Reply with quote

Hi, thank you for your responses.

Started from zero, with a signal generator + pic + virtual terminal (rs232) and the code worked perfectly.

Now, using with my own input signal, works with the virtual terminal, but when I use the LCD (16x1, LM020L on proteus) on A or B ports, or mixed, it seems like the CCP stops functioning, showing the "no signal" msg.

Adding to that, the #include lcd.c is below the #define pins, and the lcd_init() is on main().

In the meantime I will test with another lcd module.

EDIT: Apparently was a problem with the printf's and something on proteus, seems like it is solved.

TY!
temtronic



Joined: 01 Jul 2010
Posts: 9229
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Fri May 03, 2019 5:36 am     Reply with quote

You do KNOW that Proteus is NOT 100% functional ? It's full of bugs, errors and faulty DRCs !!
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Goto page Previous  1, 2, 3, 4, 5, 6  Next
Page 5 of 6

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group