|
经过一段时间的摸索,ICP及PWM终于取得了收获。我要做的实验是要求ICP进行捕捉来测量脉冲的频率,计算出的结果显示在5位LED数码管上,同时利用12位的PWM输出测量结果。测量电路与以前做过的“M16频率测量及PWM”一文的电路相同,脉冲信号输入到T0及ICP引脚。各计数器的作用如下:
Timer0:对外部脉冲进行计数,使用溢出中断,在其中断服务程序中对溢出次数进行计数;
Timer1:ICP捕捉及PWM控制,工作在方式15,OCR1A的值定为0x0FFF,使用ICP捕捉中断和溢出中断。 溢出中断服务程序中对Timer1的溢出次数进行计数,ICP中断服务程序中读出Timer0的TCNT0及其溢出次数、Timer1的溢出次数及ICR1的值,并且允许中断嵌套;
Timer2:工作在CTC方式,产生1mS的定时中断,用于LED数码管的动态扫描和测量闸门的控制。
在开始试验时,由于开放的中断比较多,其实际的响应与我的设想存在偏差,因此测量的结果总是不稳定,表现为显示值随机跳动比较的大。通过JTAG的观察发现,引起这种原因的根源在于,T0、T1及ICP的中断可能同时触发,而根据AVR的中断优先级设定,ICP会抢先进入中断,导致了ICP中断服务程序中读到的T0或T1的溢出值不正确,最终影响依次计算结果。当采用了中断嵌套方式后,这个问题基本上得到了解决,出现异常的情况已经无法用肉眼观察到。
程序用CVAVR编写,源码如下:
/*********************************************
This program was produced by the
CodeWizardAVR V1.23.8d Professional
Automatic Program Generator
?Copyright 1998-2003 HP InfoTech s.r.l.
http://www.hpinfotech.ro
e-mail:office@hpinfotech.ro
Project :
Version :
Date : 2005-5-23
Author : Bucker
Company :
Comments:
Chip type : ATmega16L
Program type : Application
Clock frequency : 8.000000 MHz
Memory model : Small
External SRAM size : 0
Data Stack size : 256
*********************************************/
#include <mega16.h>
#include <sbit.h>
#define EnableICP 10
flash char LedDat[]={/*0,1,2,3,4,5,6,7,8,9,A,b,C,d,E,F,-,*/
0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x58,0x5E,0x79,0x71,0x40};
unsigned char LED[6],Status=0,Time0H,Time0L,Timer0H=0;
unsigned int Timer1H=0,Time1H,Time1L,Na=0;
// Timer 0 overflow interrupt service routine
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
// Place your code here
Timer0H++;
}
// Timer 1 overflow interrupt service routine
interrupt [TIM1_OVF] void OldTimer1_ovf_isr(void)
{
// Place your code here
Timer1H++;
}
#pragma savereg-
// Timer 1 input capture interrupt service routine
interrupt [TIM1_CAPT] void OldTimer1_capt_isr(void)
{
// Place your code here
unsigned char sREG;
#asm("sei")
#asm("st -y,r30")
sREG=SREG;
Time0L=TCNT0;
Time1L=ICR1;
Time1H=Timer1H;
Time0H=Timer0H;
BitSet(Status,0);
BitClr(TIMSK,5);
Na=0;
SREG=sREG;
#asm("ld r30,y+")
}
#pragma savereg+
// Timer 2 output compare interrupt service routine
interrupt [TIM2_COMP] void timer2_comp_isr(void)
{
// Place your code here
static char Nb=0;
#asm("sei")
if (Nb<5)
{
PORTA=LED[Nb];
PORTD&=0xF8;
PORTD|=Nb;
}
else PORTA=0x00;
if (++Nb>10) Nb=0;
if (Na<60000)
{
if (Na++>EnableICP)
{
BitSet(TIFR,5);
BitSet(TIMSK,5);
}
}
}
// Declare your global variables here
void main(void)
{
// Declare your local variables here
unsigned int a,b=0,OldTimer0,Timer0;
unsigned long L,OldTimer1,Timer1,Temp1,Temp0;
// Input/Output Ports initialization
// Port A initialization
// Func0=Out Func1=Out Func2=Out Func3=Out Func4=Out Func5=Out Func6=Out Func7=Out
// State0=0 State1=0 State2=0 State3=0 State4=0 State5=0 State6=0 State7=0
PORTA=0x00;
DDRA=0xFF;
// Port B initialization
// Func0=In Func1=In Func2=In Func3=In Func4=In Func5=In Func6=In Func7=In
// State0=T State1=T State2=T State3=T State4=T State5=T State6=T State7=T
PORTB=0x00;
DDRB=0x00;
// Port C initialization
// Func0=In Func1=In Func2=In Func3=In Func4=In Func5=In Func6=In Func7=In
// State0=T State1=T State2=T State3=T State4=T State5=T State6=T State7=T
PORTC=0x00;
DDRC=0x00;
// Port D initialization
// Func0=Out Func1=Out Func2=Out Func3=In Func4=Out Func5=In Func6=In Func7=In
// State0=0 State1=0 State2=0 State3=T State4=T State5=T State6=T State7=T
PORTD=0x00;
DDRD=0x07;
// Timer/Counter 0 initialization
// Clock source: T0 pin Rising Edge
// Mode: Normal top=FFh
// OC0 output: Disconnected
TCCR0=0x07;
TCNT0=0x00;
OCR0=0x00;
// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: 8000.000 kHz
// Mode: Fast PWM top=OCR1A
// OC1A output: Discon.
// OC1B output: Non-Inv.
// Noise Canceler: Off
// Input Capture on Falling Edge
TCCR1A=0x23;
TCCR1B=0x19;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x0F;
OCR1AL=0xFF;
OCR1BH=0x00;
OCR1BL=0x00;
// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: 250.000 kHz
// Mode: CTC top=OCR2
// OC2 output: Disconnected
ASSR=0x00;
TCCR2=0x0B;
TCNT2=0x00;
OCR2=0xF9;
// External Interrupt(s) initialization
// INT0: Off
// INT1: Off
// INT2: Off
MCUCR=0x00;
MCUCSR=0x00;
// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0xA5;
// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
// Analog Comparator Output: Off
ACSR=0x80;
SFIOR=0x00;
// Global enable interrupts
#asm("sei")
while (1)
{
// Place your code here
if (BitTst(Status,0))
{
Timer0=Time0L|(unsigned int)Time0H<<8;
Timer1=Time1L|(unsigned long)Time1H<<16;
L=8e6/59986*60000/(Temp1=(Timer1-OldTimer1))*(Temp0=(Timer0-OldTimer0));
if (L/10!=9932)
{
if (b++>2)
{
PORTA=0x00;
b=0;
}
}
OldTimer1=Timer1;
OldTimer0=Timer0;
LED[0]=LedDat[L/10000];
a=L % 10000;
LED[1]=LedDat[a/1000];
a%=1000;
LED[2]=LedDat[a/100];
a%=100;
LED[3]=LedDat[a/10];
LED[4]=LedDat[a % 10] | 0x80;
BitClr(Status,0);
}
}
}
原理图可参考点击此处打开armok0150871.pdf
-----此内容被bucker于2005-05-28,11:07:16编辑过 |
|