經(jīng)過一段時間的摸索,ICP及PWM終于取得了收獲。我要做的實驗是要求ICP進行捕捉來測量脈沖的頻率,計算出的結(jié)果顯示在5位LED數(shù)碼管上,同時利用12位的PWM輸出測量結(jié)果。測量電路與以前做過的“M16頻率測量及PWM”一文的電路相同,脈沖信號輸入到T0及ICP引腳。各計數(shù)器的作用如下:
Timer0:對外部脈沖進行計數(shù),使用溢出中斷,在其中斷服務(wù)程序中對溢出次數(shù)進行計數(shù);
Timer1:ICP捕捉及PWM控制,工作在方式15,OCR1A的值定為0x0FFF,使用ICP捕捉中斷和溢出中斷。 溢出中斷服務(wù)程序中對Timer1的溢出次數(shù)進行計數(shù),ICP中斷服務(wù)程序中讀出Timer0的TCNT0及其溢出次數(shù)、Timer1的溢出次數(shù)及ICR1的值,并且允許中斷嵌套;
Timer2:工作在CTC方式,產(chǎn)生1mS的定時中斷,用于LED數(shù)碼管的動態(tài)掃描和測量閘門的控制。
在開始試驗時,由于開放的中斷比較多,其實際的響應(yīng)與我的設(shè)想存在偏差,因此測量的結(jié)果總是不穩(wěn)定,表現(xiàn)為顯示值隨機跳動比較的大。通過JTAG的觀察發(fā)現(xiàn),引起這種原因的根源在于,T0、T1及ICP的中斷可能同時觸發(fā),而根據(jù)AVR的中斷優(yōu)先級設(shè)定,ICP會搶先進入中斷,導致了ICP中斷服務(wù)程序中讀到的T0或T1的溢出值不正確,最終影響依次計算結(jié)果。當采用了中斷嵌套方式后,這個問題基本上得到了解決,出現(xiàn)異常的情況已經(jīng)無法用肉眼觀察到。
程序用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);
- }
- }
- }
復制代碼