Generar onda sinusoidal con PWM en el programa C - STM32F100RB

-3

Estoy tratando de generar ondas sinusoidales desde mi microcontrolador (STM32F100RB) mediante el uso de PWM en C. Me gustaría generar ondas sinusoidales y para hacerlo necesitaría variar el ancho del pulso. Estoy tratando de programar múltiples ciclos de trabajo diferentes para crear estas ondas sinusoidales. Hasta ahora, este código solo proporciona un ciclo de trabajo constante del 50%. ¿Alguien sabe cómo podría realizar múltiples ciclos de trabajo diferentes?

#include "stm32f10x.h"

#include stm32f10x_gpio.h

#include stm32f10x_rcc.h

#include stm32f10x_tim.h

int main(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;
  TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
  TIM_OCInitTypeDef TIM_OCInitStructure;
  uint32_t Prescaler, Period;

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 
  GPIO_Init(GPIOA, &GPIO_InitStructure);


  Prescaler = (SystemCoreClock / 400000);
  Period = 20000;

  TIM_TimeBaseStructure.TIM_Prescaler = (uint16_t)(Prescaler - 1);
  TIM_TimeBaseStructure.TIM_Period = (uint16_t)(Period - 1);
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; 
  TIM_TimeBaseStructure.TIM_ClockDivision = 0; // Not used
  TIM_TimeBaseStructure.TIM_RepetitionCounter = 0; // Not used
  TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);


  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
  TIM_OCInitStructure.TIM_Pulse = (uint16_t)(Period / 2); // 50%
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
  TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_Low;
  TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
  TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset;

  TIM_OC1Init(TIM1, &TIM_OCInitStructure);


  TIM_Cmd(TIM1, ENABLE);

  TIM_CtrlPWMOutputs(TIM1, ENABLE);

  while(1);
}

#ifdef USE_FULL_ASSERT
 void assert_failed(uint8_t* file, uint32_t line)
{

  while (1)
  {
  }
}

#endif
    
pregunta Michael Ojiaku

4 respuestas

1

¿Tal vez cambiar el período?

Una línea en tu código es:

TIM_OCInitStructure.TIM_Pulse = (uint16_t)(Period / 2); // 50% 

Cambie el divisor para satisfacer sus necesidades. Por ejemplo, para lograr el 33% del ciclo de trabajo:

TIM_OCInitStructure.TIM_Pulse = (uint16_t)(Period / 3); // 33%

Esto es principalmente adivinar porque el código que publicaste es muy ilegible.

    
respondido por el Martin Tramšak
1

Lo que debes hacer es cambiar el período de Pulso al final de cada ciclo (PWM_Periodo).

En los procesadores ARM esto es fácil de hacer .....      Encender interrupciones de fin de ciclo.      Escriba un método de servicio de interrupción para pasar el pulso cíclicamente a través de una tabla de valores que representa la onda sinusoidal (u otra) que desea generar.

Para activar las interrupciones, debe configurar el NVIC.

Al utilizar DMA en modo cíclico, puede hacer que DMA realice un ciclo a través de su tabla. Mire algunos de los procesadores ARM de nivel superior con DAC. El código que quieras será muy similar.

Luego usa STM_Cube para escribir la mayor parte del código para ti :-)

    
respondido por el ChrisR
1

No estoy muy familiarizado con tu código, pero tienes una línea:

  TIM_OCInitStructure.TIM_Pulse = (uint16_t)(Period / 2); // 50%

Esta línea está configurando de alguna manera su ciclo de trabajo. Parece que estás usando alguna biblioteca. Dentro del temporizador, hay un registro de ciclo de trabajo, no sé cómo se llama, pero todos los temporizadores con módulos PWM los tienen. Encuéntralo.

Versión de punto flotante:

void setDutyCycle(float dutyCyclePercentage){
    <duty cycle register> = (unsigned int)(<period register> * dutyCyclePercentage);
}

Versión de punto fijo:

void setDutyCycle(signed int dutyCyclePercentageFixed){
    <duty cycle register> = q15_mul(<period register>,dutyCyclePercentage);
}

Me gusta usar libmathq15, que está dirigido a procesadores de 16 bits, pero funcionará bien en todas las arquitecturas, pero con menos ventajas.

También puede consultar enlace

    
respondido por el slightlynybbled
0

Realmente no leí tu código.

Piense en la salida PWM como un DAC de un bit. A medida que el ciclo de trabajo varía de 0% a 100%, el voltaje de su "DAC" varía de 0 a VCC.

Por lo tanto, debe crear de alguna manera un flujo de datos que represente una onda sinusoidal (numéricamente) y alimentar ese flujo de datos al registro de ciclo de trabajo del PWM. Debe actualizar el registro de ciclo de trabajo PWM una vez por período de ciclo de trabajo. El tiempo debe gestionarse para que el nuevo ciclo de trabajo entre en vigencia después de que expire el actual.

Dado que su código se ejecuta en un microcontrolador, no intente ejecutar funciones trigonométricas. Lo que usted querrá hacer es crear un software DDS. Utiliza una variable como acumulador de fase. La fase de una onda sinusoidal aumenta linealmente, y vuelve a cero a 2 * PI. Por lo tanto, solo puede incrementar un tipo entero sin cadena (este es su acumulador de fase). Utilice la cantidad de bits que desee en su acumulador de fase.

Luego tome los 8 bits principales de su fase y úselo para ingresar a la tabla de búsqueda. La tabla de búsqueda le dará sus datos de salida. Puedes usar más bits para tu tabla de búsqueda, pero el tamaño se volverá rápidamente inmanejable.

La tabla de búsqueda debe calcularse previamente en una PC o con una hoja de cálculo o algo así, y pegarse en su programa antes de la compilación.

Espero que ayude.

    
respondido por el mkeith

Lea otras preguntas en las etiquetas