STM32C8T6 电磁小车增量式 PID 控制编码电机代码示例
STM32C8T6 电磁小车增量式 PID 控制编码电机代码示例
以下是一个示例代码,演示了在 STM32C8T6 电磁小车上使用增量式 PID 控制编码电机,并在定时中断中读取电机的速度。
#include "stm32f10x.h"
#include "stm32f10x_tim.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"
#include "misc.h"
#define MOTOR_TIM TIM2
#define MOTOR_TIM_RCC RCC_APB1Periph_TIM2
#define MOTOR_GPIO_RCC RCC_APB2Periph_GPIOA
#define MOTOR_GPIO GPIOA
#define MOTOR_PIN1 GPIO_Pin_0
#define MOTOR_PIN2 GPIO_Pin_1
#define ENCODER_TIM TIM3
#define ENCODER_TIM_RCC RCC_APB1Periph_TIM3
#define ENCODER_GPIO_RCC RCC_APB2Periph_GPIOB
#define ENCODER_GPIO GPIOB
#define ENCODER_PIN1 GPIO_Pin_4
#define ENCODER_PIN2 GPIO_Pin_5
volatile int32_t motor_velocity = 0;
volatile int32_t target_velocity = 0;
float Kp = 1.0;
float Ki = 0.0;
float Kd = 0.0;
int32_t error_sum = 0;
int32_t last_error = 0;
void Motor_PWM_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
RCC_APB1PeriphClockCmd(MOTOR_TIM_RCC, ENABLE);
RCC_APB2PeriphClockCmd(MOTOR_GPIO_RCC | RCC_APB2Periph_AFIO, ENABLE);
GPIO_InitStructure.GPIO_Pin = MOTOR_PIN1 | MOTOR_PIN2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(MOTOR_GPIO, &GPIO_InitStructure);
TIM_TimeBaseStructure.TIM_Period = 20000 - 1;
TIM_TimeBaseStructure.TIM_Prescaler = 72 - 1;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(MOTOR_TIM, &TIM_TimeBaseStructure);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 0;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC1Init(MOTOR_TIM, &TIM_OCInitStructure);
TIM_OC1PreloadConfig(MOTOR_TIM, TIM_OCPreload_Enable);
TIM_ARRPreloadConfig(MOTOR_TIM, ENABLE);
TIM_Cmd(MOTOR_TIM, ENABLE);
}
void Encoder_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_ICInitTypeDef TIM_ICInitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(ENCODER_TIM_RCC, ENABLE);
RCC_APB2PeriphClockCmd(ENCODER_GPIO_RCC, ENABLE);
GPIO_InitStructure.GPIO_Pin = ENCODER_PIN1 | ENCODER_PIN2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(ENCODER_GPIO, &GPIO_InitStructure);
TIM_TimeBaseStructure.TIM_Period = 0xFFFF;
TIM_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(ENCODER_TIM, &TIM_TimeBaseStructure);
TIM_EncoderInterfaceConfig(ENCODER_TIM, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);
TIM_ICStructInit(&TIM_ICInitStructure);
TIM_ICInitStructure.TIM_ICFilter = 6;
TIM_ICInit(ENCODER_TIM, &TIM_ICInitStructure);
TIM_SetCounter(ENCODER_TIM, 0);
TIM_ITConfig(ENCODER_TIM, TIM_IT_Update, ENABLE);
NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
TIM_Cmd(ENCODER_TIM, ENABLE);
}
int32_t PID_Controller(int32_t target, int32_t current)
{
int32_t error = target - current;
int32_t output = Kp * error + Ki * error_sum + Kd * (error - last_error);
last_error = error;
error_sum += error;
return output;
}
void TIM3_IRQHandler(void)
{
if (TIM_GetITStatus(ENCODER_TIM, TIM_IT_Update) != RESET)
{
int16_t encoder_count = TIM_GetCounter(ENCODER_TIM);
motor_velocity = encoder_count;
TIM_SetCounter(ENCODER_TIM, 0);
TIM_ClearITPendingBit(ENCODER_TIM, TIM_IT_Update);
}
}
void TIM2_IRQHandler(void)
{
if (TIM_GetITStatus(MOTOR_TIM, TIM_IT_Update) != RESET)
{
int32_t current_velocity = motor_velocity;
int32_t output = PID_Controller(target_velocity, current_velocity);
// 设置PWM输出
TIM_OC1Init(MOTOR_TIM, &TIM_OCInitStructure);
TIM_SetCompare1(MOTOR_TIM, output);
TIM_ClearITPendingBit(MOTOR_TIM, TIM_IT_Update);
}
}
int main(void)
{
Motor_PWM_Config();
Encoder_Config();
// 初始化定时器,设置定时中断
TIM1_Config();
while (1)
{
// 在主循环中处理其他任务
}
}
在以上代码中,Motor_PWM_Config函数用于配置电机的 PWM 输出,Encoder_Config函数用于配置编码器,PID_Controller函数用于实现增量式 PID 控制。
在TIM3_IRQHandler中断处理函数中读取编码器的数值,计算电机的速度。
在TIM2_IRQHandler中断处理函数中,根据目标速度和当前速度,计算 PID 控制器的输出,并设置 PWM 占空比控制电机转动。
请注意,以上代码只是一个示例,实际应用中可能需要根据具体的编码器分辨率、PID 参数、电机和编码器的接口等进行相应的配置和调整。同时,还要根据具体的应用场景进行相应的功能实现和优化。
使用说明:
- 将代码移植到 STM32C8T6 开发板上。
- 根据实际情况修改电机和编码器的引脚定义以及 PID 参数。
- 运行程序,观察电机转动情况,并根据需要调整 PID 参数。
注意事项:
- 代码中使用了 STM32F10x 库函数,请确保您已经安装了该库。
- 编码器分辨率、PID 参数以及电机和编码器的接口等需要根据实际情况进行调整。
- 代码中省略了部分代码,例如 TIM1_Config() 函数的实现,请根据实际需要自行补充。
- 以上代码仅供参考,实际应用中可能需要根据具体的应用场景进行相应的修改和优化。
原文地址: https://www.cveoy.top/t/topic/TFU 著作权归作者所有。请勿转载和采集!