программное обеспечение PLL для генерации частоты дискретизации 3,2 кГц с 1pps из GPS в Arduino - PullRequest
0 голосов
/ 06 июня 2019

Я хочу спроектировать фазовую петлю с использованием Arduino.Чтобы сгенерировать частоту дискретизации 3,2 кГц, заблокированную с 1 PPS (от GPS), для моего модуля сбора данных

тактовые частоты дискретизации, генерируемые без использования PLL, со временем смещаются.что приводит к неправильному сбору образцов.если часы выборки генерируются с использованием ФАПЧ, заблокированного с эталонной частотой (1 PPS) :: модули сбора данных в другом месте смогут собирать выборку в одно и то же время.

1 Ответ

0 голосов
/ 06 июня 2019

Вы можете сделать петлю с фазовой синхронизацией, буквально.

Вам нужно два прерывания:

  1. Сначала сработает фронт импульса на входе 1 PPS.
  2. Second будет вызываться 3200 раз в секунду, каждый раз, когда таймер переключается.

Сначала установите длительность цикла таймера до 5000 циклов ЦП.

Прерывание таймера очень просто, просто увеличивает некоторую переменную счетчика, а когда оно достигает 3200, сбрасывает его в ноль.

Односекундное импульсное прерывание действует следующим образом:

  • Если значение переменной счетчика равно нулю - это означает, что таймер работает с точной частотой - ничего не делать
  • Если значение переменной счетчика больше 0, но меньше 1600 (т.е. таймер работает быстрее, чем требуется) - увеличьте период таймера на 1
  • Если значение переменной счетчика 1600 или больше (прерывание раз в секунду происходило быстрее, чем счетчик достиг 3200), уменьшите период таймера на 1

Для первого запуска установите переменную счетчика на 0, значение таймера на 2500 (половину периода), период таймера на 5000 и дождитесь появления первого импульса, затем запустите таймер.

Пример кода может выглядеть следующим образом (при условии использования Arduino UNO и 1 PPS, подключенного к входу INT0, срабатывающего по нарастающему фронту):

volatile uint16_t counter = 0; // counter variable

ISR(TIMER1_COMPA_vect) { // Timer interrupt
  if (++counter >= 3200) counter = 0;
}

// edited: INT0_vect
ISR(INT0_vect) { // External Interrupt Request 0
  if ((TCCR1B & ((1 << CS12) | (1 << CS11) | (1 << CS10))) == 0) {
    // if timer is not running (the first pulse)
    TCCR1B = (1 << WGM12) | (1 << CS10); // Start in CTC mode, 1:1 prescaler
  } else { // Once-per-second pulse
    uint16_t cnt = counter;
    if (cnt >= 1600) { 
      uint16_t ocr_val = OCR1A - 1; // edited: uint16_t
      OCR1A = ocr_val;
      if (TCNT1 >= ocr_val) { // for the case, when OCR1A was changed below the current value of TCNT1
        TCNT1 = 0;
      }
    } else if (cnt > 0) {
      OCR1A++;
    }
  }
}


// initialization code
TCCR1A = 0; // for now timer is disabled
TCCR1B = 0;
OCR1A = 4999; // 5000 timer period
TCNT1 = 2500; // starts from the middle of the first period
TIMSK1 = (1 << OCIE1A); // allow the output compare 1 interrupt


EICRA = (1 << ISC01) | (1 << ISC00); // The rising edge of INT0 generates an interrupt request
EIMSK = (1 << INT0); // Allow int0 interruput

sei(); // Enable interrupts.

Если вы хотите, чтобы выходной сигнал генерировался на выводе OC1B, вы можете инициализировать таймер следующим образом:

TCCR1A = (1 << COM1B1) | (1 << WGM11) | (1 << WGM10); // edited: COM1B1
OCR1B = 2499; // PWM with pulse length half of the period 

DDRB |= (1 << DDB2); // edited: port initialization

и при прерывании INT0 запустите таймер следующим образом:

TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS10); // Start in FastPWM - CTC mode, 1:1 prescaler

выход должен отображаться на выводе PB2 / OC1B = вывод Arduino UNO 10

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...