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 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: Sun Apr 08, 2007 4:19 pm     Reply with quote

To do that, you need to do these things:

1. Declare a global variable to indicate that a CCP interrupt occured.

2. Inside the CCP isr, set the global variable = TRUE.

3. At start of main(), set it = FALSE.

4. Then, down at bottom of the main while() loop, change the code
that displays the frequency so that it checks this global flag.
If the flag is TRUE, then display the frequency. If not, then display
a message indicating there's no signal present. Also, if the flag
is TRUE, then clear it.

Here's the modified code:
Code:

if(gc_capture_flag == TRUE)
  {
   frequency = (int16)(1000000L / current_ccp_delta);
   
   // Display the calculated frequency.
   printf("%lu Hz    \n\r", frequency);
   gc_capture_flag = FALSE;
  }
else
  {
   printf("No signal\n\r", frequency);
  }

I added a few spaces after the "Hz" so that if this was being displayed
on an LCD, it would be sure to overwrite the "No signal" text if that was
present.
acidice333



Joined: 14 Oct 2006
Posts: 33

View user's profile Send private message

PostPosted: Mon Apr 23, 2007 7:05 pm     Reply with quote

What is needed to change for this to work on a 48mhz clock? (PLL 20mhz)
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Apr 24, 2007 2:56 pm     Reply with quote

I assume you have a board with a PIC such as the 18F4550 that you
want to run at 48 MHz, with a 20 MHz crystal. Your fuses statement
should look like this:
Quote:

#include <18F4550.H>
#fuses HSPLL, PLL5, CPUDIV1, NOWDT, PUT, BROWNOUT, NOLVP
#use delay(clock=48000000)


The minimum number of changes required to make the tachometer demo
program work at 48 MHz are:

1. Change the ADC divisor to 64:
Quote:
setup_adc_ports(AN0);
setup_adc(ADC_CLOCK_DIV_64); // Divisor for 48 MHz oscillator
set_adc_channel(0);
delay_us(20);


2. Change the frequency calculation equation, to account for the
oscillator running 12 times faster than in the original example.
Change the numerator from 1 million to 12 million.
Quote:
frequency = (int16)(12000000L / current_ccp_delta);


Because of the higher 48 MHz oscillator frequency, the minimum PWM
frequency is much higher than the original example. So when you
turn the trimpot, the frequency range will be from 2929 Hz minimum,
to a maximum of 24193 Hz. But the program still works OK and you
will see the correct frequency displayed in the terminal window.
acidice333



Joined: 14 Oct 2006
Posts: 33

View user's profile Send private message

PostPosted: Tue Apr 24, 2007 6:22 pm     Reply with quote

Thanks I thought I did something wrong but its all correct.

I'm having a wierd probem- with it operating at 4mhz it seems fine and at 48mhz the reading spikes and is never stable. I will try running it at 20mhz tommorow.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Tue Apr 24, 2007 6:26 pm     Reply with quote

What's your PIC and your compiler version ?
acidice333



Joined: 14 Oct 2006
Posts: 33

View user's profile Send private message

PostPosted: Tue Apr 24, 2007 6:57 pm     Reply with quote

18f2550, and v4.009

4mhz crystal, with it set to 4mhz works fine.
4mhz crystal, with it set to 24mhz doesn't work (spikes)
20mhz crystal, with it set to 48mhz doesn't work (spikes)

Im measuring a frequency from a 4n25, ranging from 25hz to 200hz
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.
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 1, 2, 3, 4  Next
Page 1 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