Главная » Хабрахабр » Синхронизация ШИМ на STM32

Синхронизация ШИМ на STM32

Не буду особо вдаваться в теорию, в сети много ресурсов где все очень подробно описано. Но когда дело доходит до практики понимаешь, что все намного сложнее. Используется микроконтроллер stm32l152c-discovery. В статье будет описан процесс запуска ШИМ двух таймеров в одно и то же время (полная синхронизация):

image

А так же запуск с отставанием (на фото отставание в пол периода):

image

Создадим функцию для инициализации initPWM, объявим в ней переменные для удобства

void initPWM()
{ const uint32_t Period = 20 - 1;//переменная периода const uint32_t prescaler = 1 - 1;//Предделитель //-1 потому что счет начинается с 0 const uint32_t pulse = 15;//Длина импульса
}

Для начала необходимо провести инициализацию структур для конфигурирования таймеров:

GPIO_InitTypeDef port; TIM_TimeBaseInitTypeDef timer; TIM_OCInitTypeDef timerPWM;

Далее активируем необходимую нам периферию. Будем использовать TIM3 и TIM4, просто потому что так захотелось:

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);

GPIOB активируем, т.к. выходы таймеров сидят на этой шине PB5 и PB9. Эту информацию можно найти в юзер мануале к микроконтроллеру в таблице MCU pin description versus board function.

image

Настраиваем выходы в режим альтернативной фунции:

GPIO_StructInit(&port); port.GPIO_Mode = GPIO_Mode_AF;//Режим альтернативной функции, нужен для ШИМ port.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_9; port.GPIO_Speed = GPIO_Speed_2MHz;//Частота до 2Мгц port.GPIO_OType = GPIO_OType_PP;//режим работы "push-pull" "двухтактный выход" GPIO_Init(GPIOB, &port);
//активация альтернативной функции выхода PB5 GPIO_PinAFConfig(GPIOB,GPIO_PinSource5,GPIO_AF_TIM3);
//активация альтернативной функции выхода PB9 GPIO_PinAFConfig(GPIOB,GPIO_PinSource9,GPIO_AF_TIM4);

Настраиваем таймер в режим работы ШИМ:

TIM_TimeBaseStructInit(&timer); timer.TIM_ClockDivision = TIM_CKD_DIV1; timer.TIM_CounterMode = TIM_CounterMode_Up;//Счет вверх timer.TIM_Prescaler = prescaler;//Предделитель timer.TIM_Period = Period;//Период TIM_TimeBaseInit(TIM4, &timer);//Записываем настройки в оба таймера TIM_TimeBaseInit(TIM3, &timer); TIM_OCStructInit(&timerPWM); timerPWM.TIM_Pulse = pulse;//Длина импульса timerPWM.TIM_OCMode = TIM_OCMode_PWM1;//Выравнивание по границе timerPWM.TIM_OutputState = TIM_OutputState_Enable;//активируем выход timerPWM.TIM_OCPolarity = TIM_OCPolarity_High;//Импульс это 3.3В

Инициализируем нужные каналы для таймеров, каналы ищем в юзер мануале:

TIM_OC2Init(TIM3, &timerPWM); TIM_OC4Init(TIM4, &timerPWM);

А теперь самое важное, настройка синхронизации. Необходимо сделать один таймер мастером, другой слейвом:

//Настройка синхронизации TIM_SelectOutputTrigger(TIM4, TIM_TRGOSource_Enable);//Конфигурируем мастера TIM_SelectMasterSlaveMode(TIM4, TIM_MasterSlaveMode_Enable);//Задаем режим TIM_SelectInputTrigger(TIM3, TIM_TS_ITR3);//Конфигурируем подчиненного,
//используем триггер TIM4 канал 4, но нумерация с нуля, поэтому TIM_TS_ITR3 TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Gated);//режим стробирования

Если нам нужно сделать отставание, допустим на пол периода, то необходимо задать начальное значение счета подчиненного таймера равное половине периода. Для полной синхронизации счет начинаем с 0:

TIM3->CNT = 10;//Период 20, поэтому чтоб начать с половины пишем 10
//отставание в четверть это 5, в три четверти это 15

Активируем таймеры:

TIM_Cmd(TIM3, ENABLE);//Обязательно сначала слейв TIM_Cmd(TIM4, ENABLE);//А потом уже мастер

Выкладываю весь код полностью:

#include "stm32l1xx.h" //Для ШИМ
const uint32_t Period = 20 - 1;//переменная периода
const uint32_t prescaler = 1 - 1;
const uint32_t pulse = 15; void initPWM()
{ GPIO_InitTypeDef port; TIM_TimeBaseInitTypeDef timer; TIM_OCInitTypeDef timerPWM; //активация переферии RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); // настройка выхода PB5, PB9 GPIO_StructInit(&port); port.GPIO_Mode = GPIO_Mode_AF; port.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_9; port.GPIO_Speed = GPIO_Speed_2MHz; port.GPIO_OType = GPIO_OType_PP; GPIO_Init(GPIOB, &port); //активация альтернативной функции выхода PB5 GPIO_PinAFConfig(GPIOB,GPIO_PinSource5,GPIO_AF_TIM3);
//активация альтернативной функции выхода PB9 GPIO_PinAFConfig(GPIOB,GPIO_PinSource9,GPIO_AF_TIM4); //настройка таймера TIM_TimeBaseStructInit(&timer); timer.TIM_ClockDivision = TIM_CKD_DIV1; timer.TIM_CounterMode = TIM_CounterMode_Up; timer.TIM_Prescaler = prescaler; timer.TIM_Period = Period; TIM_TimeBaseInit(TIM4, &timer); TIM_TimeBaseInit(TIM3, &timer); TIM_OCStructInit(&timerPWM); timerPWM.TIM_Pulse = pulse; timerPWM.TIM_OCMode = TIM_OCMode_PWM1; timerPWM.TIM_OutputState = TIM_OutputState_Enable; timerPWM.TIM_OCPolarity = TIM_OCPolarity_High; TIM_OC2Init(TIM3, &timerPWM); TIM_OC4Init(TIM4, &timerPWM);
//Настройка синхронизации TIM_SelectOutputTrigger(TIM4, TIM_TRGOSource_Enable);//Конфигурируем мастера TIM_SelectMasterSlaveMode(TIM4, TIM_MasterSlaveMode_Enable); TIM_SelectInputTrigger(TIM3, TIM_TS_ITR3);//Конфигурируем подчиненного TIM_SelectSlaveMode(TIM3, TIM_SlaveMode_Gated); TIM3->CNT = 5;
// TIM_Cmd(TIM4, ENABLE); TIM_Cmd(TIM3, ENABLE); TIM_Cmd(TIM4, ENABLE);
} int main()

}

Вот собственно и все. В моей задаче нужно было управлять двумя шаговыми двигателями. Дополнительно еще писался код для плавного разгона, начинал работу с более длинным периодом и постепенно его уменьшал функцией TIM_SetAutoreload.


Оставить комментарий

Ваш email нигде не будет показан
Обязательные для заполнения поля помечены *

*

x

Ещё Hi-Tech Интересное!

[Перевод] Учёные вырастили универсальные стволовые клетки при помощи CRISPR инженерии

Клетки сердечной мышцы человека, полученные из новых универсальных стволовых клеток Учёные из University of California San Francisco впервые вырастили универсальные стволовые клетки, используя технологию редактирования генов CRISPR в целях получения плюрипотентных стволовых клеток, которые могут быть трансплантированы любому пациенту, не ...

[Перевод] Шесть историй, как код переписали с нуля

Новый взгляд на извечный вопрос: следует ли переписывать приложение с нуля или это «самая худшая стратегическая ошибка, которую может сделать разработчик программного обеспечения»? Оказывается, при работе со зрелой кодовой базой есть более двух вариантов ответа. «Исходный код словно заржавел!» — Джоэл ...