Нужен сигнал ШИМ частотой 10 кГц от контактов 3 и 11 с использованием таймера 2.

Работа контакта 11 должна быть инверсной по отношению к контакту 3. Я использовал цифровое чтение и цифровую запись, а также простой, если еще. Но задержка составляет 10 мкс. Что мне делать?

Я нашел этот код на форуме, но он имеет форму таймера 1. Он мне нужен для таймера 2.

void setup()
  {
  // Определение PB1 и PB2 как выходов путем установки PORTB1 и PORTB2
  // Установка DDB1 и DDB2
  DDRB |= bit (DDB1) | bit (DDB2);

  // остановка таймера 1
  TCCR1A = 0;
  TCCR1B = 0;

  TCCR1A = bit (COM1B0) | bit (COM1B1)  // Устанавливаем OC1B при сравнении, очищаем
                                        // OC1B внизу (режим инвертирования)
         | bit (COM1A1)                 // Очистить OC1A при сравнении, установить
                                        // OC1A внизу (неинвертирующий режим)
         | bit (WGM11);                 // Быстрый ШИМ, максимум на ICR1
  TCCR1B = bit (WGM12)  | bit (WGM13)   // то же самое
         | bit (CS11);                  // Запускаем таймер, прескалер 8

  // Инициализируем OCR1A = 300 (pulse_width = 150 мкс), OCR1B и ICR1
  ICR1 = 0xFFFF;
  OCR1B = 299;
  OCR1A = ICR1 - OCR1B;

  }  // конец настройки

void loop()
  {
  }

, 👍-1

Обсуждение

Что мне делать? ... использовать инвертор, @jsotola

В режиме быстрого ШИМ на таймере 2 контакт 11 использовать нельзя. Только контакт 3. См.: https://forum.arduino.cc/t/atmega328p-timer2-fastpwm-mode/499500. Если вам нужен инверсный контакт 3, то можно использовать простой инвертор (скажем, транзистор), как предложил @jsotola., @6v6gt

а какая у тебя ардуино?, @Juraj

Я использую ардуино ООН, @Pranav Pillai


2 ответа


3

Вы не сможете сделать это с Таймером 2 без внешнего оборудования. Этот код будет генерировать сигнал частотой 10 кГц на выводе 3, однако для этого он использует оба регистра таймера:

  • OCR2A используется для установки периода (т. е. частоты)
  • OCR2B используется для установки рабочего цикла.

const byte OUTPUT_PIN = 3;  // Таймер 2 "B" выход: OC2B

const byte n = 199;  // 10 кГц

void setup()
 {
  pinMode (OUTPUT_PIN, OUTPUT);

  TCCR2A = bit (WGM20) | bit (WGM21) | bit (COM2B1); // быстрый ШИМ, очистка OC2A при сравнении
  TCCR2B = bit (WGM22) | bit (CS21);         // быстрый ШИМ, прескалер 8
  OCR2A =  n;                                // период
  OCR2B = ((n + 1) / 2) - 1;                 // рабочий цикл 50%
  }  // конец настройки

void loop() { }
,

Обратите внимание, что сигнал с коэффициентом заполнения 50% может генерироваться в режиме CTC, при этом выходы настроены на «переключение на совпадение сравнения»., @Edgar Bonet

и вот, для полноты картины, NPN-транзистор, настроенный как инвертор (НЕ затвор) https://www.tutorialspoint.com/build-an-inverter-with-a-transistor, @6v6gt

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

Вы пытались написать бит «Принудительное сравнение вывода»?, @Edgar Bonet

@EdgarBonet Это, похоже, ни на что не влияет. Согласно техническому описанию, эффект возникает только при записи в этот бит, а не на постоянной основе. В моем тестировании в режиме CTC to OCR2A (010) два выхода не совпадают по фазе, но не инверсны друг другу. Фактически, они, похоже, на 50% не совпадают по фазе друг с другом (по какой-то причине). В режиме 101 (PWM to OCR2A) я не получаю выходного сигнала (т. е. 0 В) на выходе B (D3)., @Nick Gammon

А при этом: TCCR2A = бит (WGM20) | бит (WGM21) | бит (COM2A0) | бит (COM2B0) | бит (COM2B1); и TCCR2B = бит (CS21) | бит (WGM22); выход B совпадает по фазе с выходом A, но имеет удвоенную частоту., @Nick Gammon


2

Как пояснил в ответе Ник Гэммон, на самом деле невозможно сгенерировать два ШИМ сигналы с частотой 10 кГц от Таймера 2: регистр OCR2A будет используется для установки частоты, и у вас не будет независимого управления рабочий цикл выхода OC2A.

Однако вы можете создать два дополнительных сигнала по 10 кГц с коэффициентом заполнения 50%. цикл. Это не совсем ШИМ (широтно-импульсная модуляция), так как вы не можете на самом деле модулировать ширину импульса. Если это соответствует вашим потребностям, Решение — настроить выходы в режиме переключения. Написание Бит «принудительное сравнение выходных данных B» создает дополнительный переключатель OC2B, который гарантирует, что выходы будут иметь противоположные фазы. Вот код для сделайте это:

void setup() {
    TCCR2B = 0;           // остановить Таймер 2
    TCNT2  = 0;           // сбросить таймер
    TCCR2A = _BV(COM2A0)  // переключить OC2A при сравнении совпадений
           | _BV(COM2B0)  // переключить OC2B при сравнении совпадений
           | _BV(WGM21);  // режим 2 = CTC, TOP = OCRA
    OCR2A  = 99;          // период таймера = 100 * 2 * 8 / C_CPU
    OCR2B  = 99;          // одновременное переключение OC2A и OC2B
    TCCR2B = _BV(CS21)    // тактовая частота @ F_CPU/8
           | _BV(FOC2B);  // принудительное сравнение выходного сигнала B: инвертирование сигнала OC2B
    DDRB  |= _BV(PB3);    // OC2A = PB3 = цифровой 11 как выход
    DDRD  |= _BV(PD3);    // OC2B = PD3 = цифровой 3 как выход
}

void loop(){}
,

Поздравляю! У вас получилось! Как вы сказали, рабочий цикл ограничен 50%, но, как мне кажется, автор этого и хотел., @Nick Gammon

Если кому-то интересно, _BV и bit практически идентичны. В hardware/arduino/avr/cores/arduino/Arduino.h bit определяется следующим образом: #define bit(b) (1UL << (b)), а в hardware/tools/avr/avr/include/avr/sfr_defs.h _BV определяется следующим образом: #define _BV(bit) (1 << (bit))., @Nick Gammon