qq1328454800 发表于 2012-7-5 16:44:18

avr T1定时器捕获功能测评率

/*主函数*/
#include <iom16v.h>
#include <macros.h>
#include "12864.h"
#include "delay.h"

#define uint unsigned int
#define uchar unsigned char

uint Cnt1;                             //第一次捕获值
uint Cnt2;                           //第二次捕获值
uint Cnt;                   //捕获差值
uchar Flag=0;                   //捕获次数
uchar Data={0,0,0,0,0,0};//显示初值,最后一个0是结束符,方便液晶显示
void init_timer1(void)                          //初始化T/C1的输入捕获中断
{
DDRD=0x00;
PORTD=0xff;//设置D口为带上拉电阻输入       
TCCR1A = 0;//设值为普通模式
TCCR1B |= (1 << ICNC1)|(1 << CS11);///输入捕获噪声抑制使能,下降沿触发,1/8分频
TIMSK |= (1 << TICIE1);//输入捕捉中断使能
SREG=0x80;        //打开总中断
                               

}

void hz(uint i,uchar *p)               //显示处理,+48是因为液晶显示的是ASCII码
{p=i%10;//个
p=i%100/10;//十
p=i%1000/100;//百
p=i%10000/1000;//千
p=i/10000;//万

}

void main()
{
uint t;
port_init();
init_timer1();       
lcd_init();
lcd_clr();
while(1);
}


#pragma interrupt_handler timer1_capt:6
void timer1_capt(void)
{
        Cnt2=(ICR1H<<8)+ICR1L;           //cnt2存放点前捕获值
        Cnt=Cnt2-Cnt1;                           //cnt存放两次时间差
        Cnt1=Cnt2;                                   //cnt1存放上次捕获值
        Flag++;       
        if(Flag==2)
       {
        Flag=0;                                   //清除捕获标志位
        hz(Cnt,Data);                           //显示处理
        Lcd_DisplayOnenum(1,1,Data);               //显示
        Cnt=0;Cnt1=0;Cnt2=0;                //清除捕获值几捕获差值
       }
}

我用AVR16 的T1定时器的捕获功能做测频计测频率时,不能正常工作,我的外接信号是信号发生器发出的方波,当我把频率调大时12864显示的频率减小。并且显示的频率与我给的方波的频率差别很大,这个问题我弄了好久都没解决,请高手们指点一下,谢谢了!!!

thomascao 发表于 2012-7-6 00:32:54

本帖最后由 thomascao 于 2012-7-6 00:49 编辑

Cnt 你没换算成频率,是被测量频率的周期,所以你测量的频率越高,显示的值越小,换算下就好了。
另你没考虑T1溢出问题,帮你在程序里提出了。(如你测量频率周期小于(频率大于)T1溢出范围,那就不用加了)


/*主函数*/
#include <iom16v.h>
#include <macros.h>
#include "12864.h"
#include "delay.h"

#define uint unsigned int
#define uchar unsigned char

//uint Cnt1;                           //第一次捕获值
//uint Cnt2;                           //第二次捕获值
//uint Cnt;                   //捕获差值

unsigned long int Cnt1; //*************************考虑溢出,不考虑溢出可不修改
unsigned long int Cnt2; //*************************考虑溢出,不考虑溢出可不修改
unsigned long int Cnt;//**************************考虑溢出,不考虑溢出可不修改

uchar Flag_OVF=0;//****************************溢出次数计数,不考虑溢出可不修改

uchar Flag=0;                   //捕获次数
uchar Data={0,0,0,0,0,0};//显示初值,最后一个0是结束符,方便液晶显示
void init_timer1(void)                        //初始化T/C1的输入捕获中断
{
DDRD=0x00;
PORTD=0xff;//设置D口为带上拉电阻输入      
TCCR1A = 0;//设值为普通模式
TCCR1B |= (1 << ICNC1)|(1 << CS11);///输入捕获噪声抑制使能,下降沿触发,1/8分频
TIMSK |= (1 << TICIE1);//输入捕捉中断使能
TIMSK |= (1 << TOIE1);   //T1溢出中断使能,********************不考虑溢出可不修改

//SREG=0x80;      //打开总中断 *********************放到main()中,等所有初始化结束后开
                              

}

void hz(uint i,uchar *p)               //显示处理,+48是因为液晶显示的是ASCII码

{p=i%10;//个
p=i%100/10;//十
p=i%1000/100;//百
p=i%10000/1000;//千
p=i/10000;//万

}

void main()
{
uint t;
port_init();
init_timer1();      
lcd_init();
lcd_clr();
SREG=0x80;      //打开总中断**************************
while(1);
}

#pragma interrupt_handler T1_OVF:10 //T1 溢出中断
void T1_OVF (void)
{
if( Flag_OVF<?? )   //累计溢出次数,超出频率测量范围处理,自己编下******************
   {
      Flag_OVF++;
    }
else
   {
      Flag=0;                                 //清除捕获标志位
    Cnt=0;Cnt1=0;Cnt2=0;                //清除捕获值几捕获差值
    Flag_OVF=0; //溢出记数清除
    TIFR |=( 1 << ICF1 );// 清除捕获中断标记
    // 再加LCD显示 测量频率超出测量范围
   }
}


#pragma interrupt_handler timer1_capt:6
void timer1_capt(void)
{
//      Cnt2=(ICR1H<<8)+ICR1L;         //cnt2存放点前捕获值
      cnt2=(ICR1H<<8)+ICR1L+ Flag_OVF * 65536;
            Cnt=Cnt2-Cnt1;                           //cnt存放两次时间差
      //***Cnt 这你没换算成频率,这是你测量频率的周期,换算下,所以你测量的值频率越高,显示的值越小。
      //****************************************************
            Cnt1=Cnt2;                                 //cnt1存放上次捕获值
      Flag++;      
         if(Flag==2)
            {
               Flag=0;                                 //清除捕获标志位
            hz(Cnt,Data);                           //显示处理
            Lcd_DisplayOnenum(1,1,Data);               //显示
            Cnt=0;Cnt1=0;Cnt2=0;                //清除捕获值几捕获差值
            Flag_OVF=0;
                }
}

qq1328454800 发表于 2012-7-6 21:31:16

太谢谢你了,我刚学AVR对你面的寄存器用的并不熟,所以遇到好多问题,幸亏有你们这些高手,谢谢啊!!!

qq1328454800 发表于 2012-7-6 21:44:21

如果我想测正弦波的频率时,是不是要将正玄波转换成方波然后再用这种方法来测量

znsword 发表于 2012-7-6 23:46:22

qq1328454800 发表于 2012-7-6 21:44 static/image/common/back.gif
如果我想测正弦波的频率时,是不是要将正玄波转换成方波然后再用这种方法来测量 ...

模拟比较器+捕获

qq1328454800 发表于 2012-7-7 10:07:55

当我测量方波的频率上兆时第一个下降沿到来时开始计数,当第二个下降沿到来时程序就进入if(Flag==2)
            {
               Flag=0;                                 //清除捕获标志位
            hz(Cnt,Data);                           //显示处理
            Lcd_DisplayOnenum(1,1,Data);               //显示
            Cnt=0;Cnt1=0;Cnt2=0;                //清除捕获值几捕获差值
            Flag_OVF=0;
                }
的Lcd_DisplayOnenum(1,1,Data);   显示中 正在执行时,又来了一个下降沿,此时程序还会进入中断,这样不就影响lcd显示吗?

qq1328454800 发表于 2012-7-7 11:14:50

我用的是内部8M晶振,八分频,理论值测得的最大频率为1M,为什么我用着程序最大只能测35K,并且误差比较大,数据处理我用的是unsigned long int plv;
plv=1000000/i;
p=plv%10;//个
p=plv%100/10;//十
p=plv%1000/100;//百
p=plv%10000/1000;//千
p=plv/10000;//万
函数???

thomascao 发表于 2012-7-8 04:41:07

qq1328454800 发表于 2012-7-7 10:07 static/image/common/back.gif
当我测量方波的频率上兆时第一个下降沿到来时开始计数,当第二个下降沿到来时程序就进入if(Flag==2)
       ...

是个问题,不过不是你担心的问题,是测量频率不准的问题。
由于描述起来很绕,我假设你的程序经过2次捕获中断,已经测量出频率值了,你在第2次捕获中断中进行频率计算并LCD显示当前测量到的频率。
但这时又来了新的一个频率信号,这样又将产生第3个捕获中断,但注意你处理 LCD显示当前测量到的频率 的程序是在捕获中断(既第2个捕获中断)里的,
由于进入中断后,全局中断被关闭,这样第3个捕获中断将不会立即执行,程序会在显示完LCD处理完当前中断里的其他操作正常退出中断并打开全局中断,
这时才进入第3个捕获中断,这样频率测量就不准了。
处理方法是在已经测量出频率并LCD显示中断退出时将TIFR寄存器中的ICF1清零( TIFR |=(1<<ICF1 ),舍弃在计算或显示中产生的捕获中断。

#pragma interrupt_handler timer1_capt:6
void timer1_capt(void)
{
//      Cnt2=(ICR1H<<8)+ICR1L;         //cnt2存放点前捕获值
      cnt2=(ICR1H<<8)+ICR1L+ Flag_OVF * 65536;
            Cnt=Cnt2-Cnt1;                           //cnt存放两次时间差
      //***Cnt 这你没换算成频率,这是你测量频率的周期,换算下,所以你测量的值频率越高,显示的值越小。
      //****************************************************
            Cnt1=Cnt2;                                 //cnt1存放上次捕获值
      Flag++;      
         if(Flag==2)
            {
               Flag=0;                                 //清除捕获标志位
            hz(Cnt,Data);                           //显示处理
            Lcd_DisplayOnenum(1,1,Data);               //显示
            Cnt=0;Cnt1=0;Cnt2=0;                //清除捕获值几捕获差值
            Flag_OVF=0;          //清除溢出次数
            TIFR |=( 1 << ICF1 );// 清除捕获中断标记
                }
}

thomascao 发表于 2012-7-8 06:02:01

qq1328454800 发表于 2012-7-7 11:14 static/image/common/back.gif
我用的是内部8M晶振,八分频,理论值测得的最大频率为1M,为什么我用着程序最大只能测35K,并且误差比较大 ...

8M 8分频率 =1M哦
你要测量1M信号 {:sweat:}
T1那才1个数。。。。,并且你使用了噪声抑制,附加了4个系统时钟周期的延迟,所以用测周法这不行了,你用计数法吧

如定时器0.5S,计数下一共有多少个被测量信号,再换算下就可以了。

qq1328454800 发表于 2012-7-8 14:15:32

恩,谢谢啊,我在试一下

znsword 发表于 2012-7-8 14:36:31

1M的信号......液晶来得及刷新吗?

qq1328454800 发表于 2012-7-8 15:15:24

不能了,最大只能测量35K,然后把频率调大显示不变,难道用捕获功能测频率不行吗

znsword 发表于 2012-7-8 16:02:43

低频应该可以,而且准确性很高。高频的话我觉得一个要考虑液晶的刷新率,另外还要考虑时钟(毕竟中断里面的那些语句执行还是要时间的)。所有高频的话,定时器定个时间间隔,然后数脉冲数目吧。

qq1328454800 发表于 2012-7-8 17:40:47

恩,我想应该加一个分频器,把被测的信号分频

qq1328454800 发表于 2012-7-8 17:41:52

忘了谢谢了

thomascao 发表于 2012-7-8 20:49:37

qq1328454800 发表于 2012-7-8 15:15 static/image/common/back.gif
不能了,最大只能测量35K,然后把频率调大显示不变,难道用捕获功能测频率不行吗
...

低频 测周法 高频 计数法

qq1328454800 发表于 2012-7-8 21:03:03

恩,谢谢啊

竹风xu 发表于 2012-8-6 15:00:59

不错哦,正需要

guwu454 发表于 2012-12-15 22:47:42

为什我我按照这个配置进不了中断啊?

jz701209李 发表于 2012-12-16 20:31:54

路过,学习一下

糖烧熊 发表于 2013-1-5 21:29:44

{:handshake:}给力的帖子
页: [1]
查看完整版本: avr T1定时器捕获功能测评率