PWM Sync en STM32

No entraré particularmente en la teoría, hay muchos recursos en la red donde todo se describe con gran detalle. Pero cuando se trata de practicar, entiendes que todo es mucho más complicado. Se utiliza el microcontrolador stm32l152c-discovery. El artículo describirá el proceso de iniciar el PWM de dos temporizadores al mismo tiempo (sincronización completa):

imagen

Y también inicie con un retraso (en la foto hay un retraso en el piso del período):

imagen

Creemos una función para inicializar initPWM, declaremos variables en él por conveniencia

void initPWM() { const uint32_t Period = 20 - 1;//  const uint32_t prescaler = 1 - 1;// //-1      0 const uint32_t pulse = 15;//  } 

Primero debe inicializar las estructuras para configurar los temporizadores:

  GPIO_InitTypeDef port; TIM_TimeBaseInitTypeDef timer; TIM_OCInitTypeDef timerPWM; 

A continuación, activamos los periféricos que necesitamos. Usaremos TIM3 y TIM4, simplemente porque queríamos:

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

Activamos GPIOB, porque Las salidas del temporizador se encuentran en este bus PB5 y PB9. Esta información se puede encontrar en el manual del usuario del microcontrolador en la tabla Descripción del pin MCU versus función de la placa.

imagen

Configure las salidas en el modo de función alternativa:

  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); 

Ajuste el temporizador al modo PWM:

  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 

Inicializamos los canales necesarios para los temporizadores, buscamos canales en el manual del usuario:

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

Y ahora lo más importante es configurar la sincronización. Es necesario hacer que un temporizador sea maestro y el otro esclavo:

 //  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);//  

Si necesitamos retrasarnos, por ejemplo, en medio período, entonces necesitamos establecer el valor inicial de la cuenta del temporizador esclavo igual a la mitad del período. Para una sincronización completa, comenzamos la puntuación desde 0:

  TIM_SetCounter(TIM3, 10);// 20,       10 //    5,     15 

Activamos temporizadores:

  TIM_Cmd(TIM3, ENABLE);//   TIM_Cmd(TIM4, ENABLE);//    

Difundí todo el código por completo:

 #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); TIM_SetCounter(TIM3, 10); // TIM_Cmd(TIM4, ENABLE); TIM_Cmd(TIM3, ENABLE); TIM_Cmd(TIM4, ENABLE); } int main() { initPWM(); while(1) { } } 

Eso es todo En mi tarea, era necesario controlar dos motores paso a paso. Además, el código fue escrito para un overclocking suave, comenzó a funcionar con un período más largo y lo disminuyó gradualmente con la función TIM_SetAutoreload.

Source: https://habr.com/ru/post/es415523/


All Articles