STM Урок 10. HAL. Изучаем PWM (ШИМ). Мигаем светодиодами плавно
Урок 10
HAL. Изучаем PWM (ШИМ). Мигаем светодиодами плавно
Сегодня мы продолжим использование библиотеки HAL. Также сегодня мы коснёмся такой технологии, как PWM (ШИМ).
Тонкости данной технологии мы подробно рассматривали в уроке по контроллерам AVR. Я думаю, нет смысла ещё раз повторять.
Мы изучим, как именно широтно-импульсная модуляция реализована в контроллерах STM32, в частности в STM32F407, с которым мы и будем продолжать работать.
Проще всего управлять технологией PWM у данных контроллеров посредством таймеров. Урок по таймерам у нас уже был. Какой таймер чем занимается, мы уже кратко ознакомились, поэтому нам будет намного проще.
В качестве таймера для ШИМ мы возьмём таймер 4. Данный таймер является 16-битным. Доступно до 4 раздельных канала. Также в технической документации на контроллер указано, что таймер может выступать в роли PWM-генератора

Точно также как и раньше проект создаем из самого первого (TEST001), называем его MYPWM
Запускаем Cube MX, отключим. во-первых все ножки портов светодиодов, а также ножку кнопки


Включаем таймер, выбрав в выпадающем списке внутреннее тактирования, и включаем в нем каналы – все 4, выбрав там PWM

Как мы видим, ножки портов, отвечающих за светодиоды на плате, включились сами в определенный альтернативный режим

В настройках таймера в Configuration параметр Counter Period выставляем в 65535

На всякий случай включим прерывания и всем 4м портам выставим скорость high. Генерируем проект


Добавляем код инициализации
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_TIM4_Init();
/* USER CODE BEGIN 2 */
HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_2);
HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_3);
HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_4);
/* USER CODE END 2 */
В функцию main пишем также
/* USER CODE BEGIN 1 */
uint32_t i,d;
/* USER CODE END 1 */
И в бесконечный цикл пишем
/* USER CODE BEGIN 3 */
for(i=0;i<=524288;i++)
{
if(i<65536) TIM4->CCR1=i;
else if ((i>65535)&&(i<131072)) TIM4->CCR1=131071-i;
else if((i>131071)&&(i<196608)) TIM4->CCR2=i-131072;
else if ((i>196607)&&(i<262164)) TIM4->CCR2=262164-i;
else if((i>262163)&&(i<327680)) TIM4->CCR3=i-262164;
else if ((i>327679)&&(i<393216)) TIM4->CCR3=393216-i;
else if((i>393216)&&(i<458752)) TIM4->CCR4=i-393216;
else TIM4->CCR4=524288-i;
for(d=0;d<300;d++)
{
}
}
}
/* USER CODE END 3 */
Теперь соберём код, прошьём контроллер.
После этого мы должны видеть следующую картину

Наши светодиоды зажигаются по очереди, причем зажигаются плавно и тухнут тоже плавно. Вот таким образом мы ощутили эффект широтно-импульсной модуляции визуально.
Отладочную плату можно приобрести здесь STM32F4-DISCOVERY
Смотреть ВИДЕОУРОК в RuTube (нажмите на картинку)
Смотреть ВИДЕОУРОК в YouTube (нажмите на картинку)



Здравствуйте! Хотел у вас спросить, можете ли вы пояснить запись "TIM4->CCR1=i;" что происходит на ножке порта? В один пин выводится четырехбайтовое число?! Где можно посмотреть за что отвечает регистр ССRx?
На ножке порта также продолжают формироваться импульсы с той же частотой, только скважность становится равна значению, полученному в правой части равенства.
ведь период ограничен 65535, а в CCRх передаеется 524288
Нигде такое число не передаётся. Число передаётся от 0 до 65535. Внимательно просчитайте в каждой строке, чему может быть равно i, а затем посчитайте разность в правых частях равенств. Мы нигде ни разу не превысили допустимый интервал.
Спасибо большое!)) дурацкая невнимательность всй губит!) Разобрался!
Здравствуте Владимир!
Огромное спасибо за ваши уроки. Все подробно объясняете. Я уже много чего успел сделать и запустить, благодаря вам, хотя раньше с STM32 не сталкивался.
Не подскажете — как можно запустить ШИМ на частоту примерно 7kHz, а потом плавно менять частоту (не скважность) вверх — вниз, используя, например, две кнопки?
Привет с Болгарии. Вы здесь тоже популярны 🙂
Уже разобрался, спасибо.
И где тут управление шим через HAL?
Вы пишете в регистры напрямую.
Что то автор уроков гонит мне кажется, причем в наглую.
Очень много денег просит за свои уроки?
Конкретизируйте свою предъяву.
Спасибо за уроки. Подскажите как можно сделать плавное включение лампы на 220в. и 12 в.
Посредством PWM, только надо будет организовать для ламп отдельное питание постоянным током и в качестве ключа использовать один или два транзистора с изолированным затвором (MOSFET). А какие именно, можно посмотреть в даташитах соответствующих транзисторов. На 12 вольт например подойдёт вот этот — IRL3103N. На 220 вольт будет посложнее, скорей всего придется ставить два. Так как далеко не все транзисторы откроются при напряжении на затворе ниже 3 вольт.
Что насчёт тиристора?
Там долго объяснять за полпериода:))
А не подскажите, нет ли случаем в HAL метода задающего значение скважности?
Такой функции нет.
Можно только через заполнение структуры переменной типа структуры TIM_OC_InitTypeDef с последующей передачей в качестве параметра функции HAL_TIM_PWM_ConfigChannel. А в структуре есть поле Pulse, которое и задаст скважность.
Только не думаю, что это будет хорошим решением, так как будет выполняться долго, лучше всё-таки через регистр.
Спасибо большое за ответ, правда остаётся непонятной логика разработчиков библиотеки.
А зачем включать прерывание таймера 4 на avr так я не делаю? если мы его используем как шим?
Добрый день ! Спасибо огромное за уроки ! У меня вопрос следующего характера , у таймеров есть пункт » pwm generation no output » . Правильно ли я понимаю что это просто обработчик и в него мы можем засунуть любые ноги МК ? Если да , тогда возникает следующий вопрос — ка это реализуется в жизни ? Спасибо еще раз .
Вам также спасибо за интерес к ресурсу!
Не совсем понятен вопрос.
Вы про какой регистр и про какой бит говорите (или битовое поле)?
В Кубе , при выборе режима таймера ( в данном случае 4 канал второго таймера , просто для примера ) , есть такой пункт pwm generation no output см. картинку (ссылка) Гугл молчит на эту тему . Вот я и сделал предположение , может и ошибочное . По мотивам ваших видео сделал паяльную станцию на ili9341 , если интересно видео (ссылка) . Еще раз большое спасибо !
Спасибо! (ссылки на сторонние ресурсы подчистил). Все ссылки мне в личку в контакте, так как я работаю один и не могу проследить за всеми ссылками. А попадаются всякие, можно запросто лишиться сайта.
Черт с ними с ссылками ))) Все таки вопрос остался открытым : В Кубе , при выборе режима таймера , есть такой пункт pwm generation no output . Если это просто обработчик , тогда по идее мы можем засунуть в него любые ноги МК . Если это верно , то как с этим работать ? Спасибо .
Я лично, к сожалению, с данной функцией не работал. Но подозреваю, что в момент совпадений мы будем попадать в определённые обработчики прерываний, где и можем изменить уровень тех или иных контактов какого-либо порта.
Могли бы уже трехфзный шим показать
То HAL, то запись регистры — винегрет какой-то.
Если необходимо менять величину заполнения, то в HAL следует использовать __HAL_TIM_SET_COMPARE
Здравствуйте! Подскажите пожалуйста, как с помощью таймеров можно прерывать PWM. У меня выход PWM 300Гц на TIM2 и его нужно прерывать, скажем, с частотой 10 Гц. Как это можно сделать?
Непонятно что значит «прерывать PWM с частотой 10Гц». Что вы имеете ввиду? Какой сигнал хотите получить?
Исходя из своих теоретических предположений по вашему запросу:
В обработчик прерывания по переполнению добавьте переменную-счётчик.
На 300 Гц досчитали до 30:
TIM2->CCR1 = 0; //предположил что у вас TIM2 Channel1
// или TIM2->CCR1 = TIM2->ARR — смотря чем вы хотите «прервать» — нулём или единицей на выходе.
досчитали еще до 30:
TIM2->CCR1 = PWM_Value;
но возможно я неправильно понял задачу. не экстрасенс.
Спасибо за ответ! Я хотел получить ШИМ пачками. Искал другие варианты чтоб не через коллбэки. Думал, может можно всё это аппаратно будет заставить работать. Выставить таймер в режим ШИМ и как слейв а второй таймер в режим счётчика или ШИМ без выхода. Таким образом прерывать работу ШИМ'а без коллбэка, но чтот не выходит. Видимо проще завести ещё один ШИМ и решить проблему внешним лог. вентилем AND.
Можно и аппаратно. Частота таймеров 72 МГц.
TIM2 конфигурация:
Slave Node = Gated Mode
Trigger Source = ITR2
Channel1 = PWM Generation CH1
TIM2 настройки:
Prescaler = 2399
Counter Period = 99
PWM -> Pulse = 50 (скважность PWM)
TIM3 конфигурация:
Channel1 = PWM Generation No Output
TIM3 настройки:
Prescaler = 2399
Counter Period = 2999
Trigger Event Selection = Output Compare (OC1REF)
PWM -> Pulse = 1500
запуск в программе:
HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
Ах, вот почему не работало у меня. Я забыл выставить Out Compare в Trigger Event Selelection 😀 Большое Вам спасибо за помощь!
Доброго времени суток, возможно осуществить с одного канала чтобы дрыгало несколько ножек? Чтобы можно было отключить/включить независимо любую?