Генератор прямоугольных импульсов время от времени генерирует более короткий импульс.

Я использую Arduino Micro для генерации 8 прямоугольных сигналов на 8 контактах. Идея следующая: на выводе 13 идет основной прямоугольный сигнал. Он представляет собой определенный BPM (ударов в минуту). Остальные 7 контактов должны обеспечивать умножение или деление этого BPM.

Он использует таймер 1 для запуска прерывания на уровне BPM/192 (это число выбрано для облегчения умножения). Он подсчитывает эти прерывания и при необходимости меняет состояния выходов.

Похоже, что коды нормально работают для большинства делений и большинства умножений. Однако в некоторых случаях, таких как /2, время от времени появляются более короткие импульсы, которые сбивают весь тайминг.

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

Кто-нибудь знает, в чем может быть проблема?

Чтение осциллографа

int counter[8] = {0,0,0,0,0,0,0,0}; //сохраняем количество прерываний с момента последнего импульса
int trip[8] = {191,383,767,1535,3071,6143,12287,24575}; //количество прерываний, необходимых для div/mult
int outputPin[8] = {13,12,11,10,9,8,7,6};

void setup() {

  for (int x = 0; x < 8; x++){

    pinMode(outputPin[x], OUTPUT);
    digitalWrite(outputPin[x], HIGH);

  }

  cli();
  TCCR1A = 0;
  TCCR1B = 0;
  TCNT1 = 0;
  OCR1A =2602; // 16000000/(x * 8)-1
  TCCR1B |= (1 << WGM12);
  TCCR1B |= (0 << CS12) | (1 << CS11) | (0 << CS10);//пределитель 8
  TIMSK1 |= (1 << OCIE1A);
  sei();

}

void pulse(){

  for (int count = 0; count < 8; count++){

    counter[count]++;

  }

}

ISR(TIMER1_COMPA_vect){

  pulse();
}

void loop() {

  for (int y = 0; y < 8; y++){

    if(counter[y] > trip[y]){

      digitalWrite(outputPin[y],!digitalRead(outputPin[y]));
      counter[y] = 0;

    }

  }

  delayMicroseconds(100);

}

, 👍1


1 ответ


Лучший ответ:

4

Здесь есть две проблемы:

  1. На counter[] происходит гонка данных: ее можно изменить в прерывании контекст, пока он читается (или даже изменяется) основным программа.

  2. Очистка counter[y] приведет к потере тиков, если по какой-то причине (скажите какое-нибудь прерывание) вы делаете это немного поздно. Вместо этого вам следует уменьшите его на trip[channel].

Вот безопасный способ управления счетчиками:

volatile int counter[8] = {...};  // не забывайте `летучий`

// Возвращаем информацию о том, сработал ли этот канал, и обновляем счетчик.
bool tripped(int channel) {
    noInterrupts();
    bool did_trip = counter[channel] >= trip[channel];
    if (did_trip) counter[channel] -= trip[channel];
    interrupts();
    return did_trip;
}

void loop() {
    for (int y = 0; y < 8; y++)
        if (tripped(y))
            digitalWrite(outputPin[y], !digitalRead(outputPin[y]));
}

Обратите внимание, что критический раздел (раздел с отключенными прерываниями) живет внутри цикла for, а не вокруг него. Лучше иметь несколько маленьких критических секций вместо одной большой.

Редактирование 1: вам не нужна задержка. Это делает систему «более стабильной» потому что это снижает вероятность того, что в любой заданный TIMER1_COMPA прерывание, основная программа обращается к счетчикам (поскольку она потратит большую часть времени откладывает). Добавление этой задержки является своего рода решением проблемы симптомы, а не основная причина гонки данных.

Изменение 2: ответ на комментарий. Если вы хотите, чтобы квадратные волны остались при синхронизации их отношения частот должны быть целыми числами. В вашей программе это почти, но не совсем так. Например, если вы посмотрите на соотношение между первыми двумя каналами:

Канал 0: 191 прерывание на одно переключение сигнала
канал 1: 383 прерывания на переключение сигнала
соотношение: 383 ÷ 191 ≈ 2,0052

Простое решение — добавить 1 к каждому элементу массива trip (384 ÷ 192). это точно 2).

,

Я попробовал ваш код. Сами импульсы сейчас кажутся стабильными, но теперь все прямоугольные волны расходятся. Ни одна из волн теперь не синхронизируется с первой., @Janw

@Janw: см. исправленный ответ., @Edgar Bonet

Спасибо, что решили это!, @Janw