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 ... в память где-то
  • тогда вы можете проверить на фоновый процесс, независимый от ввода-вывода
Другие вопросы по тегам