генерировать два сдвинутых по фазе ШИМ-импульса, запускаемых внешним сигналом с частотным разделением, с помощью Arduino uno?

У меня есть импульс 4 кГц в качестве триггера, и мне нужны два сдвинутых по фазе ШИМ-выхода с разделенной частотой от arduino uno.

Теперь я управлял одним выходом ШИМ, используя следующий код:

int cnt = 0;
void setup() {
  pinMode(3, OUTPUT);
  pinMode(2, INPUT);
  attachInterrupt(digitalPinToInterrupt(2), rising_edge, RISING);
}

void loop() {

}

void rising_edge() {
  cnt = cnt + 1;
  if (cnt >= 4) {                           //divide by 8
    digitalWrite(3,(digitalRead(3)^1));
    cnt = 0;
  }
}

Как предложил Majenko♦, я попытался использовать библиотеку Timer1, но фазовый сдвиг всегда составляет 15 мкс, независимо от периода timer1.

#include <TimerOne.h>

int cnt = 0;

void setup() {
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(2, INPUT);
  Timer1.initialize(10000);
  Timer1.attachInterrupt(ISP_T1);
  attachInterrupt(digitalPinToInterrupt(2), ISP_INTx, RISING);
}

void loop() {

}

void ISP_INTx() {
  cnt = cnt + 1;
  if (cnt >= 4) {
    digitalWrite(3,(digitalRead(3)^1));
    cnt = 0;
    Timer1.start();
  }
}

void ISP_T1() {
  digitalWrite(4,(digitalRead(4)^1));
  Timer1.stop();
}

Сдвиг должен быть произвольным значением от 0 до 1 x период (зависит от делителя)

Регулируемая нагрузка предпочтительна, но не обязательна.

, 👍-1

Обсуждение

На сколько сдвинулась фаза?, @Majenko

0-1 x период, который зависит от делителя (целого числа), @7E10FC9A

Значит, вам нужен переменный фазовый сдвиг? Это усложняет задачу., @Majenko

Для этого вопроса подойдет фиксированный фазовый сдвиг. Я могу прослушивать последовательный порт в цикле и переназначать регистры позже., @7E10FC9A

Если вы можете жить с фиксированным рабочим циклом 50%, то вы можете установить Таймер 1 в режим 4 (CTC с TOP = OCR1A), перевести оба выхода в режим переключения и использовать OCR1B для управления фазовым сдвигом. Никаких прерываний, никакого участия ЦП после установки таймера. Сложная часть будет заключаться в выборе между фазовыми сдвигами φ и φ+π. В этом может помочь TCCR1C., @Edgar Bonet


2 ответа


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

1

Я думаю, что ваш первый пример очень близок. А как насчет:

int cnt = 0;
void setup() {
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(2, INPUT);
  attachInterrupt(digitalPinToInterrupt(2), rising_edge, RISING);
}

void loop() {

}

void rising_edge() {
  cnt = cnt + 1;
  if (cnt >= 4) {                           //делим на 8
    cnt = 0;
  }
  switch(cnt){
    case 0: digitalWrite(3,HIGH);break;
    case 1: digitalWrite(4,HIGH);break;
    case 2: digitalWrite(3,LOW);break;
    case 3: digitalWrite(4,LOW);break;
  }
}

При одинаковой входной частоте контакт 3 будет сдвинут по фазе на 90 градусов по отношению к контакту 4. Вы можете сделать это регулируемым, если не возражаете против большего делителя, расширив переключатель/корпус, например, до 6 или 8 шагов.

Вы можете получить больше шагов, запуская по переднему и заднему фронту (хотя это может не дать однородной фазы, если входящий ШИМ не имеет коэффициент заполнения 50%).

,

0

Если я правильно понимаю, он использует timer0 для прерывания и CPU для подсчета.

Нет, это не так. Прерывание есть прерывание. Timer0 - это таймер. На данный момент у вас есть только внешнее прерывание, запускающее ISR, которое добавляет к переменной и переключает выход.

Timer0 используется для управления millis() и delay().

Что вам нужно сделать, так это настроить таймер (не Timer0, так как он уже зарезервирован), который будет отключаться с периодом, равным разнице во времени фазового сдвига. Запустите его в вашем существующем ISR (когда выход переключен), а в ISR таймера остановите таймер и переключите второй выход (или установите его таким же, как выход 0°).

В этом вам может помочь библиотека TimerOne.

,

Но почему функции timer0 не работают с attachInterrupt?, @7E10FC9A

timer0 не имеет ничего общего с attachInterrupt., @Majenko

[ссылка](https://www.arduino.cc/reference/en/language/functions/external-interrupts/attachinterrupt/) здесь говорится: «Внутри присоединенной функции delay() не будет работать, и значение, возвращаемое millis() не будет увеличиваться»., @7E10FC9A

Это верно. ISR Timer0 не будет работать, пока работает INTx ISR. Но это не имеет никакого отношения к твоему вопросу, так почему ты спрашиваешь?, @Majenko

Я попытался настроить Timer1, но сдвиг всегда 15 мкс., @7E10FC9A