频率测量的方法常用的有测频法和测周法两种
测频法:
测频法的基本思想是让计数器累计计数1秒时间,计数结果是1秒内被测信号的脉冲数,即被测信号的频率。 当被测信号频率较高时,一般采用测频法。
测周法:
当被测信号频率较低时,为保证测量精度,常采用测周法。即先测出被测信号的周期,再换算成频率。测周法的实质是把被测信号作为闸门信号,在它的脉冲变化的时间内,用一个标准频率的信号源作为计数器的时钟脉冲。
测频法示例代码:
#include "stc32g.h"
#include"STC32G_GPIO.h"
#include "oled.h"
unsigned int F_dat = 0;
unsigned long int F_Count= 0;
void GPIO_config(void)//io配置全部设置成准双向 此为stc32库函数(根据所需配置io模式即可)
{
P0_MODE_IO_PU(GPIO_Pin_All);
P1_MODE_IO_PU(GPIO_Pin_All);
P2_MODE_IO_PU(GPIO_Pin_All);
P3_MODE_IO_PU(GPIO_Pin_All);
P4_MODE_IO_PU(GPIO_Pin_All);
P5_MODE_IO_PU(GPIO_Pin_All);
P6_MODE_IO_PU(GPIO_Pin_All);
P7_MODE_IO_PU(GPIO_Pin_All);
}
//=========================================
void Timer0Init(void) //计时 12Mhz 设置成外部脉冲输入捕获计数模式
{
AUXR &= 0x7F; //定时器时钟12T模式
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x04;
TL0 = 0x00; //设置定时初值
TH0 = 0x00; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 0; //定时器0停止计时
ET0=0;//关闭定时器0中断
}
void Timer1_Init(void) //50毫秒@12.000MHz
{
AUXR &= 0xBF; //定时器时钟12T模式
TMOD &= 0x0F; //设置定时器模式
TL1 = 0xB0; //设置定时初始值
TH1 = 0x3C; //设置定时初始值
TF1 = 0; //清除TF1标志
TR1 = 1; //定时器1开始计时
ET1 = 1; //使能定时器1中断
}
void Timer1_Isr(void) interrupt 3
{
static unsigned int count =0;
unsigned int Freq_count =0;
count++;
if(count == 20)//1s
{
count = 0;
TR0 = 0;
Freq_count = (TH0<<8)|TL0; //获取计数脉冲次数
F_dat = Freq_count; //1秒内的脉冲数就是频率
TH0 = 0;
TL0 = 0;
TR0 = 1;
}
}
void main()
{
GPIO_config();
OLED_Init();
Timer0Init();
Timer1_Init();
EA = 1;
OLED_Clear();
OLED_ShowNum(0,0,55,2,16);
while (1)
{
OLED_ShowNum(0,2,F_dat,7,16); //显示频率
}
}
测周法示例代码:
#include "stc32g.h"
#include "STC32G_GPIO.h"
#include "oled.h"
void GPIO_config(void)//io配置全部设置成准双向 此为stc32库函数(根据所需配置io模式即可)
{
P0_MODE_IO_PU(GPIO_Pin_All);
P1_MODE_IO_PU(GPIO_Pin_All);
P2_MODE_IO_PU(GPIO_Pin_All);
P3_MODE_IO_PU(GPIO_Pin_All);
P4_MODE_IO_PU(GPIO_Pin_All);
P5_MODE_IO_PU(GPIO_Pin_All);
P6_MODE_IO_PU(GPIO_Pin_All);
P7_MODE_IO_PU(GPIO_Pin_All);
}
//=========================================================
void Timer0Init(void) //计100脉冲 //16位不自动重载 上升沿下降沿捕获
{
AUXR &= 0x7F; //定时器时钟12T模式
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x04;
TL0 = (65535-100)%256; //设置定时初值
TH0 = (65535-100)/256; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0计时
ET0 = 1;
}
void Timer1_Init(void) ///500微秒@12.000MHz
{
AUXR &= 0xBF; //定时器时钟12T模式
TMOD &= 0x0F; //设置定时器模式
TL1 = 0x0C; //设置定时初始值
TH1 = 0xFE; //设置定时初始值
TF1 = 0; //清除TF1标志
TR1 = 1; //定时器1开始计时
ET1 = 1; //使能定时器1中断
}
void Timer0_Isr(void) interrupt 1 //100脉冲计数中断
{
TR0 = 0;
TR1 = 0; //停止计时
time2_new=(TH1<<8)|TL1;//获取时间
TL1 = 0x0C; //设置定时初始值
TH1 = 0xFE; //设置定时初始值
TL0 = (65536-100)%256; //设置定时初值
TH0 = (65536-100)/256; //设置定时初值
freq_temp = freq;
freq = 0;
freq_ok = 1;
TR0 = 1;
TR1 = 1; //定时器1开始计时
}
void Timer1_Isr(void) interrupt 3 //500us定时中断
{
freq++;
}
void main()
{
GPIO_config();
OLED_Init();
Timer0Init();
Timer1_Init();
EA = 1;
OLED_Clear();
while (1)
{
if(freq_ok)
{
freq_temp = (100/(((freq_temp*500)+(time2_new-65036))*0.000001))*100;// 频率=100(次数)/(多少个500us+当前时间us)*0.000001(换算成秒) *100放大100倍保留2个小数
OLED_ShowNum(50,2,freq_temp,7,16);//显示频率
freq_ok = 0;
}
}
}
经测试,测频法会丢失小数点后的精度,测周法可以获得小数点后的精度。测周法显示的频率显示是以放大100倍显示的,因此实际的频率应该除100即可,程序并未显示小数点.