hex.pp.ua

Захват частоты в STM8

Захват частоты и отслеживание её исчезновения на STM8




Захват частоты на STM8 делается довольно просто. Читаешь документацию, и пишешь нечто подобное (для таймера 1):

volatile u16 uInterruptCount = 0;

void CaptureTimerStart(void)
{ 
  TIM1_DeInit();
  
  // Канал № 1, предделитель 8, на повышении уровня сигнала
  TIM1_ICInit(TIM1_CHANNEL_1, TIM1_ICPOLARITY_RISING, 
    TIM1_ICSELECTION_DIRECTTI, TIM1_ICPSC_DIV8, 0);
  
  // Включить сброс счётчика по высокому уровню сигнала первого канала таймера № 1.
  TIM1->SMCR = 0x54;   

  // Очистка флага CC1 
  TIM1_ClearFlag(TIM1_FLAG_CC1);
  
  // Включить прерывание
  TIM1_ITConfig(TIM1_IT_CC1, ENABLE);
  
  // Включить таймер № 1
  TIM1_Cmd(ENABLE);  
}

void TIM1_CAP_COM_IRQHandler(void) interrupt 12
{  
  if (TIM1_GetITStatus(TIM1_IT_CC1))
  {
    uCaptureValue = TIM1_GetCapture1();    
    uInterruptCount++;
    TIM1_ClearITPendingBit(TIM1_IT_CC1);    
  } 
}

Всё хорошо, если есть частота — прерывание возникает, uCaptureValue обновляется, и оттуда можно брать текущую захваченную частоту. Проблема возникает тогда, когда частота пропадает. В этот момент прерывание больше не вызывается и в uCaptureValue остаётся последнее захваченное значение частоты. Остаётся оно до тех пор, пока частота снова не возникнет, хоть какая-нибудь. А если она не возникнет, последнее значение так и будет там торчать. Частоты уже нет, а в переменной значение сообщает нам, что есть. Непорядок.

Засунуть в прерывание какой-либо код, проверяющий это невозможно, ведь оно не вызывается без частоты, вообще. Поэтому код проверки я засунул в функцию GetFreq(), которая у меня в программе вызывается через одинаковые промежутки времени. За это и можно уцепиться. Можно сделать так, чтобы программа считала, что если uInterruptCount не менял своего значения, скажем, за 1000 вызовов функции GetFreq(), значит, прерывание уже достаточно долго не вызывается, следовательно частота не захватывается, её нет. В таком случае GetFreq() должна вернуть 0. Сделал я это так:

u16 GetFreq(void)
{
  u16 uResult = 0;
  static u16 uRequestCount = 0; // здесь сохраняется количество попыток дождаться возобновления частоты
  const u16 uMaxCount = 1000; // максимальная граница для предыдущей переменной
  // чтобы сравнение проходило правильно, uInterruptCount 
  // ограничен данным значением, чтобы не переполнялся  
  const u16 uMaxInterrupts = 1000; 
  static bool bWorking = false; // Признак того, что в данный момент производится захват
 
  // Было ли обновление значения?
  if (uInterruptCountOld == uInterruptCount) 
  {    
    if (bWorking)
    {      
      if (++uRequestCount < uMaxCount) 
      {
        // Без обновления некоторое время продолжаем выдавать старый результат
        uResult = (uCaptureValue > 0) ? (CLK_GetClockFreq() / uCaptureValue) : 0;
      } 
        else
      {
        // Давно не было обновления. Частота не захватывается
        uRequestCount = 0;
        bWorking = false;
      }
    } 
  } 
    else
  {
    if (uInterruptCount > uMaxInterrupts || uInterruptCountOld > uMaxInterrupts)
    {
      // Не даём счётчику переполниться
      uInterruptCountOld = 0;
      uInterruptCount = 1;
    } else
    {
      uInterruptCountOld = uInterruptCount;
    }
    
    // Обновилось значение, захват работает
    bWorking = true;    
    uRequestCount = 0;
    
    uResult = (uCaptureValue > 0) ? (CLK_GetClockFreq() / uCaptureValue) : 0;        
  }

  return uResult;  
}

Когда прерывание больше не возникает, функция ещё некоторое время выдаёт прежнее значение, в надежде, что прерывания возобновятся. Но потом она выдаёт 0. До тех пор, пока прерывание действительно не возобновится и захват частоты не начнёт работать вновь.

Ну, может и не очень изящный код, зато работает.

Ах да, чтобы получить значение захваченной частоты в Гц, нужно ещё разделить частоту микроконтроллера на захваченное значение (CLK_GetClockFreq() / uCaptureValue).



Автор: амдф
Дата: 10.11.2012


При копировании материалов хорошим тоном будет указание авторства и ссылка на сайт. По поводу рекламы обращайтесь на почту [email protected]