16-битный ШИМ на Nano Every

Мне нужно управлять светодиодной лентой через модуль MOSFET. Для работы в условиях очень слабой освещенности модулю требуется ШИМ высокого разрешения. Как мне установить для моего вывода 16-битное разрешение ШИМ на Arduino Nano Every?

, 👍1


2 ответа


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

4

Возможно, что для D5 (TCA0-WO2) + D9 (TCA0-WO0) + D10 (TCA0-WO1) все три из них будут 16-битными, если вы измените верхнее значение TCA0, но вы не сможете использовать аналоговую запись.

р>
void setup() {
  // период изменения TCA0 (уже настроен и запущен ядром Arduino)
  TCA0.SINGLE.PER = 0xFFFF; // меняем верхнее значение с 255 на 65535

  // устанавливаем значение ШИМ D9 (канал 0)
  TCA0.SINGLE.CMP0 = 0; // Начальное значение
  // включаем выход ШИМ (требуется только один раз при настройке)
  pinMode(9, OUTPUT); // установка вывода как выход
  TCA0.SINGLE.CTRLB |= TCA_SINGLE_CMP0EN_bm; // включаем ШИМ->контакт

  // Д5
  TCA0.SINGLE.CMP2 = 1; // Начальное значение
  pinMode(5, OUTPUT);
  TCA0.SINGLE.CTRLB |= TCA_SINGLE_CMP2EN_bm;

  // Д10
  TCA0.SINGLE.CMP1 = 65530; // Начальное значение
  pinMode(10, OUTPUT);
  TCA0.SINGLE.CTRLB |= TCA_SINGLE_CMP1EN_bm;
}

и в коде вы будете использовать только TCA0.SINGLE.CMPn = val; где n равно 0..2

(не проверялось, но должно работать)

РЕДАКТИРОВАТЬ: я забыл, что период будет 3,8 Гц, поэтому вам также нужно будет изменить прескалер TCA0 или использовать меньшую точность, например 10b или около того. Изменение прескаллера приведет к испорчению всех периодов счетчиков TCB, а также периода, используемого для счетчика миллис, поэтому вам также придется изменить его.

EDIT2: для классического UNO/nano это будет выглядеть так:

TCCR1B = 0; // останавливаем таймер

ICR1  = 0xFFFF; // f = 16 МГц / (2*N*ICR1) = 16 МГц / (2*65536) => ~122 Гц
OCR1A = 1;             // PB2 -> D9 (значение ШИМ)
TCCR1A = _BV(COM1A1);  // включаем выход ШИМ на PB2
TCCR1B = _BV(WGM13) | _BV(CS10);  // mode=8 (фаза и частота правильные, ICR1 вверху) и запускаем таймер с предварительным вызовом /1
,

Спасибо за подробный код. Попробую на днях. Я использовал функцию AnalogWrite на Uno, которая записывала uint16_t в OCR1A (контакт 9). Это все еще то же самое?, @awado

Нет, у классического uno/nano (с Atmega328) другие настройки таймера1 - но с другой стороны у него независимый прескалер, так что ничего не сломаешь., @KIIV

@awado добавил изменения для классического uno (pinMode опущен), @KIIV


0

Ещё раз спасибо за помощь КИЕВ. Я могу подтвердить, что это работает. Это пример ШИМ при слабом освещении для светодиода на контакте 10. Возможно, это поможет другим.

int brightness = 0;  // насколько яркий светодиод
int fadeAmount = 1;  // на сколько пунктов затухать светодиод

void setup() {
  TCA0.SINGLE.PER = 0x4000;
  TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV16_gc | 1 << TCA_SINGLE_ENABLE_bp
  TCA0.SINGLE.CMP1 = 65530; // Начальное значение
  pinMode(10, OUTPUT);
  TCA0.SINGLE.CTRLB |= TCA_SINGLE_CMP1EN_bm;
}

void loop() {
  // устанавливаем яркость светодиодного вывода:
  TCA0.SINGLE.CMP1 = brightness;

  // изменяем яркость для следующего прохода цикла:
  brightness = brightness + fadeAmount;

  // инвертируем направление затухания на концах затухания:
  if (brightness <= 0 || brightness >= 64) {
    fadeAmount = -fadeAmount;
  }
  // ждем, чтобы увидеть эффект затемнения
  delay(50);
}
,