|
问题: 请问谁用AVR做过频率计, 我用Input Capture做的测周期, 但是发现总是不准.相差能在4%左右.实在太大了. 我的要求是最大千分之一. 不知谁做过这个,能否指点一二? 回答1:测量的频率范围是多少?如果频率不是很低,用计数法更好些。 回答2:我也准备做一个频率计,能否将你的代码参考一下?我是参加电子设计竞赛的学生,没有商业上的问题 如果你也用的是ATmega8的芯片,我十分愿意共同开发,不要报酬。 回答3:没道理啊.没道理不能用Input Capture测频测周啊. AVR的DataSheet上就说Input Capture可以用来测频的. 而且,我觉得程序应该没有什么问题, 一进Capture的中断就立即读取ICR的值,应该没错吧. 即便考虑进中断的四个时钟周期,那也只是0.5us的误差吧, 误差率应在0.5us/1ms=0.05%以下吧.(我现在只是做1KHz以下的测周) 可是误差怎么会这么大呢? 用计数器会不会好一点? 这是不是AVR本身的bug?或者是我在使用中遗漏了什么重要环节? 想了很久,改了很久,都没有什么变化. 请高手指教.
回答4:我的程序不具有什么参考价值过纯中,你好. 我的程序不具什么参考价值, 只是随手写来测试一下AVR的Input Capture和Timer的准确度. 只写了一小部分(测周), 如果你要的话,可以等我写完后交换代码看一看. 我也是参加了今年的竞赛,QQ:151018994 可以交流 回答5:发现问题了.原来是内部晶振的问题.原来是内部晶振不准. 换了外部的就好了. 只不过还是有点问题,就是精度只能到0.3%左右, 达不到0.1%的要求.:( 回答6:信号源的波形和精度能达到要求吗? 回答7:ICP的噪声抑制使用了吗? 回答8:用了噪声抑制.用了噪声抑制,信号源的精度没问题.
在低频时测量精度高(能达到5位有效数字,最后一位有时有点小变化,问题不大),100Hz以上精度就不太高,(第3位数字会变).比如844.33,测出来就变成855.21 我想不明白为什么. 我是这样测的: 1Hz-10Hz 以32us为单位进行测量.即TCCR1B=0xC4;(C表示上升沿,带噪声抑制,4表示256预分频) 10hz-100hz 以8us为单位进行测量. 100Hz-1KHz 以1us为单位进行测量.
这样测出来的数据应该都在1000-10000之间,误差率应在0.1%以下, 我这样算没错吧... 可是最后出来误差率在0.3%左右.... 有可能是什么原因呢?
回答9:被测信号作为闸门测量方法看上去好像没有问题,100Hz-1KHz 以1us为单位进行测量时数据在1000-10000之间,理论上只存在+-1误差。 你能确定信号源频率正确吗?844.33用什么测量的?要用好的频率计确认,示波器看的不准。还有信号源本身稳不稳定,精度能达到0.1%吗? 回答10:今天我也写出了频率计的基本代码。不过好像问题多多,首先一个频率自适应问题就需要大量编码,不然如果被测信号频率低的话,16位的计数器很容易就溢出了n次了。
blackthick的程序应该写了差不多了,不知道你是怎么解决的?
如果你愿意请将代码发至: ericguo@eastday.com 回答11:过纯中不好意思,我只写了测周(量程自转换)的部分, 因为这几天比较忙,所以一直没动那个程序. 我过两天写好了再跟你探讨吧.OK?
回答12:其实测频还是用CPLD做比如方便.用CPLD测又准又简单, 一个状态机就可以解决量程自转换的问题. 用单片机好像真的很麻烦, 还要一些外围的分频器之类的.:( 回答13:我的程序使用32位软计数器来解决问题最高频率<100KHz// Eric Guo writed at 2003-08-02, GPL license. #include <AVR/io.h> #include <AVR/interrupt.h> #include <AVR/signal.h> #include <stdlib.h> #include <string.h>
#include "global.h" #include "zlg7289.h"
volatile union cap_tags{ u32 l; struct {u16 i0, i1; } i; } cap_new, cap_old;
volatile u08 CAN_show;
void display_num(unsigned long num);
void mcu_init(void) { ACSR =(1<<ACBG)|(1<<ACIC)|(1<<ACIS1)|(1<<ACIS0);
TCCR1A=0x00; TCCR1B=0x81; // CLK/1 ICR1 =0; TCNT1 =0;
ASSR = 1<<AS2; // Page 99 TCCR2 = 0x05; // Div128
TIMSK =(1<<TICIE1)|(1<<TOIE1)|(1<<TOIE2); // enable capture }
SIGNAL(SIG_INPUT_CAPTURE1) { cap_old.l=cap_new.l; cap_new.i.i0=ICR1; CAN_show=1; }
SIGNAL(SIG_OVERFLOW1) { cap_new.i.i1++; CAN_show=0; }
INTERRUPT(SIG_OVERFLOW2) { while(CAN_show==0) ; if(cap_new.l>cap_old.l) { float fre; fre=F_CPU/(cap_new.l-cap_old.l); display_num( fre ); } }
int main(void) { zlg7289_reset(); mcu_init();
sei();
cap_old.l=0; cap_new.l=0; CAN_show=0;
while(1) { // let the interrupt do jobs. } return 0; }
void display_num(unsigned long num) { char zlg_line[0x10]; u08 i, j; zlg7289_disp(0, 0, ZLG7289_RESET); ultoa(num, zlg_line, 10); for(i=strlen(zlg_line)-1, j=0; i>0; i--, j++) zlg7289_disp(zlg_line[i], j, ZLG7289_TYPE0); zlg7289_disp(zlg_line[0], j, ZLG7289_TYPE0); }
// 大家以后还是用代码说话。 回答14:我现 在也正在编一个频率计的程序我用的是AT90S8515,我正在编,望各位大侠有好的建议,给我 发E-MAIL. 同时我 也正在编串口通讯和LCD控制,请各位大侠给点建议和指导。 我的 E-MAIL:wanglele615@163.com |