|
买了马老师的书,业余时间一直在研读,从中也学了不少,在此要感谢马老师!!
由于本人只会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[16] PROGMEM = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e};//common+
const unsigned char position[8] PROGMEM = {0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe};
unsigned char posit=0;
unsigned char dis_buff[8]={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 int icp_v1,icp_v2;
void display(void)
{
PORTC = 0xff;
PORTA = pgm_read_byte(&led_7[dis_buff[posit]]);
if(posit==1) PORTA &=0x7f;
PORTC = pgm_read_byte(&position[posit]);
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;
}
}
} |
|