В чём проблема?


Как мы уже говорили в уроке про функции времени и про ШИМ сигнал, у микроконтроллера есть несколько таймеров, которые могут выполнять разные функции, в частности – генерировать ШИМ сигнал. Чтобы таймер генерировал ШИМ, его нужно предварительно настроить при помощи редактирования регистра таймера. Когда мы работаем в Arduino IDE, таймеры настраиваются без нашего ведома в библиотеке Arduino.h, и собственно получают настройки, которые пожелали разработчики. И вот настройки эти не очень хорошие: частота ШИМ по умолчанию низкая, возможности таймеров не используются в полной мере. Посмотрим на стандартный ШИМ у ATmega328 (Arduino UNO/Nano/Pro Mini):

Таймер Пины Частота Разрешение
Timer 0 D5 и D6 976 Гц 8 бит (0-255)
Timer 1 D9 и D10 488 Гц 8 бит (0-255)
Timer 2 D3 и D11 488 Гц 8 бит (0-255)

На самом деле все таймеры спокойно могут выдавать 64 кГц ШИМ сигнал, а таймер 1 – он вообще 16 битный, и на той частоте, которую ему дали Arduino, мог бы работать с разрешением 15 бит вместо 8, а это, на минуточку, 32768 градаций заполнения вместо 256!!! Так к чему такая несправедливость? Таймер 0 занимается отсчётом времени, и настроен так, чтобы миллисекунды тикали точно. А остальные таймеры просто причёсаны к нулевому под одну гребёнку, чтобы у ардуинщика не возникло лишних проблем. Такой подход в целом можно понять, но сделали бы хоть пару стандартных функций для более высокой частоты, ну серьёзно! Ладно, если они не сделали, то сделаем мы.

Настройка частоты ШИМ через регистры


Как мы обсуждали в предыдущем уроке, микроконтроллер настраивается на низком уровне через регистры, так вот генерация ШИМ настраивается через регистры таймеров. Далее вы найдёте несколько готовых “кусков” кода, которые достаточно вставить в setup(), и частота ШИМ будет перенастроена (меняется предделитель и режим работы таймера). Работать с ШИМ сигналом можно будет всё так же при помощи функции analogWrite(), управляя заполнением ШИМ на стандартных пинах.

Меняем частоту ШИМ на ATmega328 (Arduino UNO/Nano/Pro Mini)


// Пины D5 и D6 - 62.5 кГц
TCCR0B = 0b00000001;	// x1
TCCR0A = 0b00000011;	// fast pwm

// Пины D5 и D6 - 31.4 кГц
TCCR0B = 0b00000001;	// x1
TCCR0A = 0b00000001;	// phase correct

// Пины D5 и D6 - 7.8 кГц
TCCR0B = 0b00000010;	// x8
TCCR0A = 0b00000011;	// fast pwm

// Пины D5 и D6 - 4 кГц
TCCR0B = 0b00000010;	// x8
TCCR0A = 0b00000001;	// phase correct

// Пины D5 и D6 - 976 Гц - по умолчанию
TCCR0B = 0b00000011;	// x64
TCCR0A = 0b00000011;	// fast pwm

// Пины D5 и D6 - 490 Гц
TCCR0B = 0b00000011;	// x64
TCCR0A = 0b00000001;	// phase correct

// Пины D5 и D6 - 244 Гц
TCCR0B = 0b00000100;	// x256
TCCR0A = 0b00000011;	// fast pwm

// Пины D5 и D6 - 122 Гц
TCCR0B = 0b00000100;	// x256
TCCR0A = 0b00000001;	// phase correct

// Пины D5 и D6 - 61 Гц
TCCR0B = 0b00000101;	// x1024
TCCR0A = 0b00000011;	// fast pwm

// Пины D5 и D6 - 30 Гц
TCCR0B = 0b00000101;	// x1024
TCCR0A = 0b00000001;	// phase correct

// Пины D9 и D10 - 62.5 кГц
TCCR1A = 0b00000001;	// 8bit
TCCR1B = 0b00001001;	// x1 fast pwm

// Пины D9 и D10 - 31.4 кГц
TCCR1A = 0b00000001;	// 8bit
TCCR1B = 0b00000001;	// x1 phase correct

// Пины D9 и D10 - 7.8 кГц
TCCR1A = 0b00000001;	// 8bit
TCCR1B = 0b00001010;	// x8 fast pwm

// Пины D9 и D10 - 4 кГц
TCCR1A = 0b00000001;	// 8bit
TCCR1B = 0b00000010;	// x8 phase correct

// Пины D9 и D10 - 976 Гц
TCCR1A = 0b00000001;	// 8bit
TCCR1B = 0b00001011;	// x64 fast pwm

// Пины D9 и D10 - 490 Гц - по умолчанию
TCCR1A = 0b00000001;	// 8bit
TCCR1B = 0b00000011;	// x64 phase correct

// Пины D9 и D10 - 244 Гц
TCCR1A = 0b00000001;	// 8bit
TCCR1B = 0b00001100;	// x256 fast pwm

// Пины D9 и D10 - 122 Гц
TCCR1A = 0b00000001;	// 8bit
TCCR1B = 0b00000100;	// x256 phase correct

// Пины D9 и D10 - 61 Гц
TCCR1A = 0b00000001;	// 8bit
TCCR1B = 0b00001101;	// x1024 fast pwm

// Пины D9 и D10 - 30 Гц
TCCR1A = 0b00000001;	// 8bit
TCCR1B = 0b00000101;	// x1024 phase correct

// Пины D9 и D10 - 15.6 кГц 10bit
TCCR1A = 0b00000011;	// 10bit
TCCR1B = 0b00001001;	// x1 fast pwm

// Пины D9 и D10 - 7.8 кГц 10bit
TCCR1A = 0b00000011;	// 10bit
TCCR1B = 0b00000001;	// x1 phase correct

// Пины D9 и D10 - 2 кГц 10bit
TCCR1A = 0b00000011;	// 10bit
TCCR1B = 0b00001010;	// x8 fast pwm

// Пины D9 и D10 - 977 Гц 10bit
TCCR1A = 0b00000011;	// 10bit
TCCR1B = 0b00000010;	// x8 phase correct

// Пины D9 и D10 - 244 Гц 10bit
TCCR1A = 0b00000011;	// 10bit
TCCR1B = 0b00001011;	// x64 fast pwm

// Пины D9 и D10 - 122 Гц 10bit
TCCR1A = 0b00000011;	// 10bit
TCCR1B = 0b00000011;	// x64 phase correct

// Пины D9 и D10 - 61 Гц 10bit
TCCR1A = 0b00000011;	// 10bit
TCCR1B = 0b00001100;	// x256 fast pwm

// Пины D9 и D10 - 30 Гц 10bit
TCCR1A = 0b00000011;	// 10bit
TCCR1B = 0b00000100;	// x256 phase correct

// Пины D9 и D10 - 15 Гц 10bit
TCCR1A = 0b00000011;	// 10bit
TCCR1B = 0b00001101;	// x1024 fast pwm

// Пины D9 и D10 - 7.5 Гц 10bit
TCCR1A = 0b00000011;	// 10bit
TCCR1B = 0b00000101;	// x1024 phase correct

// Пины D3 и D11 - 62.5 кГц
TCCR2B = 0b00000001;	// x1
TCCR2A = 0b00000011;	// fast pwm

// Пины D3 и D11 - 31.4 кГц
TCCR2B = 0b00000001;	// x1
TCCR2A = 0b00000001;	// phase correct

// Пины D3 и D11 - 8 кГц
TCCR2B = 0b00000010;	// x8
TCCR2A = 0b00000011;	// fast pwm

// Пины D3 и D11 - 4 кГц
TCCR2B = 0b00000010;	// x8
TCCR2A = 0b00000001;	// phase correct

// Пины D3 и D11 - 2 кГц
TCCR2B = 0b00000011;	// x32
TCCR2A = 0b00000011;	// fast pwm

// Пины D3 и D11 - 980 Гц
TCCR2B = 0b00000011;	// x32
TCCR2A = 0b00000001;	// phase correct

// Пины D3 и D11 - 980 Гц
TCCR2B = 0b00000100;	// x64
TCCR2A = 0b00000011;	// fast pwm

// Пины D3 и D11 - 490 Гц - по умолчанию
TCCR2B = 0b00000100;	// x64
TCCR2A = 0b00000001;	// phase correct

// Пины D3 и D11 - 490 Гц
TCCR2B = 0b00000101;	// x128
TCCR2A = 0b00000011;	// fast pwm

// Пины D3 и D11 - 245 Гц
TCCR2B = 0b00000101;	// x128
TCCR2A = 0b00000001;	// phase correct

// Пины D3 и D11 - 245 Гц
TCCR2B = 0b00000110;	// x256
TCCR2A = 0b00000011;	// fast pwm

// Пины D3 и D11 - 122 Гц
TCCR2B = 0b00000110;	// x256
TCCR2A = 0b00000001;	// phase correct

// Пины D3 и D11 - 60 Гц
TCCR2B = 0b00000111;	// x1024
TCCR2A = 0b00000011;	// fast pwm

// Пины D3 и D11 - 30 Гц
TCCR2B = 0b00000111;	// x1024
TCCR2A = 0b00000001;	// phase correct

void setup() {
  // Пины D5 и D6 - 7.8 кГц
  TCCR0B = 0b00000010;  // x8
  TCCR0A = 0b00000011;  // fast pwm

  // Пины D3 и D11 - 62.5 кГц
  TCCR2B = 0b00000001;  // x1
  TCCR2A = 0b00000011;  // fast pwm

  // Пины D9 и D10 - 7.8 кГц 10bit
  TCCR1A = 0b00000011;  // 10bit
  TCCR1B = 0b00000001;  // x1 phase correct

  analogWrite(3, 15);
  analogWrite(5, 167);
  analogWrite(6, 241);
  analogWrite(9, 745);    // да, диапазон 0-1023
  analogWrite(10, 345);   // да, диапазон 0-1023
  analogWrite(11, 78);
}

void loop() {
}

Важно! При изменении частоты на пинах D5 и D6 вы потеряете функции времени (millis(), delay(), pulseIn(), setTimeout() и прочие), они будут работать некорректно. Также перестанут работать библиотеки, которые их используют!

Библиотеки для работы с ШИМ


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

  • Библиотека PWM (GitHub) – мощная библиотека, позволяющая менять частоту ШИМ на микроконтроллерах ATmega48 / 88 / 168 / 328 / 640 / 1280 / 1281 / 2560 / 2561, из них 328 стоит на UNO/Nano/Mini, а 2560 – это Arduino Mega.
    • Позволяет установить любую частоту ШИМ, предделитель, TOP
    • При работе с 8-битными таймерами доступен только один канал (например на ATmega328 останутся D3, D5, D9 и D10)
    • Позволяет работать с 16-битными таймерами на более высоком разрешении (16 бит вместо стандартных 8)
    • Библиотека написана очень сложно, по кускам её растащить не получится
    • Смотрите примеры в папке с библиотекой!
  • Библиотека GyverPWM (GitHub) – библиотека, которую мы написали вместе с Егором Захаровым. Библиотека позволяет очень гибко работать с ШИМ на микроконтроллере ATmega328 (позже добавим Мегу):
    • Позволяет установить любую частоту ШИМ в диапазоне 250 Гц – 200 кГц
    • Выбор разрядности: 4-8 бит для 8 бит таймеров, 4-16 бит для 16-бит таймеров (при разрядности 4 бита частота ШИМ составляет 1 МГЦ 😀 )
    • Выбор режима работы ШИМ: Fast PWM или Phase-correct PWM (благоприятен для электродвигателей)
    • Генерация меандра на пине D9 с частотой от 2 Гц до 8 МГц с максимальной точностью
    • При работе с 8-битными таймерами доступен только один канал (например на ATmega328 останутся D3, D5, D9 и D10)
    • Есть функции для перенастройки стандартного ШИМ, при котором не теряются ШИМ выходы
    • Библиотека написана очень просто, можно брать из неё код кусками
    • Смотрите примеры в папке с библиотекой!

Важные страницы


  • Каталог ссылок на дешёвые Ардуины, датчики, модули и прочие железки с AliExpress у проверенных продавцов
  • Подборка библиотек для Arduino, самых интересных и полезных, официальных и не очень
  • Полная документация по языку Ардуино, все встроенные функции и макро, все доступные типы данных
  • Сборник полезных алгоритмов для написания скетчей: структура кода, таймеры, фильтры, парсинг данных
  • Видео уроки по программированию Arduino с канала “Заметки Ардуинщика” – одни из самых подробных в рунете
Увеличение частоты ШИМ
5 (100%) 1 vote[s]
Последнее обновление Июль 05, 2019
2019-07-05T14:56:08+03:00