Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

Measuring the time of the zero crossings

Status
Not open for further replies.

Fan174

Member level 2
Joined
Mar 27, 2018
Messages
51
Helped
0
Reputation
0
Reaction score
0
Trophy points
6
Activity points
413
I want to measure the time interval between every zero crossings for 5V AC input signal using the PIC16f877a.
I understand c programming but I am struggling to measure the time interval between every zero crossings. I did google search and found that I have to use Analog Comparator, Interrupt and CCP Module.

How to detect every zero crossing ?

if crossing detect then how to measure time ?
 

use a zero crossing detector circuit(opamp comparator based).
This will give you a pulse output for every zero crossing.

start a timer at first pulse and end it after you detect the second pulse.

time interval is the timer value * period of your timer clock.
 
  • Like
Reactions: Fan174

    Fan174

    Points: 2
    Helpful Answer Positive Rating
use a zero crossing detector circuit(opamp comparator based).
I want to use inbulit comparator in pic16f877a. I think it can be compare positive and negative voltage. if its positive voltage than output will high and its negative voltage then output will low


start a timer at first pulse and end it after you detect the second pulse.

time interval is the timer value * period of your timer clock.

I think I need to set interrupt with cpp model
 

For precise timing measurements, CCP is the way to go, it's the only way to get it crystal accurate without e.g. interrupt latency effects. Internal comparator can't directly drive CCP, if you want it though, you need an external loopback connection from comparator output to CCP input.
 
  • Like
Reactions: Fan174

    Fan174

    Points: 2
    Helpful Answer Positive Rating
For precise timing measurements, CCP is the way to go, it's the only way to get it crystal accurate without e.g. interrupt latency effects. Internal comparator can't directly drive CCP, if you want it though, you need an external loopback connection from comparator output to CCP input.

Exactly what do you mean ? Do i need to use external comparator?
 

Hi,

I assume the PIC and it´s comparator input can´t handle negative input voltages. Read datasheet.

Also read about CCP in the datasheet.
In short: CCP just safes the timestamp of the CCP event (zero cross)
You need to save this timestamp (t0) and wait for the next CCP event.
you may calculate delta_t = t_new - t0
then save t_new at the place of t0
do this in a loop

--> delta_t is the time difference in clock ticks from one zero_cross to the next zero_cross.

Klaus
 

Exactly what do you mean ? Do i need to use external comparator?
I say, you can use the internal comparator with a loop back connection. Generally I want you to read the data sheet and think yourself.

I assume the PIC and it´s comparator input can´t handle negative input voltages.
Surely not. But it would be sufficient to clamp negative input voltage. I wonder if you even need a comparator. Most zero crossing solutions work without it.

Unless you are using a schmitt trigger or a comparator with hysteresis you should expect multiple trigger events for each fundamental wave zero crossing due to noise. If the frequency range is limited (e.g. mains frequency), a time filter can do the trick.
 

Hi,

I assume the PIC and it´s comparator input can´t handle negative input voltages. Read datasheet.

Also read about CCP in the datasheet.

Klaus
Okay I looked datasheet and some links and I tried to understand basic of Capture mode in PIC

Capture mode is used to capture the value of Timer 1 when a signal at the CCP pin goes high /low. So we can get the time period from the timer count. In Capture mode, CCPR1H:CCPR1L captures the 16-bit value of the TMR1 register when an event occurs on pin RC2/CCP1.

Programming step

Configured RC2/CCP1 pin as input
Configured port as Output
set Timer 1
Enabled Global interrupts
Enabled CCP1 interrupt
Set Module to capture on Falling edge/rising edge
- On interrupt:
Read capture timer and save the value

Code:
void main(void)
{
   //Make all PORTD pins low
   PORTA = 0;
   PORTB = 0;
   PORTC = 0;
   PORTD = 0;
 
// Configured RB0 as Output
   TRISB0 = 0; //RB0 as Output PIN
 
//Configured RC2/CCP1 pin as input
   TRISC2 = 1;  
    
   T1CON = 0x01;           // set Timer 1
   CCP1CON = 0b00000101;   // Set Module to capture on rising edge
   INTCON = 0xc0;          //Enabled Global interrupts 
   CCP1IE = 1;             //Enabled CCP1 interrupt
   while(1);
}
 
void interrupt CCP1_ISP()
{
   // CCP1 Interrupt
   if(CCP1IF == 1)   // if the CCP1 Interrupt flag is set...
   {
      // Read capture timer and save the value//
   }
}
 

Hi,

basically correct.
Just the math is missing.

in case you expect bouncing signals:
* You know the expectable value. Maybe 10ms. So you know when the measured value is much smaller than the expected value .. you just may dismiss the captured value.

Klaus
 
  • Like
Reactions: Fan174

    Fan174

    Points: 2
    Helpful Answer Positive Rating
Hi,

basically correct.
Just the math is missing.

in case you expect bouncing signals:
* You know the expectable value. Maybe 10ms. So you know when the measured value is much smaller than the expected value .. you just may dismiss the captured value.

Klaus
I want to write program to measure time for every crossing.

I have used two variable value1 and value2 to store count value.

How to measure time for every crossing?
Code:
#include <xc.h>

 unsigned int value1, value2;
 
void main(void)
{
   
    
   //Make all PORTD pins low
   PORTA = 0;
   PORTB = 0;
   PORTC = 0;
   PORTD = 0;
 
// Configured RB0 as Output
   TRISB0 = 0; //RB0 as Output PIN
 
//Configured RC2/CCP1 pin as input
   TRISC2 = 1;  
    
   T1CON = 0x01;           // set Timer 1
   CCP1CON = 0b00000101;   // Set Module to capture on rising edge
   INTCON = 0xc0;          //Enabled Global interrupts 
   CCP1IE = 1;             //Enabled CCP1 interrupt
   while(1);
}
 
void interrupt CCP1_ISP()
{
   // CCP1 Interrupt
   if(CCP1IF == 1)            // if the CCP1 Interrupt flag is set...
   { 
                  value1 = CCPR1H; 
                  value2 = CCPR1L;       
   }
}
 

Hi,

I recommend to use one uint16 varible.

How to measure time for every crossing?
What´s unclear with the description of post#6?

Klaus
 

Hi,

What´s unclear with the description of post#6?
Yes I have somethings that I don't know how to implement in program

In short: CCP just safes the timestamp of the CCP event (zero cross)
You need to save this timestamp (t0) and wait for the next CCP event.
you may calculate delta_t = t_new - t0
then save t_new at the place of t0
do this in a loop

--> delta_t is the time difference in clock ticks from one zero_cross to the next zero_cross.

Klaus

When first interrupt happen it store data in the value1 and value2. How to store new data when next interrupt happen. I will have to use while loop but I need to make logic. I am struggling where to write code to store new value inside interrupt routine or outside interrupt routine

Code:
void interrupt CCP1_ISP()
{
   // CCP1 Interrupt
   if(CCP1IF == 1)            // if the CCP1 Interrupt flag is set...
   { 
                  value1 = CCPR1H; 
                  value2 = CCPR1L;       
   }
}
 

Hi,

Since CCP1 represents a 16 bit value I recommend to use uint16.
For sure you may use a nother variable: new_ccp (just local in ISR)
And you need the variable: delta_t (global)

Then (pseudo code)
Code:
* New_ccp = ccp1h, ccp1l
* Delta_t = new_ccp - t0
* t0 = new_ccp

No need for a loop

Klaus
 

You told remarkable little about your application, e.g. expected trigger frequency, so we can only guess about specific requirements. It should be clear that the previous capture time stamp must be stored or processed before it's overwritten. How it should be done depends to a large extend on the application details. In some cases, it might be processed directly in the IRQ function.

In any case, you should consider that timer 1 overflows at times. It may be necessary to track, possibly count it.
 

Hi,

Since CCP1 represents a 16 bit value I recommend to use uint16.
For sure you may use a nother variable: new_ccp (just local in ISR)
And you need the variable: delta_t (global)

Then (pseudo code)
Code:
* New_ccp = ccp1h, ccp1l
* Delta_t = new_ccp - t0
* t0 = new_ccp

No need for a loop

Klaus

I am new to PIC and xc8 IDE,. Can you please provide a link or examples on how to store 16 bit data in 16 bit register example :- UINT unsigned int

I cannot seem to find information anywhere about using UINT, but I see many code examples where it is used. I am having a issue to use UINT16 due to this lack of understanding.

Can we write like following to store 16 bit data in one 16 bit variable

UINT unsigned int = CCPR1H, CCPR1L
 

Hi,

Can you please provide a link or examples on how to store 16 bit data in 16 bit register example
This is a very basic job. Every tutorial will show how to do it. I even assume that the PIC datasheet tells you how to access 16 bit register values.

--> You urgently need to go through some basic tutorials. There will be even video tutorials.

****
In any case, you should consider that timer 1 overflows at times. It may be necessary to track, possibly count it.
I recommend to set counter frequency that it never counts more than 65536 with your lowest input signal frequency, then you don´t have to take care about timer overflow. Math will be correct.

Klaus
 

Hi,


This is a very basic job. Every tutorial will show how to do it. I even assume that the PIC datasheet tells you how to access 16 bit register values.

--> You urgently need to go through some basic tutorials. There will be even video tutorials.

Klaus

I gone through the tutorials but still have same issue.

Generally we declare and assign variable in following way

Data type variable name = data

Example : int number = 10 or char name = 'R'

When I wrote uint8_t in program it show error

Code:
void main(void)
{  
     uint8_t T1;
}
 

When I wrote uint8_t in program it show error
So it's apparently not defined in the default include files. Which compiler are you using?
 

uint8_t is defined in stdint.h XC8 doesn't include it by default. A typical XC8 source starts with
Code:
#include < xc.h>
#include < stdint.h>
#include < stdlib.h>

Be aware of < arguments> being eaten up by the HTML parser.
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top