Генератор прямоугольных импульсов время от времени генерирует более короткий импульс.
Я использую 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);
}
@Janw, 👍1
1 ответ
Лучший ответ:
Здесь есть две проблемы:
На
counter[]
происходит гонка данных: ее можно изменить в прерывании контекст, пока он читается (или даже изменяется) основным программа.Очистка
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).
- TCCR1A и TCCR2A на Леонардо
- Вопрос таймера: фазовая корректировка ШИМ на определенной частоте
- Какую наименьшую продолжительность можно измерить с помощью micros()?
- Входной Режим захвата PPM сигнала
- Использование millis() и micros() внутри процедуры прерывания
- Как сделать очень долгую функцию delay(), несколько часов
- Разница между «time_t» и «DateTime»
- Получение BPM из данного кода
Я попробовал ваш код. Сами импульсы сейчас кажутся стабильными, но теперь все прямоугольные волны расходятся. Ни одна из волн теперь не синхронизируется с первой., @Janw
@Janw: см. исправленный ответ., @Edgar Bonet
Спасибо, что решили это!, @Janw