Thursday 28 April 2016

Frequency and Pulse Width Measurement using microcontroller

The circuit designers and developers needs different measuring equipment like digital multi-meter, CRO, DSO, frequency counter, logic analyse etc for testing their circuits. When they are designing any oscillator or PWM generator or they have generated any waveform, there is a need to measure either frequency or time period. Especially in case of PWM generator there is a need to measure frequency, ON & OFF time and the most required thing is duty cycle.

Now if they are measuring these parameters using CRO then

- 1st they have to calculate no of horizontal divisions for ON period and for OFF period
- Then multiply it with time/division factor. They will get Ton and Toff
- Then after making some calculations they will find out frequency and duty cycle
- And this they have to repeat every time as they change design

Weathers then using CRO if they use DSO (digital storage oscilloscope) then all the readouts are available directly. But they have to pay a lot more cost for this. Also CRO and DSO are available only in well equipped laboratories because these are not much low cost tools such as digital multi-meters. So the hobbyists may not have these tools in their personal home laboratories.

That will give you direct readouts of four parameters (1) frequency (2) ON time (3) Off time (4) duty cycle in a second with almost 99% accuracy. The circuit is very simple, easy to build with fewer components one micro-controller (AT89C51), one LCD and additional components like crystal, capacitors, resistors, transistors etc. some of the features of the circuits are

1.  Measures frequency from 50 Hz to 65 KHz (display it in Hz)
2. Measures ON and OFF time periods from 25 µs to 65 ms (display it in µs)
3. Measures and displays duty cycle in percentage
4. Displays all four parameters on 20×4 LCD panel
5. Repeat mode of operation to continuously measure all four parameters

Hardware section

hardware connections for frequency and pulse width measurement circuit. Major components are micro-controller AT89C51 and 20×4 LCD. The data pins D0-D7 of LCD are connected to port P2 of AT89C51. Control pins RS and E are connected with port P1 pins P1.0 and P1.1. RW pin is connected to ground. A 1 K Ohm pot is connected to VEE pin as shown to vary LCD brightness. One 12 MHz crystal along with two 33 pf capacitors (C2 and C3) are connected to XTAL1 and XTAL2 pins of micro controller to provide required internal clock.

One 1 µF capacitor in parallel with one push button (reset) switch is connected in between Vcc and reset pin (no. 9) of micro controller to form “power on reset” circuit. Reset push button is used to manually reset micro controller. 

One RED LED is connected to pin P1.2 for indication. SPDT switch is connected to pin P1.7 as shown to select either repeat or no repeat operation modes. The signal is applied to pins P3.3 and P3.4 through transistor Q1 (2N2222 type) which is configured in switch mode. This small circuit with one transistor and two resistors will convert any incoming signal into square or rectangle shape and limit the amplitude of signal to Vcc (that is 5 V max)


Working and operation

PWM signal is applied at the base of transistor. Because transistor works as an invertor, the inverted wave is applied to pins P3.3 and P3.4. Negative edge on pin P3.3 will generate external interrupt. This interrupt will start counting pulses on pin P3.4. Pulses are counted for exactly 1 second period. This gives us directly value of frequency as number of pulses / second. Afterwards internal timer will measure the time (in micro sec) for which the amplitude of pulse remains high that gives Ton value and same for Toff value. At last duty cycle is calculated using equation.


LED indicated counting and calculating process. At last all four values are displayed on LCD. Now if SPDT switch is on no repeat position then measurement process is finished but if it is on repeat position the same above process repeats and it measures all four parameters continuously. This complete operation is based on the program loaded into micro controller. So now let us understand the software program.

Software section

The program is written in embedded C language and compiled through KEIL cross compiler. Complete program is divided in 9 different functions with one main function. Out of these nine functions, five functions are for LCD handling, one to measure ON time and OFF time, one to measure duty cycle one interrupt function to measure frequency and the last one is delay function.

LCD handling functions

1. write cmd function sends command byte to LCD. It takes one argument byte and sends it 
    to P2

2. write data function sends data byte to be displayed on LCD. It also takes one argument   
    byte and sends it to P2 

3. write str function writes whole string on LCD. It takes pointer as an argument
    that points address of first character of string. then through pointer it sends all the   
    character one by one to P2

4. busy function generated delay every time before any byte is sent to LCD

5. display function takes two arguments. It converts HEX numbers into decimal and then 
    decimal to ASCII so that they can be displayed on screen

Measuring functions

1. Period function measures ON time and OFF time. It measures the actual time for which pulse amplitude remains high and remains low using timer 1. It first waits for one cycle (ON time and OFF time) to complete. Then starts timer and measures time in micro second till pulse is high. This will measure OFF time because we are measuring inverted pulse width. Then again it waits for one cycle. Again timer will run till pulse is low. This will measure ON time. Both ON time and OFF time values are stored in four different variables.

2. Frequency function is an interrupt function. It measures number of pulses per second. It starts as soon as a negative edge arrives on external interrupt pin P3.3. It first clears count in TH0 and TL0 and then start counting external pulses arriving on pin P3.4. It stops counter after exact 1 second time. The count in TH0 and TL0 are stored in 2 variables that give’s directly the value of no. of pulses / second.

3. Duty cycle function calculates duty cycle of wave. It gets the values of Ton and Toff from period function and calculates duty cycle using formula. It also scales down Ton and Toff values if they are out of 16 bit (integer variable) range.


Last one is the delay function that generates exact 1 second delay using timer 1. It generates 50 ms delay using timer and rotates it in a loop for 20 times. So finely we get 50×20 = 1000 ms = 1 sec.

The main function performs following tasks

·  First initializes ports and pins as input or output.

·  Next it initializes LCD and displays message “frequency & pulse width measurement”.

·  Then to calculate frequency it initializes timer 0 as counter to count external pulses and   
   timer 1 as timer to generate 1 sec delay.

·  Then it will wait for an external interrupt. Interrupt is generated by negative edge of 
   incoming signal. As frequency is calculated it is displayed as Hz in 5 digits.

·  After that, period function will measure ON time and OFF time and they are displayed on 
   LCD. 

·  After that, duty cycle function will calculate duty cycle and it is also displayed

·  Finely, it reset flag and checks the status of pin P1.7. If its 0, repeat the same operation and    if its 1 then programs enters into continuous loop.

Source Code

unsigned int flag=0;
unsigned char offtim1, offtim2, ontim1, ontim2,f1,f2;
unsigned int ton,toff,z;
void delay()              // generates 1 sec delay  
 {    
    int k;
    TL 1 = 0xBF; // load value in timer 1
    TH1 = 0x3C;TR1 = 1; // start timer

    for(k=0;k<20;k++) // rotate loop 20 times
   {
     while(TF1==0);
     TF1 = 0;
     TL1 = 0xBF;
     TH1 = 0x3C;
   }

    TR1 = 0; // stop timer
}
void busy()     // wait until LCD is busy
{
   int x;
   for(x=0;x<1500;x++);
 }
void writecmd(unsigned char a) // send command byte to LCD
{
   busy();
   rs = 0;
   P2 = a;
   en = 1;
   en = 0;
 }
void writedata(unsigned char b) // send data byte to LCD
{
   busy();
   rs = 1;
   P2 = b;
   en = 1;
    en = 0;
  }
void writestr(unsigned char *s) // write string / message to LCD
{
   unsigned char l,i;
   l = strlen(s);
   for(i=0;i<l;i++)
   {
       writedata(*s); // display all the characters
       s++; // one by one
    }
 }
        void frequency() interrupt 2 // external interrupt 1 function
        {
EA=0;  // first disable interrupts
led=0; // indicate on LED
TH0=0x00; // clear count
TL0=0x00;
TR0=1; // start timer 0
delay(); // give 1 sec delay
TR0=0; // stop timer
f1=TL0; // save count
f2=TH0;
flag=1; // set the flag
led=1; // indication off
        }
  void period()
 {
    while(pin==1); // wait to complete one 
    while(pin==0); // cycle
   TR1=1; // start timer 1
   while(pin==1); // wait until pulse amplitude is high
   TR1=0; // stop timer
   offtim1=TL1; // save the content
   offtim2=TH1;
   TH1=0x00;   // clear timer again
   TL1=0x00;
   while(pin==0); // wait again to complete one
   while(pin==1); // cycle
   TR1=1; // start timer 1 again
   while(pin==0); // wait until pulse amplitude is low
   TR1=0; // stop timer
   ontim1=TL1; // save the content
   ontim2=TH1;
 }
   void dutycycle()
   {
      int d,d1;
      if((ton>100) || (toff>100)) // scales down values of Ton and Toff
       {
            ton=ton/10;
            toff=toff/10;
        }
         else if((ton>1000) || (toff>1000))
        {
           ton=ton/100;
           toff=toff/100;
        }
d = ton*100/(ton+toff); // calculate duty cycle
d1 = d%10; // separate two digits and convert
d1=d1+0x30; // in to ascii
d=d/10;
d=d+0x30;
writedata(d); // display them
writedata(d1);
writedata(0x25); // display %
   }
 void display(unsigned char time1, time2)  // convert hex to decimal and 
 {  
 unsigned int tmp1,tmp2,tmp3,tmp4,t,t1,i,j;
unsigned char asci[5];
tmp1 = (time1 & 0x0F);  // tmp1 as lower nibble of lower byte
tmp2 = time1 >> 4; // tmp2 as upper nibble of lower byte
tmp3 = (time2 & 0x0F); // same for tmp3 and tmp4 for
tmp4 = time2 >> 4; // upper byte
tmp2 = tmp2*16; // convert them into decimal
tmp3 = tmp3*256;
tmp4 = tmp4*4096;
t = tmp1+tmp2+tmp3+tmp4; // get the final value in t
if(z==1) ton=t; // for z=1 its Ton and 
else toff=t; // vice versa
i=4;     
       if(t>=10000) // convert all digits into ASCII
      {
         while(t>=10)
          {
             t1=t%10; // separate all digits
             asci[i]=t1+0x30; // add 30h in all digits to get ASCII value
             t=t/10;
             i--;
         }
      asci[0]=t+0x30;
   }
  else if (t>=1000)
 {
    while(t>=10)
   {
      t1=t%10;
     asci[i]=t1+0x30;
     t=t/10;
      i--;
  }
        asci[1]=t+0x30;
        asci[0]=0x20; // mask all leading values with space
 }
else if (t>=100)
 {
      while(t>=10)
     {
        t1=t%10;
        asci[i]=t1+0x30;
        t=t/10;
        i--;
    }
     asci[2]=t+0x30;
     asci[0]=0x20; // mask all leading values with space
     asci[1]=0x20;  
 }
else
  {
     t1=t%10;
     asci[4]=t1+0x30;
     t=t/10;
    asci[3]=t+0x30;
    asci[2]=0x20;
    asci[1]=0x20;
    asci[0]=0x20;
  }
    for(j=0;j<5;j++) // display
    writedata(asci[j]); // all four digits one by one   
}
  void main()
  {
P2 = 0x00;   // P2 as output port
rs=0;   // clear all LCD control pins
en=0;
sw=1; // sw as input
led=0;
led=1;  
writecmd(0x3C);   // initialize LCD
writecmd(0x0E);
writecmd(0x01);
writecmd(0x84);
writestr("Frequency &  Measurement"); //display message in 1st and 3rd line of LCD
writecmd(0xC4); // move to 2nd line
writestr("Pulse Width"); // and display message
TH0=0x00; // clear count in T0
TL0=0x00;
IT1=1; // edge trigger interrupt
IE=0x84;  // enable external interrupt 1
 TMOD=0x15;     // timer 0 in 16 bit counter and timer 1 in 16 bit timer
next:     while(flag==0);    // remain within loop till flag is clear
writecmd(0x01); // clear LCD 
writestr("Frequency:"); // display frequency
display(f1,f2);
writestr(" Hz  ");
TH1=0x00; // clear T1
TL1=0x00;
period(); // measure time periods
z=0; // for Toff clear flag
     writestr("Toff:"); // display Toff
display(offtim1,offtim2);
writestr(" microsec");   
z=1; // for Ton set flag
writecmd(0xC0);
     writestr("Ton:"); // display Ton
display(ontim1,ontim2);
writestr(" microsec  ");
writestr("duty cycle:");
dutycycle(); // calculate and display duty cycle
flag=0;  // reset the flag to 0 again
EA=1;   // again enable interrupts
if(sw==1) goto next;    // if repeat mode again go for next measurement
while(1); // otherwise continuous loop
  }


No comments:

Post a Comment