реклама на сайте
подробности

 
 
2 страниц V   1 2 >  
Reply to this topicStart new topic
> Реализация частотомера обратного счёта на PIC24H, Нужна помощь
shkal
сообщение Jul 12 2011, 12:13
Сообщение #1


Местный
***

Группа: Свой
Сообщений: 281
Регистрация: 29-04-08
Из: Москва
Пользователь №: 37 149



Добрый день всем. Я попал в некоторый затык и не могу выбраться из него без посторонней помощи.
Итак, пишется реализация частотомера по алгоритму, приведённому здесь
Входные импульсы считаются таймером Т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;

}
}



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;
}



Проблема заключается в том, что данный код примерно в 80% циклов выдаёт правильное значение частоты, а в 20% - таймер Т2 пропускает 1 входной импульс, причем это происходит совершенно хаотично, никакой закономерности я уловить не смог.
Уже довольно долго бьюсь с отладкой, но всё мимо. Будут ли какие-нибудь идеи о причинах такого поведения?
Go to the top of the page
 
+Quote Post
ar__systems
сообщение Jul 12 2011, 21:43
Сообщение #2


self made
****

Группа: Свой
Сообщений: 855
Регистрация: 7-03-09
Из: Toronto, Canada
Пользователь №: 45 795



Цитата(shkal @ Jul 12 2011, 08:13) *
Добрый день всем. Я попал в некоторый затык и не могу выбраться из него без посторонней помощи.


А почему такой извращенный подход? четыре прерывания используются! Зачем опорную частоту надо заводить на пин и считать, когда от нее можно просто затактировать сам процессор?

Измеряемую частоту заведите на счетчик, и одно прерывание по Т1 - истечение периода усреднения.
Go to the top of the page
 
+Quote Post
shkal
сообщение Jul 13 2011, 06:48
Сообщение #3


Местный
***

Группа: Свой
Сообщений: 281
Регистрация: 29-04-08
Из: Москва
Пользователь №: 37 149



Цитата(ar__systems @ Jul 13 2011, 00:43) *
Зачем опорную частоту надо заводить на пин и считать, когда от нее можно просто затактировать сам процессор?
Измеряемую частоту заведите на счетчик, и одно прерывание по Т1 - истечение периода усреднения.


Опора на внешний пин не заводится, Т3 считает внутренний клок.
Вы ссылку на алгоритм посмотрели, которую я дал? Там извращенность подхода тщательно обсуждается.
Go to the top of the page
 
+Quote Post
rx3apf
сообщение Jul 13 2011, 08:21
Сообщение #4


Гуру
******

Группа: Участник
Сообщений: 3 834
Регистрация: 14-06-06
Из: Moscow, Russia
Пользователь №: 18 047



А при каких порядках входной частоты наблюдается проблема ? Всегда или только в области больших величин ? PIC24 я не знаю, а вот что до реализации на AVR из темы по ссылке - там не все так просто, хотя решение есть.
Go to the top of the page
 
+Quote Post
shkal
сообщение Jul 13 2011, 08:37
Сообщение #5


Местный
***

Группа: Свой
Сообщений: 281
Регистрация: 29-04-08
Из: Москва
Пользователь №: 37 149



При любых. Даже очень низких, хоть 1 Гц.
Тут, похоже, дело не в алгоритме. У меня есть такое впечатление, что, когда один и тот же фронт приходит и на IC1, и на таймер, который она захватывает, то
иногда сначала срабатывает таймер, а потом IC, а иногда наоборот, и зависит это от фазы входного фронта по отношению к фронту тактовой.
Go to the top of the page
 
+Quote Post
rx3apf
сообщение Jul 13 2011, 10:09
Сообщение #6


Гуру
******

Группа: Участник
Сообщений: 3 834
Регистрация: 14-06-06
Из: Moscow, Russia
Пользователь №: 18 047



Цитата(shkal @ Jul 13 2011, 12:37) *
При любых. Даже очень низких, хоть 1 Гц.
Тут, похоже, дело не в алгоритме. У меня есть такое впечатление, что, когда один и тот же фронт приходит и на IC1, и на таймер, который она захватывает, то
иногда сначала срабатывает таймер, а потом IC, а иногда наоборот, и зависит это от фазы входного фронта по отношению к фронту тактовой.

Тогда надо внимательно разглядывать, как устроена синхронизация периферии у этого семейства. А исследовать можно, заведя в качестве счетного какой-нибудь собственный сигнал (OC, PWM) через регулируемую линию задержки (интегрирующую цепочку с формирователем). Тогда можно удостовериться, что проблема в гонках. А вот можно ли обойти - надо подумать...
Go to the top of the page
 
+Quote Post
shkal
сообщение Jul 13 2011, 14:10
Сообщение #7


Местный
***

Группа: Свой
Сообщений: 281
Регистрация: 29-04-08
Из: Москва
Пользователь №: 37 149



Написал простейшую тестовую программу (инициализацию опускаю). IC1 захватывает TMR3.

CODE


int main()
{
while (1) {};
}

void __attribute__((__interrupt__)) _IC1Interrupt(void)
{
unsigned int a,b;


b=TMR3;
a=IC1BUF;
if (a==b )
{
ok1++;
}
else
{
error1++;
}
counter++;
IFS0bits.IC1IF=0; //reset interrupt flag
}



независимо от входной частоты этот код дает 75% счётчика ок и 25% счётчика error от общего числа циклов. Я в ах.... прострации wacko.gif

Сообщение отредактировал shkal - Jul 13 2011, 14:44
Go to the top of the page
 
+Quote Post
rx3apf
сообщение Jul 13 2011, 15:16
Сообщение #8


Гуру
******

Группа: Участник
Сообщений: 3 834
Регистрация: 14-06-06
Из: Moscow, Russia
Пользователь №: 18 047



Вдумчиво изучать работу схемы синхронизации. Муторно, противно, но придется...
Go to the top of the page
 
+Quote Post
shkal
сообщение Jul 13 2011, 21:23
Сообщение #9


Местный
***

Группа: Свой
Сообщений: 281
Регистрация: 29-04-08
Из: Москва
Пользователь №: 37 149



Так изучай-не изучай, повлиять на работу ея я всё равно не могу, отключить - тоже. С таймером всё более-менее понятно и оговорено в даташите - время от входного фронта до изменения состояния 0.75-1.75 цикла.
0-1 цикл - задержка синхронизации, то есть обычный Д-триггер, 0.75 цикла - сам таймер. А вот с input capture тайминги не оговариваюся. есть старый аппнот 96 года по семейству pic17, appnote где на стр.8 нарисованы тайминги работы, так как я их себе представлял (но не так, как на самом деле в pic24)
Go to the top of the page
 
+Quote Post
rx3apf
сообщение Jul 13 2011, 22:15
Сообщение #10


Гуру
******

Группа: Участник
Сообщений: 3 834
Регистрация: 14-06-06
Из: Moscow, Russia
Пользователь №: 18 047



Я бы: 1) разобрался с синхронизацией IC (в том числе для экспериментов используя регулируемую задержку импульса от какого-нибудь собственного выхода); 2) попробовал бы общую внешнюю синхронизацию, отдельной схемой. Но тут надо чесать репу, я PIC24 не знаю совершенно...

Сообщение отредактировал rx3apf - Jul 13 2011, 22:16
Go to the top of the page
 
+Quote Post
shkal
сообщение Jul 14 2011, 11:43
Сообщение #11


Местный
***

Группа: Свой
Сообщений: 281
Регистрация: 29-04-08
Из: Москва
Пользователь №: 37 149



Нашёл я ответ в документации на pic24f
Прикрепленное изображение


Note1 просто убило.
-Таймер, ты сколько импульсов сосчитал?
-Ну, сэм-восэм, не больше.
Go to the top of the page
 
+Quote Post
rx3apf
сообщение Jul 14 2011, 12:59
Сообщение #12


Гуру
******

Группа: Участник
Сообщений: 3 834
Регистрация: 14-06-06
Из: Moscow, Russia
Пользователь №: 18 047



Ну, может быть, не все так страшно, если сделать внешнюю схему синхронизации IC (половинка 74). Вот только поэкспериментировать с фазировкой. Проверять надо, конечно...
Go to the top of the page
 
+Quote Post
shkal
сообщение Jul 15 2011, 13:00
Сообщение #13


Местный
***

Группа: Свой
Сообщений: 281
Регистрация: 29-04-08
Из: Москва
Пользователь №: 37 149



Отказался в итоге от захвата таймера, считающего входную частоту. Захватываю только таймер, считающий опору, а в прерывании от IC1 просто читаю входной таймер первой командой. При высокой входной частоте этот таймер, конечно, успевает сосчитать несколько фронтов за время входа в прерывание, но, поскольку это время однинаково в начале и конце цикла измерения, то ошибка не возникает. Ессно, при такой схеме требуется , что приоритет прерывания IC1 был наивысшим.
Там есть один тонкий момент, связаный с возможностью совпадения прерывания от IC1 и прерывания от переполнения таймеров, но это вроде решаемо, тут где-то была ветка на эту тему.
Go to the top of the page
 
+Quote Post
Марк_Я
сообщение Jul 18 2011, 04:04
Сообщение #14


Частый гость
**

Группа: Свой
Сообщений: 178
Регистрация: 19-09-07
Из: М.О. г.Фрязино
Пользователь №: 30 656



Совершенно странное решение, прямо следующее из лени ТС прочитать даташит и референсный мануал на PIC24H.
Первое. Нет необходимости дважды входить в прерывание по IC. Для этого есть стек FIFO у этого модуля на 4 захвата. Ставим прерывание по 2 событиям захвата и дважды читаем буфер. Из второго чтения вычитаем первое.
Второе. Метод в том виде, в котором его применил ТС абсурден. Он имеет смысл лишь при ВНЕШНЕЙ опоре. Т.е. в этом случае частота МК не имеет значения, поскольку метод ратиометрический - одним и тем же интервалом меряется и опора и измеряемый сигнал. Если опора - это системная частота, то результат ее захвата будет КОНСТАНТОЙ. Ну какого ... ее мерять???
Третье. Модуль захвата. НИКОГДА захват не может быть асинхронным. ВСЕГДА захват происходит не фронтом сигнала, а ближайшим предыдущим (или последующим, зависит от схемотехники модуля) фронтом системной частоты. Иначе можно защелкнуть гонки фронтов таймера/счетчика.
Go to the top of the page
 
+Quote Post
shkal
сообщение Jul 20 2011, 11:30
Сообщение #15


Местный
***

Группа: Свой
Сообщений: 281
Регистрация: 29-04-08
Из: Москва
Пользователь №: 37 149



Уважаемый, читайте внимательно алгоритм по ссылке из первого поста, вы его нифига не поняли.
Go to the top of the page
 
+Quote Post

2 страниц V   1 2 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 19th July 2025 - 15:31
Рейтинг@Mail.ru


Страница сгенерированна за 0.01498 секунд с 7
ELECTRONIX ©2004-2016