STM32 ШИМ.
Генерация ШИМ у STM32 осуществляется с помощью таймеров, про них в документации написано много, но ШИМ оказалось настроить достаточно просто. Генерировать ШИМ будем с помощью 4-го канала первого таймера.
Первым делом надо найти какой вывод отвечает за 4-й канал первого таймера, для этого открываем Technical DataSheet на свой МК, у меня STM32F103VET6, и находим альтернативной функцией какого вывода является TIM1_CH4.
Для использования таймера вывод надо настроить как push-pull.
Давайте рассмотрим регистры, которые нам понадобятся.
TIMx_PSC – входной предварительный делитель частоты, его значение можно рассчитать по формуле
TIMx_ARR – регистр автоматической перезагрузки, счётчик считает от 0 до TIMx_ARR, или наоборот в зависимости от направления счёта, изменяя это значение, мы изменяем частоту ШИМ.
TIMx_CCRy[x – номер таймера, y – номер канала] – определяет коэффициент заполнения ШИМ. То есть, если в ARR мы запишем 1000, а в CCRy 300, то коэффициент заполнения при положительном активном уровне и прямом ШИМ будет равен 0.3 или 30%.
TIMx_CNT – счётный 16-битный регистр, изменяет своё значение на ±1 с приходом каждого импульса, в зависимости от направления счёта.
TIMx_CR1 ->DIR – регистр направления счёта, при установке '0' счётчик считает вверх, при установки '1' - вниз. Когда счётчик сконфигурирован в режиме выравнивания по центру, бит доступен только для чтения.
TIMx_CCER->CCyE[x – номер таймера, y – номер канала] – установка '1' в этот бит разрешает использовать соответствующий канал таймера как выход, в том числе и для генерации ШИМ.
TIMx_BDTR->MOE – установка единицы в этот бит разрешает использовать выводы таймера как выходы.
Биты OCyM[2:0], где y — номер канала, в регистре TIMx_CCMR позволяют выбрать режим ШИМ, прямой или инверсный.
Надо сказать, что первый и второй канал настраиваются в регистре CCMR1, а третий и четвёртый в регистре CCMR2.
TIMx_CCER->CCyP[x - номер таймера, y - номер канала] - этот бит позволяет выбирать каким будет активный уровень, '0' - высокий, '1' - низкий.
TIMx_CR1 ->CMS[1:0] - позволяет выбрать режим выравнивания по фронту или по центру, что аналогично Fast PWM и Phase Correct PWM у AVR.
TIMx_CRx->CEN – установка '1' в этот бит, запускает счётчик.
Давайте напишем код для генерации ШИМ с выравниванием по фронту.
Смотрим, что получилось.
Изменяем активный уровень, на высокий.
Изменяем прямой ШИМ на инверсный.
Всё стало как было раньше, ничего сложного.
Первым делом надо найти какой вывод отвечает за 4-й канал первого таймера, для этого открываем Technical DataSheet на свой МК, у меня STM32F103VET6, и находим альтернативной функцией какого вывода является TIM1_CH4.
Для использования таймера вывод надо настроить как push-pull.
Давайте рассмотрим регистры, которые нам понадобятся.
TIMx_PSC – входной предварительный делитель частоты, его значение можно рассчитать по формуле
F = fCK_PSC / (PSC[15:0] + 1)
- F – частота с которой тактируется таймер
- fCK_PSC — частота таймера до делителя
- PSC[15:0] — значение регистра PSC
TIMx_ARR – регистр автоматической перезагрузки, счётчик считает от 0 до TIMx_ARR, или наоборот в зависимости от направления счёта, изменяя это значение, мы изменяем частоту ШИМ.
TIMx_CCRy[x – номер таймера, y – номер канала] – определяет коэффициент заполнения ШИМ. То есть, если в ARR мы запишем 1000, а в CCRy 300, то коэффициент заполнения при положительном активном уровне и прямом ШИМ будет равен 0.3 или 30%.
TIMx_CNT – счётный 16-битный регистр, изменяет своё значение на ±1 с приходом каждого импульса, в зависимости от направления счёта.
TIMx_CR1 ->DIR – регистр направления счёта, при установке '0' счётчик считает вверх, при установки '1' - вниз. Когда счётчик сконфигурирован в режиме выравнивания по центру, бит доступен только для чтения.
TIMx_CCER->CCyE[x – номер таймера, y – номер канала] – установка '1' в этот бит разрешает использовать соответствующий канал таймера как выход, в том числе и для генерации ШИМ.
TIMx_BDTR->MOE – установка единицы в этот бит разрешает использовать выводы таймера как выходы.
Биты OCyM[2:0], где y — номер канала, в регистре TIMx_CCMR позволяют выбрать режим ШИМ, прямой или инверсный.
Надо сказать, что первый и второй канал настраиваются в регистре CCMR1, а третий и четвёртый в регистре CCMR2.
TIMx_CCER->CCyP[x - номер таймера, y - номер канала] - этот бит позволяет выбирать каким будет активный уровень, '0' - высокий, '1' - низкий.
TIMx_CR1 ->CMS[1:0] - позволяет выбрать режим выравнивания по фронту или по центру, что аналогично Fast PWM и Phase Correct PWM у AVR.
- 00: Режим выравнивания по фронту. Счетчик считает вверх или вниз в зависимости от бита направления(DIR).
- 01: Режим 1 выравнивания по центру. Счетчик считает вверх и вниз. Флаги прерывания устанавливаются от каналов настроенных на выход(CCxS=00 в TIMx_CCMRx), только тогда, когда счетчик считает вниз.
- 10: Режим 2 выравнивания по центру. Счетчик считает вверх и вниз. Флаги прерывания устанавливаются от каналов настроенных на выход(CCxS=00 в TIMx_CCMRx), только тогда, когда счетчик считает вверх.
- 11: Режим 3 выравнивания по центру. Счетчик считает вверх и вниз. Флаги прерывания устанавливаются от каналов настроенных на выход(CCxS=00 в TIMx_CCMRx), когда счетчик считает вверх и вниз.
TIMx_CRx->CEN – установка '1' в этот бит, запускает счётчик.
Давайте напишем код для генерации ШИМ с выравниванием по фронту.
#include "stm32f10x.h"
int main (void)
{
// Тактирование GPIOA , TIM1, альтернативных функций порта
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_TIM1EN | RCC_APB2ENR_AFIOEN;
//PA11 push-pull
GPIOA->CRH &= ~GPIO_CRH_CNF11;
GPIOA->CRH |= GPIO_CRH_CNF11_1;
GPIOA->CRH &= ~GPIO_CRH_MODE11;
GPIOA->CRH |= GPIO_CRH_MODE11_1;
//делитель
TIM1->PSC = 72;
//значение перезагрузки
TIM1->ARR = 1000;
//коэф. заполнения
TIM1->CCR4 = 300;
//настроим на выход канал 4, активный уровень низкий
TIM1->CCER |= TIM_CCER_CC4E | TIM_CCER_CC4P;
//разрешим использовать выводы таймера как выходы
TIM1->BDTR |= TIM_BDTR_MOE;
//PWM mode 1, прямой ШИМ 4 канал
TIM1->CCMR2 = TIM_CCMR2_OC4M_2 | TIM_CCMR2_OC4M_1;
//если надо настроить первый канал, это можно сделать так
//TIM1->CCMR1 = TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1;
//считаем вверх
TIM1->CR1 &= ~TIM_CR1_DIR;
//выравнивание по фронту, Fast PWM
TIM1->CR1 &= ~TIM_CR1_CMS;
//включаем счётчик
TIM1->CR1 |= TIM_CR1_CEN;
}
Смотрим, что получилось.
Изменяем активный уровень, на высокий.
Изменяем прямой ШИМ на инверсный.
Всё стало как было раньше, ничего сложного.
Похожие статьи