Continue to Site

# frequency meter resolve to 0,01Hz

Status
Not open for further replies.

#### All4U

##### Junior Member level 1
Hi all,

I want to build a frequency meter, its required as below:
-uC: Atmel or PIC;
-display: 05 of 7seg led;
-resolution: 0.01 Hz;
-range: 40 - 60 Hz;
-code in: C language;
(actually, i want to built a freg meter to measure frequency of 220Vac mains power)
Kindly give me some advice, some example,...

Thanks in front!:roll:

Hi all,

I want to build a frequency meter, its required as below:
-uC: Atmel or PIC;
-display: 05 of 7seg led;
-resolution: 0.01 Hz;
-range: 40 - 60 Hz;
-code in: C language;
(actually, i want to built a freg meter to measure frequency of 220Vac mains power)
Kindly give me some advice, some example,...

Thanks in front!:roll:

I see 37 view but not any reply...
who could help me?...hic hic

An accurate measurement can be only achieved by feeding the input signal to the hardware timer inputs intended for interval measurements respectively event capture. ATmega and most PIC processors have the option, refer to the hardware manuals.

Lowpass or bandpass filtering for interference suppression can be reasonable, a comparator should be used.

Either a simple period measurement (with about 1 MHz time base) or a more accurate multi cycle period measurement can be used to get the result in acceptable amount of time.

All4U

### All4U

Points: 2
I warmly suggest you to read the following document: **broken link removed**
as bonus, you can use the search term "reciprocal counter"

All4U

### All4U

Points: 2

I may understand what is reciprocal counter you suggested...
For example, in my case the input frequency will be around 50Hz. Time between two rising edge should be around 0,02 second, for exmple I try with 3 circle then the uC's timer will count the time around 0,06 sec. Then the the frequency should be calculated as f ~ 3/0,06 and the result will be a decimal number around 50 and it can be displayed as 50.xx Hz. Am I right?

I'm newbie...In my case, the led scanning procedure will effected on the result of measuring or not?

There are a few ways to measure the frequency.

1) use capture inputs, detect a rising edge and keep the timer count value , then capture the next rising edge which is the end of the period and store the timer count again, now if you subtract these values (you may need an timer overflow counter too depending on the time speed) you can have an accurate duration of the period given in timer counts, from that you can get an accurate frequency.

2) use two timers, one set to count the input pulses (rising or falling but one of them) and use the second timer as a gate for the first timer to measure the pulses for a specific time period, for example if you measure for 0.5sec you will get 25 counts , then multiply with two to get the counts /sec

3) it can even be done using the external interrupt to get the two edges of the period and use a timer value (like in capture mode) to calculate the frequency.

The most accurate way is the capture because the timer value is immediately stored in hardware level without any overhead

Alex

All4U

### All4U

Points: 2
I'm sorry, but I have completely not understood what you wrote!!!
Because I do not know what microprocessor you will use, I suggest you to take a look at the datasheet of your micro and to read throughly the chapters about:
- Timers (hopefully 16 bit ones)
- Timer Input Capture

Maybe a search with those terms will help: "input capture timer frequency measurement"
take a look also to this link: home

All4U

### All4U

Points: 2
I'm sorry, but I have completely not understood what you wrote!!!

Which post are you referring to ?

Alex

All4U

### All4U

Points: 2
to this one:
I may understand what is reciprocal counter you suggested...
For example, in my case the input frequency will be around 50Hz. Time between two rising edge should be around 0,02 second, for exmple I try with 3 circle then the uC's timer will count the time around 0,06 sec. Then the the frequency should be calculated as f ~ 3/0,06 and the result will be a decimal number around 50 and it can be displayed as 50.xx Hz. Am I right?

I'm newbie...In my case, the led scanning procedure will effected on the result of measuring or not?
Unfortunately my answer was posted AFTER yours: sorry for the inconvenience!!!

I'm sorry, but I have completely not understood what you wrote!!!
I think, the post is almost understandable, but the method not well considered, I think.

The microprocessor will measure the time intervall in units of it's system clock period, or a multiple of it. You can of course convert it to seconds as a float variable, but you should better try to stay with integer numbers. The other point is to decide about the intended frequency output scaling. If it's e.g. 0.01 Hz, then the f = 1/T operation can performed as a long integer division.

All4U

### All4U

Points: 2
I think, the post is almost understandable, but the method not well considered, I think.

The microprocessor will measure the time intervall in units of it's system clock period, or a multiple of it. You can of course convert it to seconds as a float variable, but you should better try to stay with integer numbers. The other point is to decide about the intended frequency output scaling. If it's e.g. 0.01 Hz, then the f = 1/T operation can performed as a long integer division.

Hi FvM,

Could your pls guide me more? You suggest me to measure the period time between two rising edge (T) and then f=1/T? Is this the same method 1) of alexan_e post?
If I use the method, then I also need the 7 segments led (4led) scanning for displaying the result. Is the scanning effected on the accurate of the measuring?

Many thanks!

Is this the same method 1) of alexan_e post?
Yes.
If I use the method, then I also need the 7 segments led (4led) scanning for displaying the result. Is the scanning effected on the accurate of the measuring?
I don't think, that the display method depends on the measurement algorithm. But anyway, if the timing measurent is implemented in hardware, e.g. using "input capture" with PICs, it won't be affected by the behaviour of other code parts. If you however use the suggested third method, interrupt latencies will reduce the measurement accuracy.

You stop display, perform input calculation, start display showing result for 1/5 sec. Repete the process. You have around 5 samples /sec readout. There is a Elektor project RPM meter for car dashboard using same techniqe.

Last edited:

Dear all,

I used Atmega32 for the project,
One more question, when I get T (ms), F=1000/T = 50.12345..... for example. How to convert F into 50.12 in this case for display it on seven segments led board?

Thanks in front!

If you have 50.12345 as a float variable, use sprintf(buf,"%5.2f", ), then extract the individual digits. Or convert to fixed point 5012, use itoa(), extract the digits. Or any other method of binary-to-decimal conversion. e.g. Double dabble - Wikipedia, the free encyclopedia

All4U

### All4U

Points: 2
Hi FvM,
i will try yours,
As I said, I'm newbie...
Here below is my code (WINAVR), note: I use event capture

#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdio.h>
#include <string.h>
#include <util/delay.h>

volatile uint32_t period=0, duty=0, pre_val=0,over_step=0;
double T,F,D, t1,t2, Scale1, Scale2 ;

void display(double F)
{
const char LedCode[10] = {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90};//7seg no decimal point
//const char LedCode1[10] = {0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10};//7seg with dec point
int a, b, c, d ; // F = ab.cd

F=F*100;
a=F/1000;
b=(F-a*1000)/100;
c=(F-a*1000-b*100)/10;
d=(F-a*1000-b*100-c*10);

//display
PORTB=0xFF;
PORTA=LedCode[a];
PORTB=0x01;
_delay_ms(10);
............................continue with scan led (but it not work)
}

int main(void){

Scale1=F_CPU/1000000; //F_CPU =16Mhz
Scale2=F_CPU/1000;

PORTA=0x00; // Clear led. Data
PORTB=0xFF; // Clear led. Control

cbi(DDRD, 6);
sbi(PORTD, 6);
TCNT1=0;
TCCR1B=(1<<CS10);
TIMSK= (1<<TICIE1)|(1<<TOIE1);
sei();

while (1){
t1=(float)period;
if(t1<Scale2)
{
T=2*t1/Scale1;
}
else
{
T=2*t1/Scale2;
}

F=1000/T;
display(F);

}
return 0;
}

ISR (TIMER1_OVF_vect ){
over_step+=0xFFFF;
}

ISR (TIMER1_CAPT_vect){
period= over_step + ICR1-pre_val;
pre_val=ICR1;
over_step=0;
}

Last edited:

Code:
F=F*100;
a=F/1000;
b=(F-a*1000)/100;
c=(F-a*1000-b*100)/10;
d=(F-a*1000-b*100-c*10);
The code is numerically correct at first sight, but very slow. Remeber that F is a double variable (single precision float should be sufficient, I guess) and the same expression is calculated multiple times. Unless your compiler is very clever (most micro compilers aren't), this creates a lot of overhead. You should refer to C type conversion rules to understand how the code is generated.

If you like to, compare the code length and execution time of your code and the below suggested one.
Code:
Fint=F*100;
a=Fint/1000;
Fint-= a*1000;
b=Fint/100;
Fint-= b*100;
c=Fint/10;
d=Fint-c*10;

All4U

### All4U

Points: 2
For what I see in your code you are using timer1 with a divider factor of 1 so it is counting at 16000000.
This is equal to a resolution of 1/16000000= 62.5ns when the resolution that you are after for 50.00-60.00Hz is about 1/6000 which is 166us.
Use a higher divider like /256 , this will give a resolution of 1/(16000000/256)=16us which is already ten times higher than you need, this will make numbers smaller and the overflow events less.

To calculate the frequency a simple division will be enough, (timer_freq*100/2)/t1
you divide with 2 because you measure for half period and multiply with 100 to get the two decimals as integers

for timer frequency of 16000000 like in your code now you just need to do 800000000/t1 to get the frequency with two decimals, for example 60Hz will result in 6000, 56.78Hz will result in 5678.

No floats variables are needed, the result is an integer

Alex

EDIT: a small mistake, you need to divide by two not multiply

All4U

### All4U

Points: 2
I can alsmost display the result now...but just in the simulator PROTEUS.
I the simulator, the led is not steady but flash one by one...I don't know how the result when I made the actual circuit...
Just have a look here:

Proteus can't work in real time so the refresh is very slow and you can actually see the multiplexing in slow motion and it even skips a few frames , that is why you see the digits turn on with no order.

To view each specific digit you can place a breakpoint in the code (in proteus) at the line where the digit turns on, then each time you press run the code will execute a loop and will stop at the breakpoint so you will see a different digit on (in sequence), you can probably do the same with the step button which is next to the run button.

Alex

Status
Not open for further replies.