Изменение частоты ШИМ и проблема с разрешением (битностью)

Strikoza

✩✩✩✩✩✩✩
21 Мар 2025
8
0
Экспериментирую с частотой ШИМ на Arduino Nano. Ардуинка китайская, но довольно качественная (RobotDyn).

Попробовал как с записью в регистры:
TCCR1A = 0b00000001; // 8bit
TCCR1B = 0b00000001; // x1 phase correct Пины D9 и D10 - 31.4 кГц
так и с помощью библиотеки GyverPWM.h:
PWM_prescaler(9, 1); // установить частоту ШИМ на пине D9 равной 7.8 кГц (см. таблицу №2 в GyverPWM.h)
или так:
PWM_frequency(9, 20000, FAST_PWM); // запустить ШИМ на D9 с частотой 20000 Гц, режим FAST_PWM
также пробовал и другие настройки библиотеки.

Частота меняется (осциллографа нет, но я ШИМ-ом регулирую яркость LED ленты и вижу мерцание через камеру на низких частотах). Но не могу понять, почему при повышении частоты, разрешение падает до буквально 10 шагов. То есть, если по дефолту у меня есть регулировка в диапазоне 0-255, то при повышении частоты регулировка ШИМ работает, например, от 0 до 12 (на 12 лента уже светит на максимум). Пробовал повышать битность с помощью библиотеки, вроде что-то меняется, но все равно работает как-то не предсказуемо.

Грешил на саму плату, но даже на относительно невысокой частоте:
PWM_frequency(9, 1000, FAST_PWM); // частота 1000 Гц (с помощью библиотеки GyverPWM)
или даже на 500 Гц, регулировка все равно неадекватная: при 8 бит глубине регулировка яркости ленты идет от 0 до 100 (при 100 лента светит примерно на половину мощности), дальше от 100 до 255 ничего не меняется, а потом только на 255 включается на полную.

Для регулировки использую модуль c MOSFET IRF540N.

Подскажите, в чем может быть дело?
 
Изменено:

viktor1703

★★★✩✩✩✩
9 Дек 2021
673
158
осциллографа нет
Для вашей задачи вполне хватит такого показомера, что бы увидеть изменения. Еще любой компьютер оснащён звуковой картой, а люди уже давно придумали, как приспособить её под осциллоскоп.
регулировка все равно неадекватная
Человеческий глаз, как и ухо, могут не различать изменений на некотором "участке" изменяемого сигнала.
 

poty

★★★★★★✩
19 Фев 2020
3,393
970

@Strikoza, сначала приведите полный код, вместе с изменением duty.
Я бы начал со стандартных analogWrite и обычного светодиода, включенного через сопротивление к PWM-пину.
Для больших частот ограничивающим может быть также транзистор, нужно понять как Вы его включили.
"Полного диапазона", видимого глазом, получить всё равно вряд ли получится. Здесь влияет как особенность восприятия, так и нелинейность мощности излучения самого светодиода, в том числе из-за упрощённого управления.
 

bort707

★★★★★★✩
21 Сен 2020
3,118
919
Частота меняется (осциллографа нет, но я ШИМ-ом регулирую яркость LED ленты и вижу мерцание через камеру на низких частотах). Но не могу понять, почему при повышении частоты, разрешение падает до буквально 10 шагов
Простите, но исследовать настройки ШИМ, оценивая разрешение на глаз а частоту по мерцанию - несерьёзно. Ваше выступление ни о чем.
Со своей стороны могу сказать, что много раз проверял разные режимы таймеров на атмеге328 с осциллографом - и каждый раз все работало согласно даташиту.
 

Strikoza

✩✩✩✩✩✩✩
21 Мар 2025
8
0
Спасибо за ответы и советы.

Я совсем новичок в Ардуино. Так что, возможно, я действительно забежал немного вперед и мне стоит начать знакомство с PWM с обычного светодиода, включенного через сопротивление. Просто, очень уж захотелось сразу сделать что-то практичное : )


@Strikoza, сначала приведите полный код, вместе с изменением duty.
Duty не менял, думал, что в библиотеке все учтено. С этим мне нужно разобраться.

Вот мой код для регулировки яркости LED ленты с помощью энкодера:

C++:
#include "GyverEncoder.h"
#include "GyverPWM.h"
Encoder enc(3, 2, 4);
int brightness = 1;

void setup() {
  enc.setType(TYPE2);
  Serial.begin(9600);
  pinMode(9, OUTPUT);
  analogWrite(9, brightness);
  // PWM_frequency(9, 20000, FAST_PWM); // запустить ШИМ на D9 с частотой 20000 Гц, режим FAST_PWM
}

void loop() {
  enc.tick();

  if (enc.isRight())
  {
    brightness = brightness+1;
    if (brightness > 255) brightness = 255;
    analogWrite(9, brightness);
    Serial.println(brightness);
  }

  if (enc.isLeft())
  {
    brightness = brightness-1;
    if (brightness < 1) brightness = 1;
    analogWrite(9, brightness);
    Serial.println(brightness);
  }
}
В таком виде все работает нормально, яркость плавно регулируется от 0 до 255 (по serial monitor). Но если добавить
PWM_frequency(9, 20000, FAST_PWM);
то регулировка от минимума до максимума происходит с 12 до 32 (по serial monitor) очень ступенчато.

Для регулировки использую вот такой модуль (Transistor Switch, 5V logic, DC 24V/30A MOSFET IRF540N):
httprobotdyn.compubmedia0g-00005192mod-mosfetrelay-dc24vphotophotoangle0g-00005192mod-mosfetre...jpg
 
Изменено:

viktor1703

★★★✩✩✩✩
9 Дек 2021
673
158
если добавить
PWM_frequency(9, 20000, FAST_PWM);
то регулировка от минимума до максимума происходит с 12 до 32
Я правильно понимаю,, что когда в setup вы РАСкомментирываете строку
C++:
PWM_frequency(9, 20000, FAST_PWM);
и ЗАкомментирываете строку
C++:
analogWrite(9, brightness);
то у вас ломается регулировка ШИМ в loop'e?
 

Strikoza

✩✩✩✩✩✩✩
21 Мар 2025
8
0
@viktor1703,

не совсем, я только РАСкомментирываю
C++:
PWM_frequency(9, 20000, FAST_PWM);
больше ничего не меняю.
И, да, после этого ломается регулировка ШИМа.
 
Изменено:

Bruzzer

★★★✩✩✩✩
23 Май 2020
542
160
PWM_frequency(9, 20000, FAST_PWM);
....
И, да, после этого ломается регулировка ШИМа.
После этого шим надо регулировать при помощи PWM_set. Непонятно, почему вас удивляет, что перестает правильно работать analogWrite
 
  • Лойс +1
Реакции: viktor1703 и poty

poty

★★★★★★✩
19 Фев 2020
3,393
970
По-моему, ещё нужно включить PWM на нужном пине с помощью PWM_attach.
 

Эдуард Анисимов

★★★★★★✩
23 Сен 2019
2,434
987
59
Марий-Эл
@Strikoza, Вспомнил. У меня была такая же проблема. Решилась не линейным изменением яркости, а логарифмическим. Тогда для глаза получается равномерное изменение яркости.

C++:
const uint8_t ArrLog[256] =
{
    0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02,
    0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
    0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04,
    0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x06,
    0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x09,
    0x09, 0x09, 0x09, 0x09, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0B, 0x0B, 0x0B, 0x0B, 0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D,
    0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x10, 0x10, 0x10, 0x11, 0x11, 0x12, 0x12, 0x12, 0x13, 0x13, 0x14, 0x14, 0x14,
    0x15, 0x15, 0x16, 0x16, 0x17, 0x17, 0x18, 0x18, 0x19, 0x19, 0x1A, 0x1B, 0x1B, 0x1C, 0x1C, 0x1D, 0x1E, 0x1E, 0x1F, 0x20,
    0x20, 0x21, 0x22, 0x23, 0x23, 0x24, 0x25, 0x26, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31,
    0x32, 0x33, 0x34, 0x35, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3D, 0x3E, 0x3F, 0x41, 0x42, 0x44, 0x45, 0x47, 0x48, 0x4A, 0x4C,
    0x4D, 0x4F, 0x51, 0x52, 0x54, 0x56, 0x58, 0x5A, 0x5C, 0x5E, 0x60, 0x62, 0x64, 0x66, 0x69, 0x6B, 0x6D, 0x70, 0x72, 0x75,
    0x77, 0x7A, 0x7C, 0x7F, 0x82, 0x85, 0x88, 0x8B, 0x8E, 0x91, 0x94, 0x97, 0x9B, 0x9E, 0xA2, 0xA5, 0xA9, 0xAC, 0xB0, 0xB4,
    0xB8, 0xBC, 0xC0, 0xC4, 0xC9, 0xCD, 0xD2, 0xD6, 0xDB, 0xE0, 0xE5, 0xEA, 0xEF, 0xF4, 0xF9, 0xFF };
Вот таблица. Она не для ардуины, поэтому нет скриптов для размещения её во FLASH. Сами добавите.
Вместо посылки напрямую кода яркости от 0 до 255, берёте правильное число из этого массива и уже его пихаете в ШИМ.
В файле теория.
 

Вложения

  • Лойс +1
Реакции: Strikoza

Strikoza

✩✩✩✩✩✩✩
21 Мар 2025
8
0
@Bruzzer,

Вы правы, я пропустил то, что необходимо использовать PWM_set вместо analogWrite при использовании этой библиотеки. Но, что интересно, ничего не изменилось. С этим кодом диапазон регулировки яркости от минимума до максимума - где-то от 5 до 15-ти.

C++:
#include "GyverEncoder.h"
#include "GyverPWM.h"
Encoder enc(3, 2, 4);
int brightness = 1;

void setup() {
  enc.setType(TYPE2);
  Serial.begin(9600);
  pinMode(9, OUTPUT);
  PWM_frequency(9, 20000, FAST_PWM); // запустить ШИМ на D9 с частотой 20000 Гц, режим FAST_PWM
}

void loop() {
  enc.tick();

  if (enc.isRight())
  {  
    brightness = brightness+1;
    if (brightness > 255) brightness = 255;
    PWM_set(9, brightness);
    Serial.println(brightness);
  }

  if (enc.isLeft())
  {
    brightness = brightness-1;
    if (brightness < 1) brightness = 1;
    PWM_set(9, brightness);
    Serial.println(brightness);
  }
}
@Геннадий П,

Возможно, дело действительно в моем модуле с мосфетом. Чем ниже я опускаю частоту (PWM_frequency), тем регулировка становится более адекватной. Попробую другой модуль... хотя, странно, ведь для IRF540N 15-20кГц - совсем небольшие частоты. Но вы, наверное, имеете ввиду не сам мосфет и его способности, а то, как разведен/сделан модуль, если я правильно понял.
 
Изменено:

Геннадий П

★★★★★★✩
14 Апр 2021
1,948
627
45
Но вы, наверное, имеете ввиду не сам мосфет и его способности, а то, как разведен/сделан модуль, если я правильно понял.
Именно так. Тока не хватает для быстрого заряда/разряда затвора. Для этого обычно используют специальный драйвер, либо простейшую комплементарную пару транзисторов.
 

Strikoza

✩✩✩✩✩✩✩
21 Мар 2025
8
0
@Геннадий П,

А я еще запитал его от Ардуино. Попробую ради эксперимента запитать отдельно. И закажу на Али такие же модули, но с двумя мосфетами, Gyver такие рекомендовал для этих целей. Спасибо за подсказки!
 

Геннадий П

★★★★★★✩
14 Апр 2021
1,948
627
45
@Strikoza, Судя по всему, у них стандартная схема с управлением на оптроне, которая не блещет скоростью заряда затвора мосфета.
Что то типа такой.

1742661136195.png
 

Strikoza

✩✩✩✩✩✩✩
21 Мар 2025
8
0
@Геннадий П,

Понял, тогда закажу еще таких, как вы посоветовали. А питания с Ардуино нано должно хватать для нормального управления ШИМ (если кроме этого к ней подключен только энкодер)?
 
Изменено:

poty

★★★★★★✩
19 Фев 2020
3,393
970
Прежде, чем что-то дозаказывать, проверьте на светодиоде, подключенном непосредственно к пину 9 через сопротивление.
 

Strikoza

✩✩✩✩✩✩✩
21 Мар 2025
8
0
@Strikoza, Вспомнил. У меня была такая же проблема. Решилась не линейным изменением яркости, а логарифмическим. Тогда для глаза получается равномерное изменение яркости.
Кстати, только когда сделал плавное включение/выключение света (через цикл) понял, о каком логарифмическом изменении вы писали. Когда крутил ручкой, этого не было заметно. Действительно, хоть в цифрах яркость и увеличивается равномерно (по времени) от 0 до 255, но на глаз воспринимается нелинейно. Насколько я понимаю, именно по логарифмической зависимости лента как раз таки у меня и разгорается - быстро вначале, медленно в конце.

В общем, попробую что-то сделать с тем массивом, что вы скинули. Хочу все-таки сделать изменение линейным.

Но это все на стандартных частотах ШИМ, на которых мой модуль с мосфетом работает корректно.
 
Изменено:

Эдуард Анисимов

★★★★★★✩
23 Сен 2019
2,434
987
59
Марий-Эл
В общем, попробую что-то сделать с тем массивом, что вы скинули. Хочу все-таки сделать изменение линейным.
Это должно помочь. Я так делал для чуваков, которые с моргающими устройствами на сцене выступают. Пару лет назад это модно было.
При вращении картинки получаются. Вот тогда и столкнулся с неравномерностью.