Неточная частота и время сигнала ШИМ

У меня есть Teensy 3.2, и для его программирования я использую Arduino IDE. Я пытаюсь сгенерировать 8 импульсов частотой 40 кГц и это нужно повторять каждую секунду. Я написал 3 разных кода, и ни один из них не работает так, как я хотел. Скважность импульсов не всегда постоянна (т.е. задний фронт часто смещается по оси времени), что указывает на неточность задержки между командами analogWrite. Кажется, существует проблема с задержками, которые не являются постоянными и меняются в пределах 8 импульсов и между 8 импульсами. Эта неточность различна для трех разных кодов, но существует во всех из них. Изменение скорости процессора между 16 МГц и 120 МГц не приводит к изменению проблемы (за исключением кода 3, где NOP зависит от в теме). Есть ли способ сделать циклы более последовательными на частоте 40 кГц? Нужно ли использовать внешний таймер или генератор? На двух изображениях ниже показаны две проблемы. На первом изображении показаны различия во временных задержках и выходной частоте. Красные пунктирные линии показаны для обозначения расхождения в одном и том же импульсе при последовательных итерациях кода. На втором изображении показана повторяющаяся проблема, когда прямоугольный сигнал на самом деле не является прямоугольным и, похоже, не вызван проблемами программного обеспечения.

Изображение 1:

Изображение 2:

Написанные мной коды можно найти ниже:

Код 1:

const uint8_t pin1 = 5;
const uint8_t pin2 = 6;

void setup() {
  analogWriteFrequency(pin1, 40000);
  analogWriteFrequency(pin2, 40000);
}

void loop() {
  analogWrite(pin1,128);   //для рабочего цикла 50%
  delayMicroseconds(188);  //Для генерации 8 импульсов на заданной частоте требуется 187,5 мкс
  analogWrite(pin1,0);
  delay(1000);
}

Код 2:

const uint8_t pin1 = 5;
const uint8_t pin2 = 6;

void setup() {
  pinMode(pin1, OUTPUT);
  pinMode(pin2, OUTPUT);
}

void loop() {
  PWMSignal();
  delay(1000);
}

void PWMSignal(){
  for(int i =0; i<=8; i++){
      analogWrite(pin1, 255);
      analogWrite(pin2, 0);
      delayMicroseconds(10);
      analogWrite(pin1, 0);
      analogWrite(pin2, 255);
      delayMicroseconds(10);
      analogWrite(pin2, 0);
  }
}

Код 3:

const uint8_t pin1 = 5;
const uint8_t pin2 = 6;

// Переменная N определяет длину задержки.
// Выполнение NOP соответствует задержке 62,5 нс
// когда частота процессора равна 16 МГц.
const int N = 50;
#define NOP __asm__ __volatile__ ("nop\n\t")

void setup() {
  pinMode(pin1, OUTPUT);
  pinMode(pin2, OUTPUT);
}

void loop() {
  PWMSignal();
  delay(1000);
}

void PWMSignal(){
  for(int i =0; i<=8; i++){
      analogWrite(pin1, 255);
      analogWrite(pin2, 0);
      delayNOP();
      analogWrite(pin1, 0);
      analogWrite(pin2, 255);
      delayNOP();
      analogWrite(pin2, 0);
  }
}

void delayNOP(){
  for(int j =0; j<=N; j++){
    NOP;
  }
}

, 👍0

Обсуждение

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

Возможно, использование [IntervalTimer](https://www.pjrc.com/teensy/td_timing_IntervalTimer.html) Teensy 3.x для ручного переключения вывода (с прямой записью порта, а не digitalWrite()) даст больше надежные результаты. Подсказка: GPIOx_PTOR переключит вывод за одну операцию. «x» — это номер порта, и напишите в него (1<<p), где p — это номер контакта., @Majenko