Итак, пишется реализация частотомера по алгоритму, приведённому здесь
Входные импульсы считаются таймером Т2, опорные - Т3. Входы IC1 IC2 T2CK - физически один пин, мэппинг с помощью PPS. IC1 захватывает Т2, IC2 захватывает T3.
Функция F_init() инициализирует переферию.
Функция F_start() запускает цикл измерения частоты.
По первому прерывнию от IC1 сохраняются пары значений F_osc_start, F_in_start и счётчики переполнения таймеров over2_start, over3_start.
Далее модули IC1 IC2 выключаются и запускается на время gate_time таймер Т5. По его прерыванию модули IC1 IC2 опять включаются, и после очередного фронта входного сигнала в прерывании IC1
сохраняются пары значений F_osc_end, F_in_end и счётчиков переполнения таймеров over2_end, over3_end. Устанавливается флаг new_data.
В main'е крутиться простейшая state machine, после установки флага new_data значение частот вычисляется функцией F_calc() и отображается на ЛСД.
CODE
main() {
F_init();
while(1)
{
switch (main_state)
{
case 0:
F_start(200);
main_state=1;
break;
case 1:
if (new_data)
{
Freq=F_calc();
LCDWriteCmd(0x01); // clear display
delay_ms(2);
if (Freq == 0)
{
LCDputstr ("NO SIGNAL");
}
else
{
sprintf(F_display, "%15f", Freq);
LCDputstr(F_display);
}
new_data=0;
main_state=0;
}
break;
}
}
F_init();
while(1)
{
switch (main_state)
{
case 0:
F_start(200);
main_state=1;
break;
case 1:
if (new_data)
{
Freq=F_calc();
LCDWriteCmd(0x01); // clear display
delay_ms(2);
if (Freq == 0)
{
LCDputstr ("NO SIGNAL");
}
else
{
sprintf(F_display, "%15f", Freq);
LCDputstr(F_display);
}
new_data=0;
main_state=0;
}
break;
}
}
CODE
void F_init(void)
{
// init timer2 for external clock
T2CONbits.TON = 0; // Disable Timer
T2CONbits.TCS = 1; // Select external clock
T2CONbits.TGATE = 0; // Disable Gated Timer mode
T2CONbits.TCKPS = 0b00; // 1:1 prescaler
T2CONbits.T32 = 0; // 16bit mode
TMR2 = 0x00; // Clear timer register
PR2=0xffff;
IPC1bits.T2IP = 6; // INT priority=6
IFS0bits.T2IF = 0; // Clear Timer1 Interrupt Flag
IEC0bits.T2IE = 1; // Enable Timer1 interrupt
// init timer 3
T3CONbits.TON = 0; // Disable Timer
T3CONbits.TCS = 0; // Select internal clock
T3CONbits.TCKPS = 0b00; // 1:1 prescaler
T3CONbits.TGATE = 0; // Disable Gated Timer mode
TMR3 = 0x00; // Clear timer register
PR3=0xffff;
IPC2bits.T3IP = 6; //INT priorty=6
IFS0bits.T3IF = 0; // Clear Timer1 Interrupt Flag
IEC0bits.T3IE = 1; // Enable Timer1 interrupt
// init timer 5 for 0.2c
T5CONbits.TON = 0; // Disable Timer
T5CONbits.TCS = 0; // Select internal clock
T5CONbits.TCKPS = 0b11; // 1:256 prescaler
T5CONbits.TGATE = 0; // Disable Gated Timer mode
TMR5 = 0x00; // Clear timer register
PR5=2879;
IPC7bits.T5IP = 4; //INT priorty=4
IFS1bits.T5IF = 0; // Clear Timer1 Interrupt Flag
IEC1bits.T5IE = 1; // Enable Timer1 interrupt
// init input capture 1 on Timer 2
IC1CONbits.ICM= 0b000; // Disable Input Capture 1 module
IC1CONbits.ICTMR= 1; // Select Timer2 as the IC2 Time base
IC1CONbits.ICI= 0b00; // Interrupt on every capture event
IPC0bits.IC1IP = 6; // Setup IC1 interrupt priority level
IFS0bits.IC1IF = 0; // Clear IC1 Interrupt Status Flag
IEC0bits.IC1IE = 1; // Enable IC1 interrupt
// init input capture 1 on Timer 3
IC2CONbits.ICM= 0b000; // Disable Input Capture 2 module
IC2CONbits.ICTMR= 0; // Select Timer3 as the IC2 Time base
IC2CONbits.ICI= 0b00; // Interrupt on every capture event - INT from IC2 DISABLED!!!
// IPC0bits.IC1IP = 6; // Setup IC1 interrupt priority level
// IFS0bits.IC1IF = 0; // Clear IC1 Interrupt Status Flag
// IEC0bits.IC1IE = 1; // Enable IC1 interrupt
gate_flag=0;
}
void F_start (unsigned int gate_time)
{
unsigned int scale;
T5CONbits.TON = 0;
scale = gate_time*(3125/(TOSC*8)) ;
TMR5 = 0x00; // Clear timer register
PR5=scale;
new_data=0;
T2_over=0; //Clear TMR2 overflow
T3_over=0; //Clear TMR3 overflow
TMR2 = 0x00; //Clear timer 2
TMR3 = 0x00; //Clear timer 3
T2CONbits.TON = 1; //Start Timer 2
T3CONbits.TON = 1; //Start Timer 3
IC1CONbits.ICM= 0b011; // Enable IC1, every rising edge
IC2CONbits.ICM= 0b011; // Enable IC2, every rising edge
}
void __attribute__((__interrupt__)) _T2Interrupt( void )
{
T2_over++ ;
IFS0bits.T2IF = 0; /* reset timer interrupt flag */
}
void __attribute__((__interrupt__)) _T3Interrupt( void )
{
T3_over++ ;
IFS0bits.T3IF = 0; /* reset timer interrupt flag */
}
void __attribute__((__interrupt__)) _T5Interrupt( void )
{
T5CONbits.TON = 0;
IC1CONbits.ICM= 0b011; //Enable IC1 , on every rising edge
IC2CONbits.ICM= 0b011; //Enable IC2 , on every rising edge
IFS1bits.T5IF = 0; /* reset timer interrupt flag */
}
// Capture Interrupt Service Routine
void __attribute__((__interrupt__)) _IC1Interrupt(void)
{
unsigned int tmp;
if (!gate_flag)
{
F_osc_start=IC2BUF;
IC2CONbits.ICM= 0b000; //Turn OFF IC2
F_in_start=IC1BUF;
IC1CONbits.ICM= 0b000; //Turn OFF IC1 module
over2_start=T2_over;
over3_start=T3_over;
while (IC1CONbits.ICBNE)
{
tmp=IC1BUF;
}
while (IC2CONbits.ICBNE)
{
tmp=IC2BUF;
}
gate_flag=1;
T5CONbits.TON = 1; //start timer5
}
else
{
F_osc_end=IC2BUF;
IC2CONbits.ICM= 0b000; //Turn OFF IC2
F_in_end=IC1BUF;
IC1CONbits.ICM= 0b000; //Turn OFF IC1 module
over2_end=T2_over;
over3_end=T3_over;
T2CONbits.TON = 0; //Stop Timer 2
T3CONbits.TON = 0; //Stop Timer 3
while (IC1CONbits.ICBNE)
{
tmp=IC1BUF;
}
while (IC2CONbits.ICBNE)
{
tmp=IC2BUF;
}
gate_flag=0;
new_data=1;
}
IFS0bits.IC1IF=0; //reset interrupt flag
}
float F_calc(void)
{
float F;
float M; //input pulse count
float N; //clock pulse count
unsigned long A1,A2 ;
A1=((unsigned long)(over2_end-over2_start))<<16;
A2=((unsigned long)(over3_end-over3_start))<<16;
M=A1+(F_in_end-F_in_start);
N=A2+(F_osc_end-F_osc_start);
if (M == 0) F=0;
else F=(OSCIL*M)/N;
return F;
}
{
// init timer2 for external clock
T2CONbits.TON = 0; // Disable Timer
T2CONbits.TCS = 1; // Select external clock
T2CONbits.TGATE = 0; // Disable Gated Timer mode
T2CONbits.TCKPS = 0b00; // 1:1 prescaler
T2CONbits.T32 = 0; // 16bit mode
TMR2 = 0x00; // Clear timer register
PR2=0xffff;
IPC1bits.T2IP = 6; // INT priority=6
IFS0bits.T2IF = 0; // Clear Timer1 Interrupt Flag
IEC0bits.T2IE = 1; // Enable Timer1 interrupt
// init timer 3
T3CONbits.TON = 0; // Disable Timer
T3CONbits.TCS = 0; // Select internal clock
T3CONbits.TCKPS = 0b00; // 1:1 prescaler
T3CONbits.TGATE = 0; // Disable Gated Timer mode
TMR3 = 0x00; // Clear timer register
PR3=0xffff;
IPC2bits.T3IP = 6; //INT priorty=6
IFS0bits.T3IF = 0; // Clear Timer1 Interrupt Flag
IEC0bits.T3IE = 1; // Enable Timer1 interrupt
// init timer 5 for 0.2c
T5CONbits.TON = 0; // Disable Timer
T5CONbits.TCS = 0; // Select internal clock
T5CONbits.TCKPS = 0b11; // 1:256 prescaler
T5CONbits.TGATE = 0; // Disable Gated Timer mode
TMR5 = 0x00; // Clear timer register
PR5=2879;
IPC7bits.T5IP = 4; //INT priorty=4
IFS1bits.T5IF = 0; // Clear Timer1 Interrupt Flag
IEC1bits.T5IE = 1; // Enable Timer1 interrupt
// init input capture 1 on Timer 2
IC1CONbits.ICM= 0b000; // Disable Input Capture 1 module
IC1CONbits.ICTMR= 1; // Select Timer2 as the IC2 Time base
IC1CONbits.ICI= 0b00; // Interrupt on every capture event
IPC0bits.IC1IP = 6; // Setup IC1 interrupt priority level
IFS0bits.IC1IF = 0; // Clear IC1 Interrupt Status Flag
IEC0bits.IC1IE = 1; // Enable IC1 interrupt
// init input capture 1 on Timer 3
IC2CONbits.ICM= 0b000; // Disable Input Capture 2 module
IC2CONbits.ICTMR= 0; // Select Timer3 as the IC2 Time base
IC2CONbits.ICI= 0b00; // Interrupt on every capture event - INT from IC2 DISABLED!!!
// IPC0bits.IC1IP = 6; // Setup IC1 interrupt priority level
// IFS0bits.IC1IF = 0; // Clear IC1 Interrupt Status Flag
// IEC0bits.IC1IE = 1; // Enable IC1 interrupt
gate_flag=0;
}
void F_start (unsigned int gate_time)
{
unsigned int scale;
T5CONbits.TON = 0;
scale = gate_time*(3125/(TOSC*8)) ;
TMR5 = 0x00; // Clear timer register
PR5=scale;
new_data=0;
T2_over=0; //Clear TMR2 overflow
T3_over=0; //Clear TMR3 overflow
TMR2 = 0x00; //Clear timer 2
TMR3 = 0x00; //Clear timer 3
T2CONbits.TON = 1; //Start Timer 2
T3CONbits.TON = 1; //Start Timer 3
IC1CONbits.ICM= 0b011; // Enable IC1, every rising edge
IC2CONbits.ICM= 0b011; // Enable IC2, every rising edge
}
void __attribute__((__interrupt__)) _T2Interrupt( void )
{
T2_over++ ;
IFS0bits.T2IF = 0; /* reset timer interrupt flag */
}
void __attribute__((__interrupt__)) _T3Interrupt( void )
{
T3_over++ ;
IFS0bits.T3IF = 0; /* reset timer interrupt flag */
}
void __attribute__((__interrupt__)) _T5Interrupt( void )
{
T5CONbits.TON = 0;
IC1CONbits.ICM= 0b011; //Enable IC1 , on every rising edge
IC2CONbits.ICM= 0b011; //Enable IC2 , on every rising edge
IFS1bits.T5IF = 0; /* reset timer interrupt flag */
}
// Capture Interrupt Service Routine
void __attribute__((__interrupt__)) _IC1Interrupt(void)
{
unsigned int tmp;
if (!gate_flag)
{
F_osc_start=IC2BUF;
IC2CONbits.ICM= 0b000; //Turn OFF IC2
F_in_start=IC1BUF;
IC1CONbits.ICM= 0b000; //Turn OFF IC1 module
over2_start=T2_over;
over3_start=T3_over;
while (IC1CONbits.ICBNE)
{
tmp=IC1BUF;
}
while (IC2CONbits.ICBNE)
{
tmp=IC2BUF;
}
gate_flag=1;
T5CONbits.TON = 1; //start timer5
}
else
{
F_osc_end=IC2BUF;
IC2CONbits.ICM= 0b000; //Turn OFF IC2
F_in_end=IC1BUF;
IC1CONbits.ICM= 0b000; //Turn OFF IC1 module
over2_end=T2_over;
over3_end=T3_over;
T2CONbits.TON = 0; //Stop Timer 2
T3CONbits.TON = 0; //Stop Timer 3
while (IC1CONbits.ICBNE)
{
tmp=IC1BUF;
}
while (IC2CONbits.ICBNE)
{
tmp=IC2BUF;
}
gate_flag=0;
new_data=1;
}
IFS0bits.IC1IF=0; //reset interrupt flag
}
float F_calc(void)
{
float F;
float M; //input pulse count
float N; //clock pulse count
unsigned long A1,A2 ;
A1=((unsigned long)(over2_end-over2_start))<<16;
A2=((unsigned long)(over3_end-over3_start))<<16;
M=A1+(F_in_end-F_in_start);
N=A2+(F_osc_end-F_osc_start);
if (M == 0) F=0;
else F=(OSCIL*M)/N;
return F;
}
Проблема заключается в том, что данный код примерно в 80% циклов выдаёт правильное значение частоты, а в 20% - таймер Т2 пропускает 1 входной импульс, причем это происходит совершенно хаотично, никакой закономерности я уловить не смог.
Уже довольно долго бьюсь с отладкой, но всё мимо. Будут ли какие-нибудь идеи о причинах такого поведения?