Frequency n Period Calculation Of an Input Signal

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Frequency n Period Calculation Of an Input Signal

Jump to solution
4,441 Views
admin
Specialist II

Hello there,

              

I have written  code to measure the parameters (frequency, period, duty cycle)of an input signal fed from a function generator, using interrupts. I have used the Enhanced Capture timer for the input capture and PLL. I have run the program on HCS12X demokit  SK-S12XDP512A but the frequency and period calculation is going wrong... also, i have declared period as an unsigned long int and frequency as a float type...I have attatched my program. do verify and clarify my doubt.

 

 

#include <hidef.h>      /* common defines and macros */
#include <mc9s12xdp512.h>
#pragma LINK_INFO DERIVATIVE "mc9s12xdp512"

void init_PLL(void);
void init_ECT(void);
void period_frequency(void);

 

unsigned int r1;
unsigned int r2;
unsigned int r3;
unsigned int count;
long int period;
float    frequency;
unsigned long int freq;

 

void main(void)

{
 init_PLL();           

 init_ECT();          

 EnableInterrupts;
 for(;:smileywink:
 {
 }
}

 

void init_PLL(void)
{
 CLKSEL       &= 0x7F;   // Deselect PLL Clock so can change SYNR, REFDV, PLLCTL
 PLLCTL       &= 0xBF;   // Turn off PLL so can change freq
 SYNR          =    4;
 REFDV         =    0;
 PLLCTL        = 0xD1;   // 1101 0001 ; Enable auto tracking mode, turn on pll, clock monitor, self clock mode      
 CLKSEL_PLLSEL =    1;
}


void init_ECT(void)
{
 ICSYS     = 0x00;       // no input sharing, normal operation
 TSCR2     = 0x81;       // timer overflow interrupt enable, prescaler factor 2
 TIOS      = 0x00;       // set the channel to input capture
 TCTL4     = 0x10;       // capture rising edges
 TFLG1     = 0xFF;       // clear flags
 TIE       = 0x04;       // enable the timer interrupts
 TSCR1_TEN = 1;          // timer on
}

 

#pragma CODE_SEG __NEAR_SEG NON_BANKED
interrupt 10 void TIMCH2_ISR(void)
{
 TFLG1      =  0x04;                     //clear the flag
 r1         =   TC2;                    
 r2         = count;
 period     = (r1+(r2*0xFFFF)-r3)*0.1;  // calculates the period
 r3         = r2;
 count      = 0;                        
 frequency  = 1.0/period;               // frequency value in floating point
 freq       = (int) frequency;          //frequency value in integer
}
 

#pragma CODE_SEG __NEAR_SEG NON_BANKED       
interrupt 16 void TIMOVF_ISR(void)

 TFLG2_TOF = 1;           // clear the overflow flag
 count++;                 //increment the counter
}

 #pragma CODE_SEG DEFAULT

Labels (1)
Tags (1)
0 Kudos
1 Solution
857 Views
bigmac
Specialist III

Hello,

 

I have chosen to directly utilise the period between pulses (in microseconds) rather than pulse frequency, since the period is the quantity measured.  I have also calculated the circumference of the wheel from its radius (2 * pi * R) with the radius conveniently in millimetres, and with the approximation for pi of 22 / 7, which should give sufficient accuracy.

 

Using the symbols that I defined in my previous post, we have

 

speed  = (1000000 / (N * T)) * (2 * 22 / 7 * R / 1000) * 3600 / 1000

           Revs per second   |    Circumference (m)    |Factor for km/h

Reducing all the numeric value to a simple quotient, and re-arranging the sequence to suit an integer calculation process, gives the expression in my previous post.  The value 158400 was obtained from (2 * 22 * 3600).

 

The ISR code will need to flag the main loop (via a volatile global variable) when each new period reading has been completed.  Only when the flag is set will the main loop calculate the speed from the measured period.  Perhaps you are not doing this.  Perhaps you will need to use the real hardware, rather than simulation, to test the input capture and timer overflow processes.

 

Regards,

Mac

 

View solution in original post

0 Kudos
8 Replies
857 Views
pgo
Senior Contributor V

Dear Manasa,

 

Another point to consider is that the floating point operations are very slow.  It would be a good idea to move the floating code from the interrupt routines to the mainline otherwise your minimum period may be limited.

 

The interrupt code should do the minimum work.

 

bye

 

 

 

0 Kudos
857 Views
bigmac
Specialist III

Hello manasa,

 

There seems to be some further problems with your period calculation, in addition to the incorrect constant multiplier for the count value.

 

  1. The r3 value being subtracted is the count value from the previous interrupt.  Since the count value starts from zero each time, this would appear to be incorrect.  It would make more sense with r3 = r1; or r3 = TC2; after the period calculation.
  2. The final constant multiplier of 0.1 within the period expression is a floating point value.  Since all other values within the expression are 16-bit or 32-bit integers, you will want to avoid unnecessary floating point conversions, particularly within the ISR, as has already been mentioned.  Therefore the expression should be modified as follows: 
     period = ( ... ) / 10;

Regards,

Mac

 

0 Kudos
857 Views
admin
Specialist II

Hey Bigmac, thank you.

It worked. Now, there is another task of calculating wheel Speed and RPM for a given PPR(Pulse per Revolution) and a given wheel radius..

I consider the PPR n WheelSpeed as two variables here.. how would the code look like?

0 Kudos
857 Views
bigmac
Specialist III

Hello,

 

I do not know the scaling of your measured pulse period, but I will assume that it is an integral number of microseconds.  I will also assume that the wheel speed result that you require is an integer number of kilometres per hour, and that integer calculations would be used for efficiency.

 

In the following calculation, R is the wheel radius in millimetres, N is the number of pulses per revolution, and T is the pulse period in microseconds.  Also the integer approximation 22 / 7 is used for pi.  If my reckoning is correct, the following expression should provide the wheel speed.  Obviously the calculation will use 32-bit values - some additional casts may prove to be necessary.

 

speed = (byte)(158400 * R / (7 * N * T));

 

If the calibration of the pulse period differs from that assumed, this will need to be taken into account in the scaling of the result.

 

Regards,

Mac

 

0 Kudos
857 Views
admin
Specialist II

Hello bigmac,

 

       I didn't get the no 158400??? 

 for a given PPR (pulse per revolution) and wheel radius, I have got the calculated values of wheel speed as 56.548Kmph and wheel RPM as 500. and the formula involved is

 

     wheel speed (in Kmph) = (no of pulses per sec / PPR)*circumference*(3600)*(1/1000000)

 

    while coding, I did not include these calculations in the ISR, what I did is called a separate functions for these calculations outside the ISR but have included the parameters that were used in the ISR.. When i tried to run, I have noticed on the true-time simulator window that the RPM and Wheel speed are not appearing against the variables....

what might have gone wrong? verify the ISR code that is there in my previous(first) post..                   

0 Kudos
858 Views
bigmac
Specialist III

Hello,

 

I have chosen to directly utilise the period between pulses (in microseconds) rather than pulse frequency, since the period is the quantity measured.  I have also calculated the circumference of the wheel from its radius (2 * pi * R) with the radius conveniently in millimetres, and with the approximation for pi of 22 / 7, which should give sufficient accuracy.

 

Using the symbols that I defined in my previous post, we have

 

speed  = (1000000 / (N * T)) * (2 * 22 / 7 * R / 1000) * 3600 / 1000

           Revs per second   |    Circumference (m)    |Factor for km/h

Reducing all the numeric value to a simple quotient, and re-arranging the sequence to suit an integer calculation process, gives the expression in my previous post.  The value 158400 was obtained from (2 * 22 * 3600).

 

The ISR code will need to flag the main loop (via a volatile global variable) when each new period reading has been completed.  Only when the flag is set will the main loop calculate the speed from the measured period.  Perhaps you are not doing this.  Perhaps you will need to use the real hardware, rather than simulation, to test the input capture and timer overflow processes.

 

Regards,

Mac

 

0 Kudos
857 Views
admin
Specialist II

hello bigmac,

 thank you again. I understood what you suggested in the thread n I have modified the code accordingly..

The main loop is continuous and the values are updating.. Thank you so much.. Iam looking forward to more suggestions and help in the future..

0 Kudos
857 Views
kef
Specialist I

             period     = (r1+(r2*0xFFFF)-r3)*0.1;  // calculates the period

1) timer overflow period is 0x10000, not 0xFFFF.

 

 

2) r2 is short, 0xFFFF is also short. In C short times short gives short. You should typecast at least one of multipliers to long. This should work better:

 

             period     = (r1+((unsigned short)r2*0x10000UL)-r3)*0.1;  // calculates the period

 

3) Your algorithm isn't good to measure long time periods. Please download HC11 reference manual here and look at 10.5.5 Measuring Long Time Periods with Input Capture and Overflow.

 

0 Kudos