veydlin
@veydlin
Мне никогда не жалко средств на свое любопытство

Почему глючит сервопривод в FreeRTOS?

Начинаю только переходить на STM после AVR
Так же мой первый опыт работы с вытесняющий RTOS, до этого использовал только кооперативные.
Пример от сюда

При попытки встроить в RTOS сервопривод начинает сходить с ума
#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"
#include "misc.h"

#include "FreeRTOS.h" // Подключаем FreeRTOS
#include "task.h" // Переключение задач



// Функция устанавливает позицию вала (в градусах)
#define SERVO_180 8200
#define SERVO_0 1800
void set_pos(uint8_t pos) {
	uint32_t tmp = (SERVO_180 - SERVO_0) / 180;
	TIM2->CCR2 = SERVO_0 + tmp * pos;
}



// Крутим сервопривод
void servo_task(void *pvParameters) {
	uint8_t i;
	while(1) {
		for(i = 0; i <= 180; i += 10) {
			vTaskDelay(10);
			set_pos(i);
		}
	}
}


// Мигаем светодиодом
void led_task(void *pvParameters) {
	while(1) {
		GPIOC->ODR |= (GPIO_Pin_8);
		vTaskDelay(1000);
		GPIOC->ODR &= ~(GPIO_Pin_8);
		vTaskDelay(1000);
	}

}


int main(void) {

	// Настраиваем порт A
	GPIO_InitTypeDef PORT_A;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // Тактируем
	PORT_A.GPIO_Pin = (GPIO_Pin_1);
	PORT_A.GPIO_Mode = GPIO_Mode_AF_PP; // Будем использовать альтернативный режим, а не обычный GPIO
	PORT_A.GPIO_Speed = GPIO_Speed_2MHz;
	GPIO_Init(GPIOA, &PORT_A);


	// Настраиваем порт С
	GPIO_InitTypeDef PORT_C;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
	PORT_C.GPIO_Pin = (GPIO_Pin_9 | GPIO_Pin_8);
	PORT_C.GPIO_Mode = GPIO_Mode_Out_PP;
	PORT_C.GPIO_Speed = GPIO_Speed_2MHz;
	GPIO_Init(GPIOC, &PORT_C);


	// Настраиваем таймер таймер 2
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); // Тактируем
	TIM2->CCER |= (TIM_CCER_CC2E); // Разрешаем таймеру использовать ногу PA1 для ШИМа
	TIM2->CCMR1 |= (TIM_CCMR1_OC2M_1 | TIM_CCMR1_OC2M_2);
	TIM2->PSC = 6; // Настраиваем предделитель, чтобы частота ШИМа была в районе 50 Гц
	TIM2->CR1 |= TIM_CR1_CEN; // Запускаем


	// Создаем задачи для ОС
	xTaskCreate(servo_task, (signed char*)"servo", configMINIMAL_STACK_SIZE, NULL, 2, (xTaskHandle*)NULL);
	xTaskCreate(led_task, (signed char*)"led", configMINIMAL_STACK_SIZE, NULL, 2, (xTaskHandle*)NULL);


	// Пинаем планировщик
	vTaskStartScheduler();
};
  • Вопрос задан
  • 824 просмотра
Решения вопроса 1
jcmvbkbc
@jcmvbkbc
http://dilbert.com/strip/1998-08-24
#define SERVO_180 8200
#define SERVO_0 1800
void set_pos(uint8_t pos) {
  uint32_t tmp = (SERVO_180 - SERVO_0) / 180;
  TIM2->CCR2 = SERVO_0 + tmp * pos;
}

Фуфуфу, сначала умножать, потом делить, иначе потеряете в точности и получите большой недобор на больших углах.
Кроме того, сдаётся мне, что эта формула должна выглядеть так:
uint32_t tmp = ((SERVO_180 - SERVO_0) * pos) / 180 + SERVO_0;
  TIM2->CCR2 = tmp;

не?
сервопривод начинает сходить с ума

Вы бы описали, как именно.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы