Увеличение частоты ШИМ
В чём проблема?
Как мы уже говорили в уроке про функции времени и про ШИМ сигнал, у микроконтроллера есть несколько таймеров, которые могут выполнять разные функции, в частности - генерировать ШИМ сигнал. Чтобы таймер генерировал ШИМ, его нужно предварительно настроить при помощи редактирования регистра таймера. Когда мы работаем в 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)
Если очень хочется
Если очень хочется или очень нужен разогнанный ШИМ на системном (нулевом) таймере без потери функций времени, то можно их скорректировать следующим образом:
#define micros() (micros() >> CORRECT_CLOCK) #define millis() (millis() >> CORRECT_CLOCK) void fixDelay(uint32_t ms) { delay(ms << CORRECT_CLOCK); }
Дефайны нужно размещать перед подключением библиотек, чтобы они залезли в код и подменили функции. Единственное, скорректировать delay внутри другой библиотеки таким образом не получится, для себя можно использовать fixDelay()
как написано выше. Самое главное - CORRECT_CLOCK
. Это целое число, равное отношению делителя таймера по умолчанию и нового установленного (для разгона ШИМ). Например ставим ШИМ 8 кГц. Из списка выше видим, что по умолчанию делитель 64, а 7.8 кГц будет 8, то есть в 8 раз меньше. CORRECT_CLOCK
ставим соответствующий.
#define CORRECT_CLOCK 8 void fixDelay(uint32_t ms) { delay(ms << CORRECT_CLOCK); } void setup() { pinMode(13, 1); // Пины D5 и D6 - 4 кГц TCCR0B = 0b00000010; // x8 TCCR0A = 0b00000001; // phase correct } void loop() { digitalWrite(13, !digitalRead(13)); fixDelay(1000); }
Библиотеки для работы с ШИМ
Помимо ковыряния регистров в ручную существуют готовые библиотеки, позволяющие изменить частоту ШИМ Ардуино. Рассмотрим некоторые из них:
- Библиотека 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)
- Есть функции для перенастройки стандартного ШИМ, при котором не теряются ШИМ выходы
- Библиотека написана очень просто, можно брать из неё код кусками
- Смотрите примеры в папке с библиотекой!
Видео
Полезные страницы
- Набор GyverKIT – большой стартовый набор Arduino моей разработки, продаётся в России
- Каталог ссылок на дешёвые Ардуины, датчики, модули и прочие железки с AliExpress у проверенных продавцов
- Подборка библиотек для Arduino, самых интересных и полезных, официальных и не очень
- Полная документация по языку Ардуино, все встроенные функции и макросы, все доступные типы данных
- Сборник полезных алгоритмов для написания скетчей: структура кода, таймеры, фильтры, парсинг данных
- Видео уроки по программированию Arduino с канала “Заметки Ардуинщика” – одни из самых подробных в рунете
- Поддержать автора за работу над уроками
- Обратная связь – сообщить об ошибке в уроке или предложить дополнение по тексту ([email protected])