移植马潮老师实验—基于T/C1捕捉功能的可变量程频率计的设计与实验,出现奇怪问题!请高
买了马老师的书,业余时间一直在研读,从中也学了不少,在此要感谢马老师!!由于本人只会WINAVR,不会CAVR开发环境,另外有自己的学习板(非马老师的),做马老师书上的实验我都是结合自己的学习板将程序移植到WINAVR上,在做本实验时,移植时将程序稍有改动,并且外部晶振为8M(熔丝设定正确!!这个无须怀疑。),发现ICP测量显示的频率总是为实际频率的1/2,(即使完全移植马老师的实验程序并且外部晶振为4M,测量的频率也是实际的1/2),直到输入实际频率>8k后,显示频率才正确,研究了好几天没有结果,非常诡异,故请高手帮忙分析问题出在哪,若有幸能被马老师指教那更是件很高兴的事情,在此先感谢大家!!路过的看看并帮帮忙!!
贴上我移植的程序:
/*********************************************
File name : demo_11_3.c
Chip type : ATmega16
Program type : Application
Clock frequency : 8.000000 MHz
Memory model : Small
External SRAM size: 0
Data Stack size : 256
*********************************************/
#include <avr/io.h>
#include <avr/delay.h>
#include <avr/pgmspace.h>
#include <avr/signal.h>
#include <avr/interrupt.h>
const unsigned char led_7 PROGMEM = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e};//common+
const unsigned char position PROGMEM = {0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe};
unsigned char posit=0;
unsigned char dis_buff={0,0,0,0,0,0,0,0};
unsigned char f_2_d=0;
unsigned char max_icp=1;
volatile unsigned char time_2ms_ok=0,full_ok=0,icp_ok=0;
volatile unsigned char icp_n;
volatile unsigned inticp_v1,icp_v2;
void display(void)
{
PORTC = 0xff;
PORTA = pgm_read_byte(&led_7]);
if(posit==1) PORTA &=0x7f;
PORTC = pgm_read_byte(&position);
if(++posit>7) posit = 0;
}
void freq_to_disbuff(unsigned long freq_temp)
{
unsigned char i;
for(i=0;i<8;i++)
{
dis_buff=freq_temp%10;
freq_temp=freq_temp/10;
}
}
//T/C0比较匹配中断服务,2ms定时
INTERRUPT(SIG_OUTPUT_COMPARE0)
{
time_2ms_ok=1;
}
//T/C1溢出中断服务
SIGNAL(SIG_OVERFLOW1)
{
full_ok=1;
}
//T/C1输入捕捉中断服务
SIGNAL(SIG_INPUT_CAPTURE1)
{
if(icp_n>max_icp) //第N个上升沿到
{
icp_v2=ICR1;
TIMSK=(1<<OCIE0);//禁止T/C1输入捕捉和溢出中断,保持T/C0比较匹配中断服务使能
icp_ok=1;
}
else if(icp_n==0)
{
icp_v1=ICR1;//记录第一个上升沿时间
}
icp_n++;
}
int main()
{
unsigned long freq=0;
unsigned int icp_temp1=0,icp_temp2=0;
DDRA=0xFF;
DDRC=0xFF;
PORTD=(1<<PD6); //PD6(ICP)输入方式,上拉有效
//T/C1初始化
TCCR1A=0;
TCCR1B=(1<<ICES1)|(0<<CS12)|(0<<CS11)|(1<<CS00); //clk,正常计数方式,上升沿出发捕捉
ICR1=0;
//T/C0初始化
TCCR0=(1<<WGM01)|(0<<WGM00)|(0<<CS02)|(1<<CS01)|(1<<CS00);//CTC模式,64分频
TCNT0=0;
OCR0=249; //2000/(1/(8/64))=250,250-1=249; 2ms定时
TIMSK=(1<<OCIE0)|(1<<TOIE1)|(1<<TICIE1);//使能T/C0比较匹配中断、T/C1溢出中断、T/C1输入捕捉中断
sei();
while(1)
{
if(icp_ok==1)//完成一次测量
{
if(icp_v2>=icp_v1)//计算N个上升沿时钟脉冲数
icp_temp2=icp_v2-icp_v1;
else
icp_temp2=65536-icp_v1+icp_v2;
if(!((icp_v2>=icp_v1)&&(full_ok==1)))//数据有效
{
if(icp_temp2==icp_temp1) //两次个数相等,测量有效(防止干扰)
{
freq=80000000*(unsigned long)max_icp/(unsigned long)icp_temp2;//换算成频率值*10; ???为 什么理论freq=80000000*max_icp/icp_temp2;输入频率<8k,显示出的结果只为实际频率的一半????
f_2_d=1; //允许新频率送显示
if(freq>40000)
max_icp=50;//如果输入频率大于4k,设置测量捕捉周期脉冲数为50个
else
max_icp=1;//如果输入频率小于4k,设置测量捕捉周期脉冲数为1个
}
}
else //有溢出,数据无效设置测量捕捉周期脉冲数为1
max_icp=1;
icp_temp1=icp_temp2;
icp_ok=0;
icp_n=0; //开始新的一次测量
full_ok=0;//清除溢出标志
TIFR=(1<<ICF1)|(1<<TOV1); //回写标志位,清楚可能存在的输入捕捉、溢出中断标志
TIMSK|=(1<<TOIE1)|(1<<TICIE1);//恢复使能T/C1溢出中断、T/C1输入捕捉中断
}
if(time_2ms_ok==1)
{
if(f_2_d==1)
{
freq_to_disbuff(freq); //新频率送显示
f_2_d=0;
}
display();
time_2ms_ok=0;
}
}
} 没有路过的高人解答??期待!!! 问题找到结贴,是自己粗心,计第脉冲个数时 if(icp_n>max_icp) ,应该是if(icp_n>max_icp) ,汗!!!!
===============================================
还是错呀:应该是if(icp_n >= max_icp) 另外,当你使用8M系统时钟,测量转换应设置在2K,而且测量频率的下限提高到250Hz,200Hz以下频率测量不能测量了,具体你自己分析一下。 谢谢马老师回复!2楼我少打了个“=”,找到问题,心情太激动了!:),谢谢马老师为我纠正;下限频率提高,200HZ以下T/C1已经溢出了。 楼主留个联系方式,讨论下哈~!! qq:19915993 好。谢谢分享。 不!!!!!!错 回复【4楼】yqing81
-----------------------------------------------------------------------
我8M晶振时,下限频率可以到200Hz一下的啊,我计算处理是125Hz,1/125Hz=0.008s,1/8M=0.125us,
在0.008s内可以计数的个数为:0.008s/0.125us=64000<65535,所以没有溢出啊。。。
为什么要定在200Hz一下呢???
页:
[1]