简体   繁体   中英

How to Generate PWM for control servo motor on STM32F103 with Timer

How to Generate PWM for control servo motor on STM32F103 with Timer C code i want control servo motor by PWM i get value from ADC then calculate to PWM duty cycle

Flow chart get value of VR --> ADC module (convert Analog to Digital) --> calculate PWM Duty cycle --> use Timer to generate PWM for control servo motor --> while loop

sorry for my english lang.

This code assumes APB1 clock = 72MHz Servo_Target as eighth of microseconds so 4000 means 1ms (low servo position) and 8000 means 2ms (high servo position) WARNING: the PWM frequency is 463Hz SO YOU CANNOT USE THIS SETTING FOR ANALOG SERVO. IT WORKS FOR BRUSHELESS REGULATORS. IF YOU WANT USE FOR ANALOG SERVO YOU HAVE TO CHANGE TIM_Prescaler, TIM_Period and take in accounts the effect on Servo_Target values

TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode   = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_Period        = 8192;                       
TIM_TimeBaseStructure.TIM_Prescaler     = 18;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
TIM_Cmd(TIM2, ENABLE);  // Start PWM Timer
TIM_OCInitStructure.TIM_OCMode      = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_OCPolarity  = TIM_OCPolarity_High;

// THIS IS THE WIDTH in 1/8 us
TIM_OCInitStructure.TIM_Pulse       = Servo_Target;     

/* PWM1 Mode configuration: TIM2 Channel1 */
TIM_OC1Init(TIM2, &TIM_OCInitStructure);
TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Enable);

/* PWM1 Mode configuration: TIM2 Channel2 */
TIM_OC2Init(TIM2, &TIM_OCInitStructure);
TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable);

// add OC3_ and OC4_ for 3rd and 4th channels    
TIM_ARRPreloadConfig(TIM2, ENABLE);

I assume you are using an IDE and writing in C, but I am not familiar with this device.

Basically, you need to use timers, of which there are several on the device, and write interrupt handlers for "output compare" interrupts. If an output compare interrupt is enabled, then every time the value in the timer matches the value in a certain register, your handler gets called.

A common technique is to have the handler toggle the pin to the servo, then change the value in the output compare register to make the handler fire again when you next need it to.

if(off)
   turn pin on
   ocreg += pwm_value
else
   turn pin off
   ocreg += cycle-pwm_value

The pin will stay on for the right length of time, and always turn on at the same frequency. You need to find good values for these variables based on the servo specifications.

You can use another timer to sample the ADC on a regular schedule, or build it in to the same interrupt handler as the PWM, or even just let it run in a busy loop waiting for the ADC to finish.

main()
  loop
    start ADC
    while (ADC busy) { do nothing }
    calculate pwm and store in variable pwm_value
    loop

Depending on the servo specs, you may have to modify these slightly to prevent cycle drift, but servos are generally pretty forgiving.

You need to find examples of interrupt handler syntax for your compiler, and always read the manual on how to use the registers to control the timers and enable interrupts.

Good luck, and post a new question with some code when you have more completed.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM