简体   繁体   English

使用STM32L TIM PWM控制伺服电机

[英]Using STM32L TIM PWM to control Servo Motor

So I'm trying to control a servo by PWM using STM32L1. 因此,我试图使用STM32L1通过PWM控制伺服器。 below is the full code, no library needed. 下面是完整的代码,不需要库。 When I upload and run this code, the servo ticks several times instead of actually moving smoothly to the required positions 600(0*), 1100(50*), 1600(100*), and 2100(150*). 当我上传并运行此代码时,伺服器会滴答几次,而不是实际平稳地移动到所需位置600(0 *),1100(50 *),1600(100 *)和2100(150 *)。 I believe this is related to the prescale value calculation, plus I'm not sure whether mentioning the ARR in micro-seconds is correct, if not, how do I configure it to read microseconds instead of milliseconds. 我相信这与预分频值的计算有关,而且我不确定以微秒为单位提到ARR是否正确,如果不正确,我如何将其配置为读取微秒而不是毫秒。 Please refer to the notes in the code for further details. 请参考代码中的注释以获取更多详细信息。

#include <stdio.h>
#include "stm32l1xx.h"             
 // Keil::Device:Startup

 // initialization of GPIOB
void TIM4_Init(){
RCC->AHBRSTR |= RCC_AHBRSTR_GPIOARST;       /* Reset GPIOB clock         */
RCC->AHBENR |= RCC_AHBENR_GPIOBEN;           /* Enable GPIOB clock         */
GPIOB->MODER   &=   ~(0x03 << (2*6));       /* Clear bit 11 & 12 Alternate mode*/
GPIOB->MODER   |=   0x02 << (2*6);          /* set as Alternate mode*/
GPIOB->OSPEEDR &=   ~(0x03<< (2*6));        /* 40 MHz  speed        */
GPIOB->OSPEEDR |=   0x03<< (2*6);           /* 40 MHz  speed        */
GPIOB->PUPDR &=         ~(1<<6);            /* NO PULL-UP PULL-DOWN        */
GPIOB->OTYPER &=        ~(1<<6);            /* PUSH-PULL        */
GPIOB->AFR[0] |=        0x2 << (4*6);       /* Pin6 set as alternate function 2 (TIM4) */

RCC->APB1ENR |= RCC_APB1ENR_TIM4EN;
TIM4->PSC = 16; //prescale value, AHB/APB1 Fmax=32MHz / 2
TIM4->ARR = 20000-1; //motor Freq = 50Hz, Period(ARR)= 1/50 = 20000us


// initialization of TIM & PWM

TIM4->CCMR1 |= TIM_CCMR1_OC1M;  // 111: PWM mode 2 - In upcounting, channel 1 is inactive 
                               //as long as TIMx_CNT<TIMx_CCR1 else active. 
                              // In downcounting, channel 1 is active as long as 
                             //TIMx_CNT>TIMx_CCR1 else inactive.

TIM4->CCMR1 |= TIM_CCMR1_OC1PE;
TIM4->CR1 |= TIM_CR1_ARPE;
TIM4->CCER |= TIM_CCER_CC1E;
TIM4->EGR |= TIM_EGR_UG;
TIM4->SR &= ~TIM_SR_UIF;
TIM4->DIER |= TIM_DIER_UIE;
TIM4->CR1 |= TIM_CR1_CEN;
}

// set servo to 4 positions in sequence

int main(void){

int i;

int position=600; // initial motor position

TIM4_Init();

while (1){  

if ((position >=600)|| (position <=2100))
position = position+500;      // motor positions will be 600(0*), 1100(50*), 1600(100*)
                             //, 2100(150*)
TIM4->CCR1 = position; 

for(i=0;i<1000;i++); // short delay


   }


 }  

That depends on your clock settings. 这取决于您的时钟设置。 You need to configure your clock first as many L1 have the default clock after the reset 2.097MHz only and the period with your settings is 0.152598951 sek, and the pulse width received by the servo is 0.07 to 0.15sek which is ~75times to long (I presume that PCS should be 15 to archive 16*20000 clocks period). 您需要首先配置时钟,因为只有在重设2.097MHz之后,许多L1都将具有默认时钟,并且设置的周期为0.152598951 sek,并且伺服器接收的脉冲宽度为0.07至0.15sek,约为75倍长(我认为PCS应该为15,以存档16 * 20000个时钟周期。 With your setting the timer clock should be more than 100MHz which is impossible for L1 根据您的设置,计时器时钟应大于100MHz,这对于L1是不可能的

Timers count ticks and how long the tick takes depends on the clock speed, and timer clock dividers. 计时器计数滴答声,滴答声需要多长时间取决于时钟速度和计时器时钟分频器。

To archive 20ms you need to leave PSC with zero value and ARR = 41939 要归档20ms,您需要将PSC保留为零值且ARR = 41939

Of course do 1ms will be 2097 and 2ms - 4194 当然1ms将是2097,而2ms-4194

You need to calculate the correct values 您需要计算正确的值

The easiest way to configure PLL is using the WYSIWYG CubeMX clock editor 配置PLL的最简单方法是使用WYSIWYG CubeMX时钟编辑器

It really depends on your clock settings, as @PeterJ mentioned. 正如@PeterJ所提到的,这实际上取决于您的时钟设置。 I will just put some more precision here. 我将在这里提出一些更高的精度。

Your ARR seems fine, as it's clear to read that your period is 20ms. 您的ARR看起来不错,因为可以清楚地看到您的周期为20ms。

But your PSC then should be set depending on the ARR in order to reach 1kHz. 但是,应根据ARR设置PSC,以达到1kHz。 For that you have to know the clock frequency. 为此,您必须知道时钟频率。

A side note, the PSC value should be 1 unit less than desired (like if you want 16, you should write 15 to the register), according to the stm documentation. 附带说明,根据stm文档,PSC值应比期望值小1个单位(例如,如果您希望16,则应将15写入寄存器)。

The counter clock frequency CK_CNT is equal to fCK_PSC / (PSC[15:0] + 1) 计数器时钟频率CK_CNT等于fCK_PSC /(PSC [15:0] +1)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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