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();
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
Solved! Go to Solution.
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
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
Hello manasa,
There seems to be some further problems with your period calculation, in addition to the incorrect constant multiplier for the count value.
Regards,
Mac
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?
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
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..
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
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..
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.