STM32. Быстрый частотомер. Reciprocal counter.

Кто любит RISC в жизни, заходим, не стесняемся.
Аватара пользователя
dosikus
Друг Кота
Сообщения: 3604
Зарегистрирован: Пн июл 28, 2008 22:12:01

Re: STM32. Быстрый частотомер. Reciprocal counter.

Сообщение dosikus »

Леонид Иванович писал(а): Начнем с того, что он не будет ничем хорош. Программный справляется точно так же, плюс имеем бонусы в виде свободного назначения ног, легкой переносимости кода и т.д., обо всем этом я уже писал. Есть случаи, когда аппаратное решение весьма желательно, например, при реализации 1-Wire, там критичны времена. Но тот же 1-Wire реализуется в STM32 через одно место, возмущает, что при столь развитой периферии не нашлось места нескольким аппаратным портам 1-Wire.
Все эти плюсы актуальны лишь для приверженцев софтового ногодрыга и ЛУТ.
Касательно 1wire это вообще смех.
Вам предоставлена мощнейшая периферия , своего рода конструктор - соберите из этих элементов 1wire.
Озвучу сразу - оно есть и работает (аппаратный 1wire) :

Изображение
Изображение
Реклама
Galizin
Мучитель микросхем
Сообщения: 478
Зарегистрирован: Ср окт 15, 2008 09:33:03
Откуда: Воронеж

Re: STM32. Быстрый частотомер. Reciprocal counter.

Сообщение Galizin »

alexf58 писал(а): Если использовать DMA для чтения состояния счетчика
Я не очень понял Вашу идею. Она выглядит как успеть прочитать захваченное состояние до того как пришел следующий импульс входного сигнала? По моему основные копья здесь связаны не с успеть прочитать, а сформировать нужным образом сигнал захвата. Не слишком рано, что бы прошел хотя бы 1 период входной частоты от предыдущего, и не поздно, что бы не слишком вылезти из интервала измерения и не потерять информацию, которую можно было бы померять.
Время захвата рассчитывается исходя из входной частоты, которая может меняться в широких пределах. А расчитывать может только процессор например в прерывании.
Леонид Иванович писал(а):Было бы заманчиво построить частотомер на STM32 с аналоговым интерполятором
По моему неразрешимых проблем нет. Единственно использовать его можно будет до Fref/2. Могут возникнуть задачи синхронизации внутренних счетчиков и интерполятора. Но по моему они разрешимы. Если есть желание - можно пообсуждать. Я еще пока не очень хорошо сформулировал как это должно работать для себя.
Леонид Иванович писал(а):Девиация Аллана - это всего лишь мера нестабильности частоты
Да похоже что действительно так. Я так закопался что бы узнать что это такое, что забыл зачем оно было нужно в статье. Оказывается только что бы показать что их частотомер ее измеряет.
Реклама
Аватара пользователя
Леонид Иванович
Друг Кота
Сообщения: 4779
Зарегистрирован: Сб апр 02, 2011 12:40:46
Откуда: Минск
Контактная информация:

Re: STM32. Быстрый частотомер. Reciprocal counter.

Сообщение Леонид Иванович »

dosikus писал(а):Вам предоставлена мощнейшая периферия , своего рода конструктор - соберите из этих элементов 1wire.
Я не могу собрать - не получается. Поэтому это плохая периферия, раз собрать из нее что-то могут лишь редкие люди. Для реализации 1-Wire использую UART, но их мало, если понадобится несколько портов - труба. Можно немного улучшить положение, использовав remap, но не сильно. Да и реализация на UART не такая простая. Хотелось бы проще - записал байт в регистр - он улетел по 1-Wire.
Спойлер

Код: Выделить всё

//----------------------------------------------------------------------------

//Модуль поддержки термометра DS18B20, заголовочный файл

//----------------------------------------------------------------------------

#ifndef THERM_H
#define THERM_H

//----------------------------- Константы: -----------------------------------

#define TEMP_MIN      0 //минимальная измеряемая температура, *0.1°C
#define TEMP_MAX    999 //максимальная измеряемая температура, *0.1°C
#define TEMP_FAIL -1000 //код ошибки температуры

enum OwpAct_t //коды операций на шине 1-Wire
{
  OWP_NONE,
  OWP_RESET,
  OWP_RW,
  OWP_ACT,
  OWP_READY,
  OWP_FAIL
};

//----------------------------------------------------------------------------
//--------------------- Абстрактный класс TOwpAction: ------------------------
//----------------------------------------------------------------------------

extern "C" void USART2_IRQHandler(void);

class TOwpAction
{
private:
  static char DataRd;
  friend void USART2_IRQHandler(void);
protected:
  volatile static OwpAct_t Action;
  static char BitCounter;
  static char DataWr;
  char Data;
public:
  TOwpAction(char data);
  OwpAct_t Result;
  char Value;
  virtual void Start(void) = 0;
  void Execute(void);
};

//----------------------------------------------------------------------------
//----------------------------- Класс TOwpReset: -----------------------------
//----------------------------------------------------------------------------

class TOwpReset : public TOwpAction
{
private:
public:
  TOwpReset(char data = 0xF0) : TOwpAction(data) {};
  void Start(void);
};

//----------------------------------------------------------------------------
//------------------------------- Класс TOwpRW: ------------------------------
//----------------------------------------------------------------------------

class TOwpRW : public TOwpAction
{
private:
public:
  TOwpRW(char data = 0xFF) : TOwpAction(data) {};
  void Start(void);
};

//----------------------------------------------------------------------------
//------------------------------ Класс TOwpTask: -----------------------------
//----------------------------------------------------------------------------

class TOwpTask
{
private:
  char MaxActions;
  char ActCount;
  char Index;
  OwpAct_t State;
  bool Error;
public:
  TOwpTask(char maxact);
  TOwpAction** Actions;
  void AddAction(TOwpAction *act);
  void Start(void);
  void Execute(void);
  bool Done(void);
  bool Fail(void);
};

//----------------------------------------------------------------------------
//----------------------------- Класс TTherm: --------------------------------
//----------------------------------------------------------------------------

class TTherm
{
private:
  TGpio<PORTA, PIN2> Pin_OWPO; 
  TGpio<PORTA, PIN3> Pin_OWPI; 
  TSoftTimer *ThermTimer;
  TOwpTask *OwpStartTherm;
  TOwpTask *OwpReadTherm;
  int16_t CalculateT(void);
  bool Upd;
public:
  TTherm(void);
  void Execute(void);
  bool Update(void);
  int16_t Value;
};

//----------------------------------------------------------------------------

extern TTherm *Therm;

//----------------------------------------------------------------------------

#endif

//----------------------------------------------------------------------------

//Модуль поддержки термометра DS18B20

//----------------------------------------------------------------------------

#include "main.h"
#include "therm.h"

//------------------------------ Константы: ----------------------------------

#define BR_RESET    10417 //скорость порта для формирования RESET
#define BR_TSLOT   166667 //скорость порта для формирования TIME SLOT
#define CONVERT_TM    800 //время преобразования температуры, мс

#define BRR_RESET (APB1_CLOCK + BR_RESET / 2) / BR_RESET;
#define BRR_TSLOT (APB1_CLOCK + BR_TSLOT / 2) / BR_TSLOT;

//----------------------------------------------------------------------------
//--------------------- Абстрактный класс TOwpAction: ------------------------
//----------------------------------------------------------------------------

//----------------------------- Конструктор: ---------------------------------

TOwpAction::TOwpAction(char data)
{
  Data = data;
  Result = OWP_NONE;
  Action = OWP_NONE;
}

//--------------------- Проверка завершения операции: ------------------------

void TOwpAction::Execute(void)
{
  if((Action == OWP_READY) ||
     (Action == OWP_FAIL))
  {
    Value = DataRd;
    Result = Action;
    Action = OWP_NONE;
  }
}

//-------------------------- Прерывание USART2: ------------------------------

volatile OwpAct_t TOwpAction::Action;
char TOwpAction::BitCounter;
char TOwpAction::DataRd;
char TOwpAction::DataWr;

void USART2_IRQHandler(void)
{
  //прерывание USART по завершению передачи:
  if(USART2->SR & USART_SR_TC)
  {
    //очистка флага прерывания:
    USART2->SR &= ~USART_SR_TC;
    //выполняется сброс:
    if(TOwpAction::Action == OWP_RESET)
    {
      TOwpAction::DataRd = USART2->DR;
      //импульс presence находится в одном из трех битов D4..D6:
      if(((TOwpAction::DataRd & 0x70) != 0x70) &&
         //бит D7 должен быть единичным, иначе это замыкание линии
         //на землю, а не присутствие устройства:
         ((TOwpAction::DataRd & 0x80) == 0x80))
        TOwpAction::Action = OWP_READY;
          else TOwpAction::Action = OWP_FAIL;
    }
    //выполняется чтение/запись:
    if(TOwpAction::Action == OWP_RW)
    {
      TOwpAction::DataRd >>= 1;
      //считывается бит D1 (а не D0), так как при этом момент опроса
      //лежит ближе всего к отметке 15 мкс после начала тайм-слота:
      TOwpAction::DataRd |= ((USART2->DR & 2)? 0x80 : 0x00);
      if(++TOwpAction::BitCounter < 8)
      {
        TOwpAction::DataWr >>= 1;  
        USART2->DR = (TOwpAction::DataWr & 1)? 0xFF : 0x00;
      }
      else
      {
        TOwpAction::Action = OWP_READY;
      }
    }
  }
}

//----------------------------------------------------------------------------
//---------------------------- Класс TOwpReset: ------------------------------
//----------------------------------------------------------------------------

//---------------------------- Запуск операции: ------------------------------

void TOwpReset::Start(void)
{
  DataWr = Data;
  USART2->BRR = BRR_RESET;
  USART2->DR = DataWr;
  Result = OWP_NONE;
  Action = OWP_RESET;
}

//----------------------------------------------------------------------------
//----------------------------- Класс TOwpRW: --------------------------------
//----------------------------------------------------------------------------

//---------------------------- Запуск операции: ------------------------------

void TOwpRW::Start(void)
{
  DataWr = Data;
  USART2->BRR = BRR_TSLOT;
  USART2->DR = (DataWr & 1)? 0xFF : 0x00;
  BitCounter = 0;
  Result = OWP_NONE;
  Action = OWP_RW;
}

//----------------------------------------------------------------------------
//---------------------------- Класс TOwpTask: -------------------------------
//----------------------------------------------------------------------------

//----------------------------- Конструктор: ---------------------------------

TOwpTask::TOwpTask(char maxact)
{
  MaxActions = maxact;
  Actions = new TOwpAction*[MaxActions];
  ActCount = 0;
  State = OWP_NONE;
}

//------------------------ Добавление операции: ------------------------------

void TOwpTask::AddAction(TOwpAction *act)
{
  if(ActCount < MaxActions)
    Actions[ActCount++] = act; 
}

//---------------- Запуск последовательности операций: -----------------------

void TOwpTask::Start(void)
{
  Index = 0;
  Error = 0;
  State = OWP_ACT;
  Actions[Index]->Start();
}

//-------------------- Процесс выполнения операций: --------------------------

void TOwpTask::Execute(void)
{
  if(State == OWP_ACT)
  {
    if(Actions[Index]->Result == OWP_READY)
    {
      Index++;
      if(Index == ActCount)
        State = OWP_READY;
          else Actions[Index]->Start();
    }
    else if(Actions[Index]->Result == OWP_FAIL)
    {
      Error = 1;
      State = OWP_READY;
    }
    else
    {
      Actions[Index]->Execute();
    }
  }
}

//------------ Проверка завершения последовательности операций: --------------

bool TOwpTask::Done(void)
{
  if(State == OWP_READY)
  {
    State = OWP_NONE;
    return(1);
  }
  return(0);
}

//----------------------------- Чтение ошибки: -------------------------------

bool TOwpTask::Fail(void)
{
  return(Error);
}

//----------------------------------------------------------------------------
//----------------------------- Класс TTherm: --------------------------------
//----------------------------------------------------------------------------
    
//----------------------------- Конструктор: ---------------------------------
     
TTherm::TTherm(void)
{
  //настройка портов:
  Pin_OWPO.Init(AF_OD_2M);
  Pin_OWPI.Init(IN_FLOAT);
  //настройка USART2:
  RCC->APB1ENR |= RCC_APB1ENR_USART2EN; //включение тактирования USART2
  USART2->BRR = BRR_RESET;
  //USART2->CR3 = USART_CR3_HDSEL; //работа через один пин USART2_TX (PA2)
  USART2->CR1 =
    USART_CR1_RE |   //разрешение приемника
    USART_CR1_TE |   //разрешение передатчика
    USART_CR1_TCIE | //разрешение прерывания по концу передачи
    USART_CR1_UE;    //разрешение USART2
  //настройка прерываний:
  NVIC_SetPriority(USART2_IRQn, 15);
  NVIC_EnableIRQ(USART2_IRQn);
  ThermTimer = new TSoftTimer(CONVERT_TM);
  ThermTimer->Oneshot = 1;

  OwpStartTherm = new TOwpTask(3);
  OwpStartTherm->AddAction(new TOwpReset());  //RESET
  OwpStartTherm->AddAction(new TOwpRW(0xCC)); //SKIP ROM
  OwpStartTherm->AddAction(new TOwpRW(0x44)); //START CONVERSION
  
  OwpReadTherm = new TOwpTask(5);
  OwpReadTherm->AddAction(new TOwpReset());   //RESET
  OwpReadTherm->AddAction(new TOwpRW(0xCC));  //SKIP ROM
  OwpReadTherm->AddAction(new TOwpRW(0xBE));  //READ SCRATCHPAD
  OwpReadTherm->AddAction(new TOwpRW());      //READ TL
  OwpReadTherm->AddAction(new TOwpRW());      //READ TH
                          
  Upd = 0;
  Value = TEMP_FAIL;
  OwpStartTherm->Start();          //запуск команды START                          
}

//-------------- Выполнение процесса измерения температуры: ------------------

void TTherm::Execute(void)
{
  OwpStartTherm->Execute();        //выполнение команды START
  if(OwpStartTherm->Done())        //если команда START выполнена,
    ThermTimer->Start(CONVERT_TM); //запуск таймера
  if(ThermTimer->Over())           //если интервал истек,
    OwpReadTherm->Start();         //запуск команды READ
  OwpReadTherm->Execute();         //выполнение команды READ
  if(OwpReadTherm->Done())         //если команда READ выполнена,
  {
    if((OwpStartTherm->Fail()) ||  //если ошибка,
       (OwpReadTherm->Fail()))
      Value = TEMP_FAIL;           //код ошибки температуры
        else Value = CalculateT(); //преобразование температуры
    Upd = 1;                       //установка флага обновления    
    OwpStartTherm->Start();        //запуск команды START                         
  }
}

//---------------------- Вычисление температуры: -----------------------------

int16_t TTherm::CalculateT(void)
{
  char tl = OwpReadTherm->Actions[3]->Value;
  char th = OwpReadTherm->Actions[4]->Value;
  int16_t temp = 10 * (tl | (th << 8)) / 16;
  if(temp < TEMP_MIN) temp = TEMP_MIN;
  if(temp > TEMP_MAX) temp = TEMP_MAX;
  return(temp);
}

//----------------------- Чтение флага обновления: ---------------------------

bool TTherm::Update(void)
{
  if(Upd)
  {
    Upd = 0;
    return(1);
  }
  return(0);
}

//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
Galizin писал(а):По моему неразрешимых проблем нет. Единственно использовать его можно будет до Fref/2.
Понятно, что до Fref/2, но и это не представляю, как сделать. Вот на внешней логике - представляю.
Galizin
Мучитель микросхем
Сообщения: 478
Зарегистрирован: Ср окт 15, 2008 09:33:03
Откуда: Воронеж

Re: STM32. Быстрый частотомер. Reciprocal counter.

Сообщение Galizin »

Леонид Иванович писал(а):Вот на внешней логике - представляю
Никто не говорил что без внешней логики, с использованием 1 корпуса 74ас74.
Реклама
Эиком - электронные компоненты и радиодетали
alexf58
Нашел транзистор. Понюхал.
Сообщения: 183
Зарегистрирован: Сб фев 09, 2013 23:00:23

Re: STM32. Быстрый частотомер. Reciprocal counter.

Сообщение alexf58 »

Galizin писал(а): Я не очень понял Вашу идею. Она выглядит как успеть прочитать захваченное состояние до того как пришел следующий импульс входного сигнала?
Если я правильно понял, то можно настроить DMA на срабатывание по событию таймера. В данном случае входной фронт измеряемого сигнала вызывает захват в счетчике, работающем на тактовой частоте (72 МГц) и очень хочется по возможности одновременно захватить значение счетчика входных импульсов. Прерывание - долго. Ждать в цикле - тоже. А DMA вроде за 6 тактов справится. Так что до 10 МГц проблем нет.

А чем плохо внутри асинхронно предварительно поделить входной сигнал, скажем на 4? Вроде точности не уменьшит?

А зачем вообще рассуждать, если HHIMERA все придумал? Интелектуальное упражнение. И для лучшего понимания переферии STM32.
Реклама
HHIMERA
Друг Кота
Сообщения: 4583
Зарегистрирован: Вс дек 05, 2010 06:10:34
Откуда: ЮВ

Re: STM32. Быстрый частотомер. Reciprocal counter.

Сообщение HHIMERA »

alexf58 писал(а): Если я правильно понял, то можно настроить DMA на срабатывание по событию таймера. В данном случае входной фронт измеряемого сигнала вызывает захват в счетчике, работающем на тактовой частоте (72 МГц) и очень хочется по возможности одновременно захватить значение счетчика входных импульсов.
Одновременно никак не получится...
А DMA вроде за 6 тактов справится.
Не уверен... даже сильно... надо мерять...
А чем плохо внутри асинхронно предварительно поделить входной сигнал, скажем на 4? Вроде точности не уменьшит?
В 4 раза и уменьшит...
А зачем вообще рассуждать, если HHIMERA все придумал?
Рассуждайте... не отвлекайтесь...
"Я не даю готовых решений, я заставляю думать!"(С)
Реклама
alexf58
Нашел транзистор. Понюхал.
Сообщения: 183
Зарегистрирован: Сб фев 09, 2013 23:00:23

Re: STM32. Быстрый частотомер. Reciprocal counter.

Сообщение alexf58 »

To что совсем одновременно не выйдет - понятно. Вопрос как минимизировать задержку, вернее успеть до следующего фронта. Про 6 тактов - так понял appnote. Не проверял.

Поясните подробнее, почему делитель на 4 уменьшит точность в 4 раза? Если прямой счет, то естественно так. А если мы измеряем время между N фронтов, частота входного сигнала не влияет на случайную погрешность. Мы отслеживаем не каждый фронт, а каждый четвертый. И что?
Аватара пользователя
Леонид Иванович
Друг Кота
Сообщения: 4779
Зарегистрирован: Сб апр 02, 2011 12:40:46
Откуда: Минск
Контактная информация:

Re: STM32. Быстрый частотомер. Reciprocal counter.

Сообщение Леонид Иванович »

А разве можно делать захват с асинхронным предделением?
Аватара пользователя
balmer
Это не хвост, это антенна
Сообщения: 1433
Зарегистрирован: Вс дек 02, 2012 03:13:48
Откуда: Калининград

Re: STM32. Быстрый частотомер. Reciprocal counter.

Сообщение balmer »

alexf58 писал(а):Про 6 тактов - так понял appnote.
ПЛИС так и просится для этого проекта. Маленькая, но высокочастотная 8)
HHIMERA
Друг Кота
Сообщения: 4583
Зарегистрирован: Вс дек 05, 2010 06:10:34
Откуда: ЮВ

Re: STM32. Быстрый частотомер. Reciprocal counter.

Сообщение HHIMERA »

... и коллайдер... карманный, но с перламутровыми пуговицами... :)))
"Я не даю готовых решений, я заставляю думать!"(С)
alexf58
Нашел транзистор. Понюхал.
Сообщения: 183
Зарегистрирован: Сб фев 09, 2013 23:00:23

Re: STM32. Быстрый частотомер. Reciprocal counter.

Сообщение alexf58 »

Леонид Иванович писал(а):А разве можно делать захват с асинхронным предделением?
Похоже нет. Не посмотрел внимательно. Ну да ладно, снаружи 74LV161A :)
Практического смысла по сравнению с CPLD не много конечно, но чисто умозрительно по моему делитель не ухудшит разрешения. Или я ошибаюсь?
Аватара пользователя
Леонид Иванович
Друг Кота
Сообщения: 4779
Зарегистрирован: Сб апр 02, 2011 12:40:46
Откуда: Минск
Контактная информация:

Re: STM32. Быстрый частотомер. Reciprocal counter.

Сообщение Леонид Иванович »

Делитель не ухудшит относительную погрешность измерения.
Galizin
Мучитель микросхем
Сообщения: 478
Зарегистрирован: Ср окт 15, 2008 09:33:03
Откуда: Воронеж

Re: STM32. Быстрый частотомер. Reciprocal counter.

Сообщение Galizin »

А вот если мы имеем таймер, тактируемый внешним сигналом допустим 1 герц. Один из каналов CC настроен на захват фронта (с формированием прерывания с переключением светодиода для наглядности). На вход захвата кнопкой подаем импульс(ы). Вопрос такой, будут ли синхронизированы включения светодиода с фронтами тактирующего сигнала или с фронтами кнопки? То есть захват будет происходить по фронту тактирующего внешнего сигнала, или внутреннего?

Если захват будет синхронизирован с внешним тактированием, то есть появляться только по фронту внешнего тактирующего синала счетчика, то частотомер сделать очень просто. Таймер Fref (Tref) осуществляет захват по триггеру от таймера входного сигнала (Tin). Tin тактируется измеряемым сигналом. Один из его каналов CC настроен на захват. На этот вывод подаем фронт. Таймер Tin осуществляет захват не сразу, а по фронту тактирования (это то и надо проверить), то есть входного сигнала. По этому сигналу он генерирует сигнал триггера (011: Compare Pulse - The trigger output send a positive pulse when the CC1IF flag is to be set (even if it was already high), as soon as a capture or a compare match occurred.). Номер входного периода в регистре захвата TIn. Номер выходного периода в регистре захвата Tref. Второй импульс на вход захвата - есть вторая точка.
Но что то мне кажется, что это не будет работать. Слишком просто.
HHIMERA
Друг Кота
Сообщения: 4583
Зарегистрирован: Вс дек 05, 2010 06:10:34
Откуда: ЮВ

Re: STM32. Быстрый частотомер. Reciprocal counter.

Сообщение HHIMERA »

Galizin писал(а):Вопрос такой, будут ли синхронизированы включения светодиода с фронтами тактирующего сигнала или с фронтами кнопки? То есть захват будет происходить по фронту тактирующего внешнего сигнала, или внутреннего?
От внутреннего... Все таймеры в STM32 синхронные... Отсюда и ограничения до половины тактирующей... Асинхронные есть у Микрочипа... да и то не везде... и унылые до не хочу...
"Я не даю готовых решений, я заставляю думать!"(С)
HHIMERA
Друг Кота
Сообщения: 4583
Зарегистрирован: Вс дек 05, 2010 06:10:34
Откуда: ЮВ

Re: STM32. Быстрый частотомер. Reciprocal counter.

Сообщение HHIMERA »

Кстати о птичках...
Леонид Иванович писал(а): В Вашем случае формирование интервала зависимо от входного сигнала. Я не говорю про урезание интервала измерения до целого количества входных периодов - это другое. При Вашем алгоритме могут быть грубые ошибки формирования измерительного интервала. На входе может быть все, что угодно. За первую половину интервала в TIM2->CNT может насчитаться одно, а за другую половину - другое, если частота на входе меняется. Частотомер должен показать среднюю частоту, но за фиксированный интервал, а не за какое-то неопределенное время.
Посмотрел у себя что и как творится... Вот так мы плаваем...

Код: Выделить всё

// Freq    Tin     Tpause
//-----------------------
// 0.5Hz    2s      2s
// 0.9Hz    1.1s    1.1s
// 1Hz      1s      1s
// 2Hz      1s      0.5s
// 5Hz      1s      0.2s
// 10Hz     1s      0,1s
// 100Hz    1s      0,01s
Выше 1Hz время измерения везде 1Сек. ...
"Я не даю готовых решений, я заставляю думать!"(С)
Аватара пользователя
Леонид Иванович
Друг Кота
Сообщения: 4779
Зарегистрирован: Сб апр 02, 2011 12:40:46
Откуда: Минск
Контактная информация:

Re: STM32. Быстрый частотомер. Reciprocal counter.

Сообщение Леонид Иванович »

Я имел в виду немного не то. При входном сигнале постоянной частоты нет сомнений в правильности работы алгоритма. Но сигнал на входе частотомера имеет право быть каким угодно. Скажем, пачки импульсов. Частотомер должен показать среднее значение частоты за измерительный интервал. И вот тут предложенный алгоритм может сформировать совсем неправильный измерительный интервал. Но эти проблемы встанут только при попытке допиливания алгоритма до уровня измерительного прибора.
alexf58
Нашел транзистор. Понюхал.
Сообщения: 183
Зарегистрирован: Сб фев 09, 2013 23:00:23

Re: STM32. Быстрый частотомер. Reciprocal counter.

Сообщение alexf58 »

Если я правильно понял, вместо того чтобы смотреть сколько импульсов набрали за 0.5 сек, можно посмотреть через 1 сек и в качестве конца счета использовать это N плуюс скажем 2. Тогда даже при сильно неравномерной входной частоте будет интервал близкий с 1 сек, если, конечно, частота хотя бы 10 Гц.
Galizin
Мучитель микросхем
Сообщения: 478
Зарегистрирован: Ср окт 15, 2008 09:33:03
Откуда: Воронеж

Re: STM32. Быстрый частотомер. Reciprocal counter.

Сообщение Galizin »

alexf58 писал(а):в качестве конца счета использовать это N плуюс скажем 2
Это если ограничить частоту сверху что бы таймер не успел прощелкнуть эти 2 такта пока производятся расчеты. Поэтому лучше все таки оценивать текущую частоту (кол-во импульсов) и на ее основе принимать решение о задержке. Задержка должна обеспечивать гарантированную настройку таймера за это время процессором.
alexf58
Нашел транзистор. Понюхал.
Сообщения: 183
Зарегистрирован: Сб фев 09, 2013 23:00:23

Re: STM32. Быстрый частотомер. Reciprocal counter.

Сообщение alexf58 »

Естественно в зависимости от грубо определенной частоты. Я написал "скажем 2" а не 1 именно чтобы не проскочить. Если большая частота, то хоть 100. Единственная разница с "классическим методом HHIMERA" в том, что определать ме по 1/2 интервала, а по почти полному.
Аватара пользователя
Леонид Иванович
Друг Кота
Сообщения: 4779
Зарегистрирован: Сб апр 02, 2011 12:40:46
Откуда: Минск
Контактная информация:

Re: STM32. Быстрый частотомер. Reciprocal counter.

Сообщение Леонид Иванович »

Galizin писал(а):захват будет происходить по фронту тактирующего внешнего сигнала, или внутреннего?
В микроконтроллере все внешние сигналы проходят через синхронизаторы. За редким исключением, типа сигналов счетных входов, где есть асинхронные прескалеры. В частотомере на ПЛИС у меня есть два разных клок-домена, один - опорная частота, второй - входная. При этом я не имею возможности прочитать счетчик входных импульсов "на лету", он в другом домене. Сигнал GATE должен поступать на счетчики обоих доменов, его нужно пропускать через синхронизаторы. Но, к сожалению, входная частота является нерегулярной, ее может совсем не быть, или она может быть очень низкой, полноценный двухтактовый синхронизатор мы здесь себе позволить не можем. Поэтому остается риск метастабильности. Можно было, конечно, перейти полностью в домен опорной частоты, но тогда бы наложилось ограничение для входной частоты в Fref/2, как и для микроконтроллера.
Ответить

Вернуться в «ARM»