Управление сервоприводом при помощи ШИМ

В разработке робототехнических систем зачастую возникает необходимость в управлении сервоприводом при помощи микроконтроллера. И если с электрическим подключением драйвера сложностей обычно не возникает, то инициализация таймеров-счётчиков микроконтроллера для генерирования широтно-импульсно-модулированного меандра на выводах OCnA/OCnB/OCnC нередко вызывает затруднения.

В данной статье я попробую осветить этот вопрос по возможности подробно.

Выбор режима и расчёт частоты ШИМ

С выбором режима в данном случае вопросов на самом деле нет, поскольку режим сброса таймера при совпадении CTC (Clear Timer on Compare match) предназначен специально для управления сервоприводами, мигания светодиодом и т.п. задач.

Соответственно при использовании библиотеки VE_AVR C++ Class Library или библиотеки VEduino инициализацию таймера-счётчика следует начинать со строки:

DEV_TIMER1.setWaveGenMode(TimerW::CTC_OCRA);

Возникает вопрос, какой таймер использовать -- один из 16-битных или 8-битный таймер-счётчик 2? Ответ зависит от того, какая частота ШИМ требуется. Расчёт можно произвести по формуле:

fШИМ = fclk/(2*prescaler*OCRA)

где:

  • fclk -- тактовая частота микроконтроллера (например 16e6 Гц для Arduino)
  • prescaler -- значение предделителя:

1, 8, 64, 256 или 1024 для таймера-счётчика 0 и 16-битных таймеров

1, 8, 32, 64, 128, 256 или 1024 для таймера-счётчика 2

  • OCRA -- значение регистра OCRnA (8-битное для 8-разрядных таймеров, 16-битное для 16-разрядных)

Соответственно, несложно подсчитать минимальную и максимальную частоты ШИМ, которые можно получить с помощью данного счётчика.

Частоты ШИМ

Несложно вывести формулу расчёта значения OCRnA, исходя из желаемой частоты ШИМ:

OCRA = fclk/(2*prescaler*fШИМ)

Допустим, что желаемая частота ШИМ равна 67 Гц, частота тактирования 16 МГц. Получаем следующие результаты:

OCRnA для частоты ШИМ 67 Гц

Посмотрим, с каким предделителем частота ШИМ будет наиболее близка к 67 Гц.

Частоты ШИМ в зависимости от предделителя

Итак, в случае 16-битного таймера нам вполне подойдёт предделитель /8. Предделитель /1 был бы ещё точнее, но значение 119403 превышает максимально-возможное значение 65534 (при 65535 вывод OC будет постоянно включен), и поэтому самый точный результат, который нам доступен в данном случае - 67,0017 Гц.

В случае 8-битного таймера-счётчика 2 максимально-возможное значение равно 254, поэтому только с предделителем /1024 возможно получить частоту, близкую к 67 Гц -- 66,77 Гц.

Итак, таймер и предделитель выбраны, поэтому следующая строка инициализации будет:

DEV_TIMER1.setClockSelect(TimerW::Prescaler_8);

Режим управления выводом OCnA

В расчётной формуле несложно заметить двойку, но возникает вопрос, откуда эта двойка взялась и что она означает. Эта двойка есть ничто иное, как половина периода меандра, поскольку нам требуется, чтобы сигнал на выводе OCnA переключался из 0 в 1 и назад с заданной частотой. Соответственно в данном случае мы его переключаем при совпадении, и таким образом следующей строкой инициализации будет:

DEV_TIMER1.setCompOutModeA(TimerW::Toggle);

Переключение пина в режим вывода

Поскольку пин OCnA по умолчанию пребывает в режиме ввода, то чтобы генерируемый таймером-счётчиком меандр ШИМ выводился из микроконтроллера, пин следует переключить в режим вывода. Для этого мы добавляем в код инициализации строку:

setModeOutput(DEV_TIMER1_OCA);

Включение питания таймера

В некоторых микроконтроллерах ATmega таймер-счётчик 1 по умолчанию включен, в других он по умолчанию выключен, поэтому чтобы его использовать, необходимо предварительно подключить его питание, добавив в код инициализации строку:

DEV_POWER.timer1On();

Автор: Андрей Шаройко <vanyamboe@gmail.com>