Друзья, привет!
Давно я уже хотел разобраться с этой темой, да все руки не доходили. А тут приболел слегка и решил закрыть несколько гештальтов относительно моего любимого микроконтроллера - CH32V003. Начну, пожалуй, именно с выяснения возможности управления сервоприводом. Для тех, кто с этими микроконтроллерами не знаком, порекомендую статью "Китайские микроконтроллеры CH32, с чего начать". И сразу еще одну, идущую в дополнение к первой: "Китайские микроконтроллеры CH32 на практике".
В свое время, когда я только начинал знакомство с современными микроконтроллерами (а начинал я, разумеется с Ардуино), меня поразили широкие возможности их использования для решения задач автоматизации. Каких только периферийных устройств, датчиков, контроллеров и т.п. не придумали! Но, сервопривод, на мой взгляд, круче всего! Я настолько был потрясен соотношением цена-возможности всей этой техники, что одним из первых моих проектов стал автомобильчик с гироскопическим управлением.
Просто поворачивая руль в воздухе можно было управлять траекторией машинки. Две кнопки - направление движения. В этой машинке сервопривод использовался для управления поворотом передних колес. Забавная получилась игрушка! Каких мы только с сыном полигонов не устраивали для нее. И соревновались, кто быстрее проедет полосу препятствий!
Теперь пришло время недорогих китайских микроконтроллеров. О них я уже много рассказывал и много чего делал. Кому интересно, найдете в статьях за последние 2 года. Дошли руки и до подключения сервопривода. Пока чисто из академических интересов. Давайте разбираться...
Особенности работы сервопривода
А собственно, почему разбираться? Ведь для той-же Arduino уже все известно! Берем библиотеку Servo и вперед... А для CH32 нет-ли библиотек? К сожалению, нет! И не нужно! CH32V003, а особенно его младшенькая, 8-пиновая модификация - CH32V003J4M6, с которой я экспериментирую - микроконтроллер замечательный, но пока лишенный такого же сообщества, что есть у Arduino. Поэтому придется самим. Хотя, для начала посмотрим, нет ли чего в интернете на эту тему...
И точно, есть, хотя и немного! Некий китайский программист из Канады выложил в репозитории GitHub пример подключения сервопривода к микроконтроллеру CH32. Со знакомства с ним я и начал свой анализ в этой области. И знаете, что я вам скажу? Никогда так не делайте! Я не могу себя считать крутым программистом. Это, скорее хобби. Но то, что в обработчик прерываний нельзя встраивать задержки процессорного ядра, по-моему, известно любому ребенку! Нет, когда ваш контроллер больше ничем не загружен кроме таймера, то пожалуйста! Но вы же ведь еще какую-то логику планируете, так? Так вот, будете очень сильно удивлены, когда код начнет выкидывать фортели, особенно если в нем появятся участки критичные к времени выполнения. К тому же, Li не потрудился снабдить код развернутыми комментариями.
Попробуем устранить все недостатки!
Для начала, как вообще управляется сервопривод. Да, я надеюсь все знают, что это такое? Механическое поворотное устройство с управляемым углом поворота. Во! Сам только придумал! Выглядит вот так.
Это самый недорогой и самый популярный вариант. Для управления используются 3 провода. Коричневый - "земля". Красный - питание 4,8...6 Вольт. Желтый - управляющий сигнал. Если с первыми двумя все более или менее понятно, то с третьим (желтым) есть проблемы.
Казалось бы чего проще - подавать на этот вывод разное напряжение от уровня которого будет зависеть угол поворота двигателя. Но нет! Все чуточку сложнее. Дело в том, что большинство микроконтроллеров не умеют формировать аналоговые выходные сигналы. То есть не имеют встроенных ЦАП. Кроме того, в цифровой технике трудно получить стабильный уровень напряжения из-за "цифрового шума",возникающего при переключении логических элементов. Поэтому сервопривод управляется не напряжением, а длительностью импульсов, передаваемых по желтому проводу. Фронт импульса исказить сложнее, а кварцевая стабилизация микроконтроллера позволяет достичь очень высокой точности. Хотя, и без нее тоже неплохо получается!
Итак длительность импульса и есть основное управляющее воздействие. Для большинства популярных сервоприводов известны и параметры этих импульсов. При длительности импульса 500 мкс сервопривод занимает крайнее левое положение. Назовем его - 0 градусов. При длительности импульса 2500 мкс сервопривод занимает крайнее правое положение (вращение по часовой стрелке). Назовем его - 180 градусов. Кроме того, импульсы должны идти с определенной периодичностью. Считается, что наиболее оптимальным вариантом является период - 20 мс (частота 50 Гц). При этом и скорость реакции приемлемая, и нагрузка на двигатель сервопривода щадящая. Если длина импульса - значение критическое для обеспечения точности регулировки, то периодичность точно можно не соблюдать.
Программная реализация
Для работы с промежутками времени в нашем микроконтроллере есть замечательное устройство - таймер. И даже не один, а целых два! А у таймера есть очень подходящий для нас режим, режим широтно-импульсной модуляции - ШИМ, или по английски - PWM (pulse width modulation). В этом режиме таймер способен формировать на физических выводах микроконтроллера периодическую последовательность импульсов заданной ширины. Это нам и нужно! Причем работа таймера никаких ресурсов процессора не требует и никак на его производительность не влияет. Процессор может быть занят полезными расчетами. Главное, это правильно настроить таймер. А, в настройке таймера нам опыта не занимать!
Попробуем прикинуть параметры ШИМ, которые нас устроят. Итак, период любого импульса ШИМ можно представить в виде отрезка времени, разбитого на 65536 частей (2 в 16-й степени, где 16 - разрядность регистров счетчика). Соответственно, длительность импульса может колебаться от 1/65536-й части периода (очень короткий импульс) до 65535/65536-й части (очень длинный импульс). Если отталкиваться от требуемой периодичности следования импульсов - 20 мс, то можно прикинуть возможную точность формирования импульсов: 20/65536 = 0,305 мкс. Примерно, разумеется. Тогда для формирования импульса, соответствующего нулю градусов поворота потребуется 500 / 0,305 = 1640 частей периода. А для импульса, соответствующего крайнему правому положению: 2500 / 0,305 = 8196 частей. Прикинем точность формирования. (8196 - 1640) / 180 = 36 импульсов на 1 градус. То есть точность позиционирования сервопривода составит не хуже 0,03 градуса. По-моему неплохо! Думаю, механика сервопривода сама такой точности не обеспечит!
Да, но это все прикидки! Позволит ли микроконтроллер получить ШИМ с такими параметрами. Давайте считать! Базовая тактовая частота микроконтроллера составляет 48 МГц. Нам нужно получить частоту элементарных интервалов таймера 50 * 65536 = 3276800 Гц. Здесь 50 - это частота импульсов в Герцах (периодичность 20 мс, это частота 50 Гц: 1/0,02). Для получения такой частоты счета нужно разделить тактовую частоту на частоту желаемую. Делим: 48000000 / 3276800 = 14,65. Округлим в меньшую сторону, до 14-ти. Тогда, если установить предделитель таймера в эту величину, то можно получить периодичность импульсов: 48000000 / 14 / 65536 = 52,3 Гц. Поскольку точного совпадения не требуется, то примем это значение за основу.
Итак, требуется запустить таймер со значением предделителя - 14 в режиме ШИМ. Для этого можно использовать практически любой вывод, поскольку на каждый можно вывести сигнал с какого-либо канала таймера. Я использую вывод 7, на который выведен 4-й канал таймера TIM1. Схема в этом случае будет выглядеть так.
Схему я, как обычно, собрал на макетной плате для быстрого монтажа.
Питание схемы осуществляется от программатора WCH Link (три провода уходят вверх, за кадр). Для питания используется напряжение 5В, поскольку именно столько нужно сервоприводу, а сам микроконтроллер может работать как от 3,3, так и от 5 Вольт.
Управляющая программа написана в среде VSCode, с установленным расширением PlatformIO. Все подробности описаны в статьях, которые я указал в начале. Код проекта снабжен подробными комментариями и доступен для скачивания по ссылке в конце статьи.
Собственно рабочая логика размещена с 48-й по 79-ю строчки.
Прежде всего, следует обратить внимание на процедуру TIMER_1_init(), в которой выполняются все необходимые действия, связанные с инициализацией нужного режима 4-го канала таймера TIM1. Все использованные константы определены в заголовочном модуле ch32v003.h. Собственно, после выполнения этой функции сервопривод приходит в среднее положение. Далее, изменяя регистр TIM1->CH4CVR, можно влиять на ширину импульса. Для демонстрации работы в главном теле реализован режим плавного увеличения-уменьшения угла поворота сервомотора. Как это выглядит можно посмотреть в небольшом видеоролике.
Код управляющей программы доступен для скачивания по ссылке.
Спасибо, что читаете-смотрите Terrabyte! Подписывайтесь, если вам интересна радиолюбительская тематика, микроконтроллеры, мини-ПК, необычные компьютерные решения и инновационные разработки! Спасибо всем, кто поддерживает меня своими советами, комментариями и лайками!
Группа ВК: https://vk.com/terrabyte
Канал на VK-Video: https://vk.com/video/@terrabyte/all