STM32 ШИМ.
Генерация ШИМ у STM32 осуществляется с помощью таймеров, про них в документации написано много, но ШИМ оказалось настроить достаточно просто. Генерировать ШИМ будем с помощью 4-го канала первого таймера.
Первым делом надо найти какой вывод отвечает за 4-й канал первого таймера, для этого открываем Technical DataSheet на свой МК, у меня STM32F103VET6, и находим альтернативной функцией какого вывода является TIM1_CH4.
![STM32 ШИМ. STM32 ШИМ.](/uploads/posts/2015-07/1437561416_screenshot_1.png)
Для использования таймера вывод надо настроить как push-pull.
![STM32 ШИМ. STM32 ШИМ.](/uploads/posts/2015-07/1437603366_screenshot_5.png)
Давайте рассмотрим регистры, которые нам понадобятся.
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' в этот бит, запускает счётчик.
Давайте напишем код для генерации ШИМ с выравниванием по фронту.
Смотрим, что получилось.
![STM32 ШИМ. STM32 ШИМ.](/uploads/posts/2015-07/1437581825_1.jpg)
Изменяем активный уровень, на высокий.
![STM32 ШИМ. STM32 ШИМ.](/uploads/posts/2015-07/1437581776_screenshot_4.png)
![STM32 ШИМ. STM32 ШИМ.](/uploads/posts/2015-07/1437581761_2.jpg)
Изменяем прямой ШИМ на инверсный.
![STM32 ШИМ. STM32 ШИМ.](/uploads/posts/2015-07/1437581793_pwm_mode_2.png)
![STM32 ШИМ. STM32 ШИМ.](/uploads/posts/2015-07/1437581825_1.jpg)
Всё стало как было раньше, ничего сложного.
Первым делом надо найти какой вывод отвечает за 4-й канал первого таймера, для этого открываем Technical DataSheet на свой МК, у меня STM32F103VET6, и находим альтернативной функцией какого вывода является TIM1_CH4.
![STM32 ШИМ. STM32 ШИМ.](/uploads/posts/2015-07/1437561416_screenshot_1.png)
Для использования таймера вывод надо настроить как push-pull.
![STM32 ШИМ. STM32 ШИМ.](/uploads/posts/2015-07/1437603366_screenshot_5.png)
Давайте рассмотрим регистры, которые нам понадобятся.
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;
}
Смотрим, что получилось.
![STM32 ШИМ. STM32 ШИМ.](/uploads/posts/2015-07/1437581825_1.jpg)
Изменяем активный уровень, на высокий.
![STM32 ШИМ. STM32 ШИМ.](/uploads/posts/2015-07/1437581776_screenshot_4.png)
![STM32 ШИМ. STM32 ШИМ.](/uploads/posts/2015-07/1437581761_2.jpg)
Изменяем прямой ШИМ на инверсный.
![STM32 ШИМ. STM32 ШИМ.](/uploads/posts/2015-07/1437581793_pwm_mode_2.png)
![STM32 ШИМ. STM32 ШИМ.](/uploads/posts/2015-07/1437581825_1.jpg)
Всё стало как было раньше, ничего сложного.
Похожие статьи