Урок 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 */
Теперь соберём код, прошьём контроллер.
После этого мы должны видеть следующую картину
Наши светодиоды зажигаются по очереди, причем зажигаются плавно и тухнут тоже плавно. Вот таким образом мы ощутили эффект широтно-импульсной модуляции визуально.
Предыдущий урок Программирование МК STM32 Следующий урок
Купить плату можно здесь STM32F4-DISCOVERY
Смотреть ВИДЕОУРОК
Здравствуйте! Хотел у вас спросить, можете ли вы пояснить запись "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 😀 Большое Вам спасибо за помощь!
Доброго времени суток, возможно осуществить с одного канала чтобы дрыгало несколько ножек? Чтобы можно было отключить/включить независимо любую?