Использование STM32L TIM PWM для управления серводвигателем

Поэтому я пытаюсь управлять сервоприводом с помощью ШИМ, используя STM32L1. ниже приведен полный код, библиотека не требуется. Когда я загружаю и запускаю этот код, сервопривод тикает несколько раз вместо того, чтобы фактически плавно перемещаться в требуемые позиции 600(0*), 1100(50*), 1600(100*) и 2100(150*). Я полагаю, что это связано с вычислением значения до масштабирования, плюс я не уверен, правильно ли упоминать ARR в микросекундах, если нет, то как мне настроить его на чтение микросекунд вместо миллисекунд. Пожалуйста, обратитесь к примечаниям в коде для получения дополнительной информации.

#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


   }


 }  

2 ответа

Решение

Это зависит от ваших настроек часов. Вам необходимо сначала настроить часы, так как многие L1 имеют часы по умолчанию только после сброса 2,097 МГц, и период с вашими настройками составляет 0,152598951 сек, а длительность импульса, получаемого сервоприводом, составляет от 0,07 до 0,15 сек, что составляет ~75 раз в длину (Я предполагаю, что PCS должно быть 15, чтобы архивировать период 16*20000 часов). С вашей настройкой таймер должен быть больше 100 МГц, что невозможно для L1

Таймеры подсчитывают тики, и длительность тика зависит от тактовой частоты и делителей таймера.

Для архивирования 20 мс необходимо оставить PSC с нулевым значением и ARR = 41939

Конечно, 1 мс будет 2097, а 2 мс - 4194

Вам необходимо рассчитать правильные значения

Самый простой способ настроить PLL - использовать редактор часов WYSIWYG CubeMX

Это действительно зависит от ваших настроек часов, как упоминал @PeterJ. Я просто добавлю немного точности здесь.

Ваш ARR кажется нормальным, поскольку ясно, что ваш период составляет 20 мс.

Но тогда ваш PSC должен быть установлен в зависимости от ARR для достижения 1 кГц. Для этого вам нужно знать тактовую частоту.

Примечание: значение PSC должно быть на 1 единицу меньше желаемого (например, если вы хотите 16, вы должны записать 15 в регистр), в соответствии с документацией stm.

Тактовая частота счетчика CK_CNT равна fCK_PSC / (PSC[15:0] + 1)

Другие вопросы по тегам