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 support@ccsinfo.com

Determining square-wave frequency input into pic
Goto page Previous  1, 2, 3, 4  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: Tue Apr 24, 2007 7:57 pm     Reply with quote

You want it to work at very low frequencies. That's different from just
making the demo work. It requires adjustments to the pre-scalers.
I'll work on it tomorrow.
acidice333



Joined: 14 Oct 2006
Posts: 33

View user's profile Send private message

PostPosted: Tue Apr 24, 2007 8:02 pm     Reply with quote

Yes. I was thinking it might be a prescalar problem, looking forward to your post tommorow (: Would be a bonus if it worked with 1hz (:
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun May 20, 2007 2:06 pm     Reply with quote

Here's the answer to your question:

To make the tachometer example work with a 1 Hz input signal while the
PIC is running at 48 MHz, you need to extend Timer1 to 24 bits (currently
it's only 16 bits wide).

The reason for this is because at 48 MHz, the Timer1 clock is 12 MHz
(1/4 of the oscillator frequency). A 1 Hz input signal has a period of
one second. During that one second, the Timer1 will count up to 12
million. But Timer1 is only 16-bits wide, so it can only hold 65535.
By extending it to 24-bits, it can count up to 16777215 and so it's now
big enough to hold the count of 12,000,000 which occurs between the
positive edges of a 1 Hz input signal.

You could increase the pre-scaler on Timer1 to 8 (the maximum value
available), and this would reduce the timer clock to 1.5 MHz. But the
count during one second would still be 1.5 million, and that's way more
than the 65535 that the Timer1 hardware can count up to. So even
with a Timer1 prescaler, you still need to extend the Timer to 24-bits.

This thread has an alternate #int_ccp1 routine, which uses a Timer1
value which is extended to 24 bits.
http://www.ccsinfo.com/forum/viewtopic.php?t=906

Other changes:
In the frequency calculation in main(), you need to change the
numerator to 12000000L. That's the frequency of the Timer1 clock
(12 MHz). You also need to increase size of the global variable that
holds the current CCP to be an 'int32' (it was 16 bits). This will hold
the 24-bit extended Timer1 value. Also the 'current_ccp_delta' will
have to be change to an 'int32'.

The revised display code would look like this.
Code:

disable_interrupts(GLOBAL);
current_ccp_delta = g32_ccp_delta;;
enable_interrupts(GLOBAL);

if(gc_capture_flag == TRUE)
  {
   frequency = (int16)((12000000L + (current_ccp_delta >> 1)) /
                       current_ccp_delta);

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

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



Joined: 06 Mar 2007
Posts: 92
Location: Pune,India

View user's profile Send private message AIM Address Yahoo Messenger

PostPosted: Wed May 23, 2007 3:41 am     Reply with quote

Dear Programmer,
Here in #int_ccp1 interrupt you're calculating time interval between two rising pulses, but I have one query abt this interrupt.
Here your statement is,
Code:

#int_ccp1
void ccp1_isr(void)
{
int16 current_ccp;
static int16 old_ccp = 0;

// Read the 16-bit hardware CCP1 register
current_ccp = CCP_1;  // From 16F877.H file

// Calculate the time interval between the
// previous rising edge of the input waveform
// and the current rising edge.  Put the result
// in a global variable, which can be read by
// code in main().
isr_ccp_delta = current_ccp - old_ccp;

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

At start , old_ccp = 0.& current_ccp = CCP_1;
consider current_ccp = 0x1000;
So, isr_ccp_delta = 0x1000.
But, Timer1 is incrementing contineously,
At one condition when, consider
current_ccp = 0xFDE8 & old_ccp = 0XF618;
Then isr_ccp_delta = 0x07D0;
Now old_ccp = 0xFDE8;
TILL HERE IS OK.
BUT WHEN timer1 is overflow & if
current_ccp = 0x1ED0;
NOW here isr_ccp_delta = current_ccp - old_ccp (gives any -ve Value?)
plz reply on this,
_________________
Thank You,
With Best Regards,
Deepak.
Ttelmah
Guest







PostPosted: Wed May 23, 2007 4:37 am     Reply with quote

Hint.
Look at how long a signal has to be stable, before it is 'seen' by the CCP. This is dependant on the Tcy of the processor (and hence on the clock). I'd suspect your input signal has got some high frequency noise, and at the higher clock rates, the PIC is 'seeing' this, while at the lower rates it is not...
Figure 20-10, values 50, 51, and 52.
Try a small capacitor on the input used to detect the signal.

Best Wishes
javi.ar



Joined: 17 Feb 2006
Posts: 59
Location: Argentina

View user's profile Send private message Send e-mail Visit poster's website MSN Messenger

dcc & frequency
PostPosted: Mon Jun 18, 2007 12:37 am     Reply with quote

Hi everyone, thanks in advance ...

what I am trying to find here is, where do I go wrong , I 've been wondering for a while how to fix and I could not. I have CCS 4.032 ver working with 18f4525 XT 10MHZ output PIN_E2
#define UNO 56
#define CERO 112
void main()
{
init(); //calls all the setup
lcd_init();
delay_ms(10);
// TODO: USER CODE!!
printf (lcd_putc,"working");

while (TRUE) {
send_bit(1);
send_bit(0);
}
}

int send_bit(unsigned int1 b)
{
if (b == 1){
output_high(OUT);
delay_us(UNO);
output_low(OUT);
delay_us(UNO);

}
else{
output_high(OUT);
delay_us(CERO);
output_low(OUT);
delay_us(CERO);
}
return 0;
}

code is slightly longer...

any way on the other end I have 16f628a input PIN_B3 / CCP1 with 10K resistor pulling down. (I test with small capacitor to see if could improve with no success)
with the following code...

int16 isr_ccp_delta;
int1 xccp_on = 0;

#int_ccp1
void ccp1_isr(void)
{
int16 current_ccp;
static int16 old_ccp = 0;

current_ccp = CCP_1; // From 16F628A.H file
isr_ccp_delta = current_ccp - old_ccp;
old_ccp = current_ccp;
xccp_on = 1;
}

int main(void)
{
init();

while(TRUE){
xccp_on = 0;

if (xccp_on == 1);
printf("%d ",read_bit());

}
return 0;

unsigned int1 read_bit(void)
{
int16 c_ccp_delta;

disable_interrupts(GLOBAL);
c_ccp_delta = isr_ccp_delta;
enable_interrupts(GLOBAL);
//printf ("%lu ", c_ccp_delta );
if ((c_ccp_delta > 11 )&& (c_ccp_delta < 19 )){
return 1;
}
else if ((c_ccp_delta > 25 ) && (c_ccp_delta < 35 )){
return 0;
}
}

and config (init())

int init(void){

setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);
setup_timer_2(T2_DISABLED,0,1);
setup_ccp1(CCP_CAPTURE_RE);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
clear_interrupt(INT_CCP1);
enable_interrupts(INT_CCP1);
enable_interrupts(GLOBAL);
setup_oscillator(False);

return 0;
}

#include <16F628A.h>
#device *=16

#FUSES NOWDT //No Watch Dog Timer
#FUSES XT //Crystal osc <= 4mhz
#FUSES PUT //Power Up Timer
#FUSES NOPROTECT //Code not protected from reading
#FUSES NOBROWNOUT //No brownout reset
#FUSES NOMCLR //Master Clear pin used for I/O
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD //No EE protection

#use delay(clock=4000000)
#use rs232(baud=2400,parity=N,xmit=PIN_B2,rcv=PIN_B1,bits=8,errors)

and here is part of the output
1 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 1 1 1 1 1 1 1 0 0 0 1 1 1 1 1 1 1 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0 1 1 1 1 1 1 1 0 0 0 1 1 1 1 1 1 1 0 0 0 0 1 1 1 1 1 1 1 0 0 ...

but I was expecting to see 101010101010101010101010101010101010101...

the value of the c_ccp_delta for 4MHZ (timer1 div by 8 reading for 112us) is about 14/16

the wired thing is if the output is only 1s or 0s works fine, but with the changes...

I dont know what else to test. Thanks a lot. guys...
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Mon Jun 18, 2007 12:49 am     Reply with quote

What is the purpose of your code ?

What project are you trying to do ?
javi.ar



Joined: 17 Feb 2006
Posts: 59
Location: Argentina

View user's profile Send private message Send e-mail Visit poster's website MSN Messenger

PostPosted: Mon Jun 18, 2007 10:04 pm     Reply with quote

PCM programmer wrote:
What is the purpose of your code ?

With this code 18f4525 is set up as command station providing dcc 1&0 bits
(1 = 58us high & 58us low ,0= 116us high & 116us low)
and 16f628a is intend to "read" bits coming into CCP1 from 18f4525. I hope I made myself clear
Quote:
What project are you trying to do ?

A personal dcc system(digital control & decoder +++... for scale trains and try to apply standard to some other toys).
I am in the very fist stages... as you may see...
Guest








PostPosted: Sun Jul 15, 2007 10:33 pm     Reply with quote

Hi

I dont have a scope, but I do have a DMM with frequency option, the frequency goes from 2.XX hz to 120.XX hz. Measuring the frequency with the DMM I get slow increasing +1hz values, with the 18f4550 I get unstable values for example the frequency could be 30.xx HZ and I printf it out and I see 27hz, 30hz, 31hz... just close.. what could be my problem?

I'm using 4mhz osc.
javi.ar



Joined: 17 Feb 2006
Posts: 59
Location: Argentina

View user's profile Send private message Send e-mail Visit poster's website MSN Messenger

dcc bit reading
PostPosted: Mon Jul 16, 2007 6:00 am     Reply with quote

In this case and only for dcc bit reading I solved this way without using interrupts

I start reading on L_to_H edge and after 90 microseconds (us) y read the port again if its high so must be a cero else must be one...
that is because a cero is 116us high and 116 us low, and one is 58us high and 58us low...

and it works!!!
javi.ar



Joined: 17 Feb 2006
Posts: 59
Location: Argentina

View user's profile Send private message Send e-mail Visit poster's website MSN Messenger

PostPosted: Mon Jul 16, 2007 6:03 am     Reply with quote

Anonymous wrote:
Hi

I dont have a scope, but I do have a DMM with frequency option, the frequency goes from 2.XX hz to 120.XX hz. Measuring the frequency with the DMM I get slow increasing +1hz values, with the 18f4550 I get unstable values for example the frequency could be 30.xx HZ and I printf it out and I see 27hz, 30hz, 31hz... just close.. what could be my problem?

I'm using 4mhz osc.


I think printf takes about 20ms to fully execute, so you may be losing some info ... better if you place the code, so we can all see what is going on.
good luck.
A
Guest







I have some question about how to calculate about frequency.
PostPosted: Tue Jul 24, 2007 11:55 am     Reply with quote

Dear PCM programmer and another user.

I have some question about how to calculate about frequency. if current ccp is less than old_ccp;
example : when first time old_ccp is 65535 and when count up and when go to #int_ccp1 again current_ccp is 1000. what is the value of isr_ccp_delta and what is frequency of this loop.

And i want to know what is the limit of this sourcecode.
example : how many range of frequency that we can capture with this sourcecode and how to calculate about this limit. Please explain me about this sourcecode. Because i very confuse and doubt about when current_ccp is less than old_ccp and isr_ccp_delta will be minus value(-???). Thank you for your explaination.
Now i try to use this sourcecode to detect frequency of square wave and duty cycle about 50%. some time this sourcecode work. but when use this in some frequency. this sourcecode is not work. because i compare with scope to check value from micron.


#int_ccp1
void ccp1_isr(void)
{
int16 current_ccp;
static int16 old_ccp = 0;

current_ccp = CCP_1; // From 16F877.H file

isr_ccp_delta = current_ccp - old_ccp;
// example : isr_ccp_delta = (1000)-(65535); this value may be minus value; Is it true??

old_ccp = current_ccp;
}
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Jul 24, 2007 11:59 am     Reply with quote

To get rid of limits, use a 24-bit timer (16-bit hardware timer with 8-bit
software extension). This is explained in a earlier post in this thread,
which has a link to the 24-bit timer code.
cybanical



Joined: 10 Apr 2008
Posts: 6
Location: Oakland, CA

View user's profile Send private message

questions
PostPosted: Sat Apr 19, 2008 7:10 pm     Reply with quote

PCM Programmer, I have a couple questions about your CCP1 code and frequency calculation:


Code:
#int_ccp1
void ccp1_isr(void)
{
int16 current_ccp;
static int16 old_ccp = 0;

// Read the 16-bit hardware CCP1 register
current_ccp = CCP_1;  // From 16F877.H file

// Calculate the time interval between the
// previous rising edge of the input waveform
// and the current rising edge.  Put the result
// in a global variable, which can be read by
// code in main().
isr_ccp_delta = current_ccp - old_ccp;

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


In the interrupt for CCP1 you initialize old_ccp=0, and then at the end you save the last timer1 value as old_ccp. I assume I'm missing something because it seems to me that each time the interrupt is triggered wouldn't the old_ccp be reinitialized to 0 again before performing the new isr_ccp_delta calculation?


Also, in the frequency calculation. What does the L at the end of the timing value do? I'm not familiar with that technique.
Code:
 frequency = (int16)(1000000L / current_ccp_delta);


thanks
_________________
cybanical == cyber+mechanical
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Sun Apr 20, 2008 11:57 am     Reply with quote

For this type of question, you can easily find the answer by yourself by
making a short test program and looking at the .LST file. Let's do that.

Here is a little test program. Compile it.
Code:

#include <16F877.H>
#fuses XT, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock=4000000)

#int_ccp1
void ccp1_isr(void)
{
int16 current_ccp;
static int16 old_ccp = 0;

current_ccp = CCP_1;
}

//==========================
void main()
{


while(1);
}


Here is part of the .LST file.
The ASM code that clears the 'old_ccp' value is shown in bold.
Notice the address. It's 0046, 0047, 0048. Now look at the code
in main(). It goes from 003D to 0049, and it has gap from 0046-0048.
So the code that clears 'old_ccp' is executed once, at the beginning
of main(), when the PIC first starts running. It's not executed every
time the int_ccp isr runs. The isr code is from 0035 to 003C, where
it jumps back to the interrupt handler at 001F (that code is not shown).
Quote:

.................... #int_ccp1
.................... void ccp1_isr(void)
.................... {
.................... int16 current_ccp;
.................... static int16 old_ccp = 0;
*

0046: BCF STATUS.RP0
0047: CLRF old_ccp
0048: CLRF old_ccp+1

....................
.................... current_ccp = CCP_1;
*
0035: MOVF CCPR1H,W
0036: MOVWF current_ccp+1
0037: MOVF CCPR1L,W
0038: MOVWF current_ccp
.................... }
....................
.................... //==========================
0039: BCF PIR1.CCP1IF
003A: BCF PCLATH.3
003B: BCF PCLATH.4
003C: GOTO 01F
.................... void main()
.................... {
003D: CLRF FSR
003E: BCF STATUS.IRP
003F: MOVLW 1F
0040: ANDWF STATUS,F
0041: BSF STATUS.RP0
0042: BSF ADCON1.PCFG0
0043: BSF ADCON1.PCFG1
0044: BSF ADCON1.PCFG2
0045: BCF ADCON1.PCFG3
....................
....................
.................... while(1);
*
0049: GOTO 049


Anytime you have a question about compiler operation, you should
always make a test program and study the .LST file to see what is
happening.
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  Next
Page 2 of 4

 
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