测频主要有三种方法:直接测频法、周期测频法、等精度测频法。
直接测量法
- 原理:在一个单位时间t里计数被测信号的上升沿/下降沿的个数N。如t=1s,则被测信号频率为N Hz。
- 优点:过程简单,计算量少,计数的结果就是被测信号的频率
- 缺点:单位时间t的精确影响测量误差;计数个数存在±1的误差,其对低频影响较大,对高频影响较小。
- 缺点:整个测频范围内的测频精度是不同的。如闸门时间是1s时,测量100MHz的信号可达到10-8的测量精度,但测量10Hz的信号只能达到10-1的测量精度。[3]
- 适用:存在正负1误差,适合于高频
周期测频法
- 原理:测量被测信号连续两个上升沿/下降沿之间的时间间隔t,再求t的倒数。
- 或:在被测信号的一个周期里,计数标准信号的个数N,N*t(t为标准信号周期)即为被测信号的周期,1/N*t即为频率。
- 优点:测量时间快,最短只需被测信号的一个周期
- 缺点:需要求倒数/除法运算,存在误差;计数时间间隔存在±1的误差;这些误差对低频影响小,对高频影响大;当被测信号频率大于标准信号时,这种方法几乎不可以用
- 适用:适用于低频,当被测信号大于标准信号时,不适用。
等精度测频法
- 原理:对时间闸门信号用被测信号进行同步,达到减少正负1的误差。对低频信号尤其有效。
- 计算:标准时钟计数结果为Nt,频率为Fs,单位为Hz,则被测频率Ft = Fs*(Nt/Ns)
- 优点:在低频阶段比直接测频法有所改进,在测量频率比标准频率高时,精度不会提高。
使用直接测量法,利用millis()函数来实现,统计1秒钟内有多少个上升沿,由于millis单位是毫秒,所以有1毫秒的误差,如果是统计一秒会带来1Hz误差,也无法测量0.1H在的频率,当然可以通过增加时间,比如10秒钟,这样精度可以达到0.1Hz。
#include <Arduino.h>
// 定义输入引脚
const int inputPin = 4;
// 脉冲计数
volatile long pulseCount = 0;
// 开始时间
unsigned long startTime = 0;
// 结束时间
unsigned long endTime = 0;
// 中断服务函数,用于计数脉冲
void pulseCounter() {
pulseCount++;
}
void setup() {
Serial.begin(115200);
// 设置输入引脚模式
pinMode(inputPin, INPUT);
// 连接中断函数到输入引脚上升沿
attachInterrupt(digitalPinToInterrupt(inputPin), pulseCounter, RISING);
startTime = millis();
}
void loop() {
if (millis() - startTime >= 1000) {
endTime = millis();
detachInterrupt(digitalPinToInterrupt(inputPin));
float elapsedTime = (endTime - startTime) / 1000.0;
float frequency = pulseCount / elapsedTime;
Serial.println("pulseCount "+String(pulseCount));
Serial.println("elapsedTime "+String(elapsedTime));
Serial.println("frequency "+String(frequency));
pulseCount = 0;
startTime = millis();
attachInterrupt(digitalPinToInterrupt(inputPin), pulseCounter, RISING);
}
}
函数发生器的输出频率为1001.1Hz,实测1001.0Hz