lpc17xx обнаружение частоты прямоугольной волны с помощью опроса
Я должен прочитать 5 разных частот (прямоугольная волна) до 20 кГц, опрашивая 5 разных выводов. Я использую только одно прерывание по таймеру, на каждую 1 миллисекунду. Опрос выводов будет сделан в ISR.
Алгоритм, о котором я до сих пор думал: 1.Счетное число ВЫСОКОГО 2.Счетное число НИЗКОГО 3.Проверьте, если сумма ВЫСОКОГО + НИЗКОГО = Период времени. Этот алгоритм кажется медленным и не практичным.
Есть ли какие-либо функции фильтра, которые я мог бы использовать для проверки частоты на выводе, чтобы все, что мне нужно было сделать, это вызвать эту функцию? Любые другие алгоритмы для определения частоты были бы хороши.
Я ограничен только 1 прерыванием в моем коде (прерывание по таймеру)
1 ответ
Вы должны иметь в виду, каковы свойства входного сигнала
- поскольку вы ограничены только одним прерыванием (что довольно странно)
- и таймер имеет только 1 кГц
- входной сигнал не должен быть выше 0,5 кГц
- если сигнал с шумом, частота может легко подняться выше этого предела много раз
скорость
- Вы писали, что простой метод подсчета периодов медленный
- какой процессор и мощность ввода-вывода у вас?
- Я привык к чипам Atmel AVR32 AT32UC3, которые 2-го поколения до чипов ARM Cortex
- и у меня там около 96MIPS и 2-5 МГц pin-частота R/W без DMA или прерываний
- так что именно медленно на этом подходе?
Я хотел бы написать это с вашими ограничениями, как это (это просто псевдокод C++, не использующий вашу платформу):
const int n=5;
volatile int T[n],t[n],s[n],r[n]; // T last measured period,t counter,s what edge is waitng for?
int T0[n]={?,?,?,...?}; // periods to compare with
void main() // main process
{
int i;
for (i=0;i<n;i++) { T[i]=0; t[i]=0; s[i]=0; r[i]=0; }
// config pins
// config and start timer
for (;;) // inf loop
{
for (i=0;i<n;i++) // test all pins
if (r[i]>=2) // ignore not fully measured pins
{
r[i]=2;
if (abs(T[i]-T[0])>1) // compare +/- 1T of timer can use even bigger number then 1
// frequency of pin(i) is not as it should be
}
}
}
void ISR_timer() // timer interrupt
{
// test_out_pin=H
int i;
bool p;
for (i=0;i<n;i++)
{
p=get_pin_state(i); // just read pin as true/false H/L
t[i]++; // inc period counter
if (s[i]==0){ if ( p) s[i]=1; } // edge L->H
else { if (!p) s[i]=0; T[i]=t[i]; t=0; r[i]++; } // edge H->L
}
// test_out_pin=L
}
- Вы также можете сканировать как сравнение между последним состоянием контакта и фактическим
- это устранит необходимость
s[]
- что-то вроде
p0=p1; p1=get_pin_state(i); if ((p1)&&(p0!=p1)) { T[i]=t[i]; t[i]=0; }
- таким образом, вы также можете более легко реализовать фильтры сбоев SW
- но я думаю, что у него MCU тоже должны быть фильтры HW (как и у большинства MCU)
Как бы я сделал это без ваших странных ограничений?
- Я бы использовал внешнее прерывание
- обычно они могут быть настроены для запуска по определенному фронту сигнала
- также включая HW-фильтрацию шума
- на каждое прерывание принимайте значение внутреннего тактового счетчика процессора
- и если он не в распоряжении, то состояние таймера / счетчика
- вычитать с последним измеренным
- восстановить из переполнения, если произошло
- изменить на
s
или жеHz
если нужно - таким образом я могу сканировать контакты на MCU с тактовой частотой 30 МГц с частотой до 15 МГц (используйте это для декодера IRC)
- и да, IRC может давать вам частоты выше 1 МГц в некоторых случаях (на границе между состояниями)
- если вы хотите, чтобы соотношение также вы можете:
- есть 2 прерывания одно для положительного и второе для отрицательного края
- или используйте только один и перенастраивайте край после каждого удара (у чипов Atmel UC3L, которые я использовал некоторое время назад, были проблемы с этим из-за внутренних ошибок)
[заметки]
- важно, чтобы контакты, к которым вы обращаетесь, находились на одном и том же порту ввода-вывода
- так что вы можете прочитать их все сразу, а затем просто расшифровать контакты после
- также модуль GPIO обычно настраивается, поэтому проверьте, на какие часы он работает
- обычно есть 2 такта один для сопряжения модуля GPIO с ядром процессора
- а второй для самого GPIO, так что проверьте оба
- Вы также можете использовать DMA вместо внешнего прерывания
- если вы можете настроить чтение порта IO через DMA ... в память где-то
- тогда вы можете проверить на фоновый процесс, независимый от ввода-вывода