这是一个新的栏目,用于记录硬件方面学习的历程。
之前硬件学习是比较零散的,没有系统性的整理过,希望这个栏目的开设能让我的学习更加系统。
注:本栏目是在学习进程中新增的,内容无任何顺序、关联。
仅是个人记录用,不适合学习者观看。
电机接口为6PIN 排线,左右两根为电机正负极,接至L298N的一个电机口
中间四根为编码器线路,外两根为编码器电源,最中间两根为编码器脉冲输出
12V供电
L298N使用PWM控制时需要拔掉跳线帽,并通过BIN1和BIN2的电平高低控制正反转(4根线连接至F103,分别为PWM、GND、BIN1、BIN2)
ams1117 -5.0给予5V供电
3根线接至F103,分别为脉冲2条、GND
F103总共有4个定时器,配置如下:
TIM1——空
TIM2——转速采样,100HZ
TIM3——2频道,PWM信号时钟,10kHZ ,对应PA7输出PWM
TIM4——编码器计数模式,上升沿触发,对应PB6/7接编码器
当TIM2计时,回调函数获取电机脉冲并换算为速度,输入到PID控制器中,PID控制器输出占空比到L298N
此处图片存在错误,增量式PID中的OUT无需+=,因为后面的return已经加上原始值。
注意增量PID和位置PID输出值的区别!!
#ifndef __CONTROL_H
#define __CONTROL_H
//全局变量
extern unsigned int MotorSpeed;
extern int SpeedTarget;
extern int MotorOutput;
//函数声明
void GetMotorPulse(void);
int SpeedInnerControl(int Speed,int Target);
void SetMotorVoltageAndDirection(int Pwm);
#endif
#include "control.h"
#include "tim.h"
#include "main.h"
#include "math.h"
unsigned int MotorSpeed;//全局变量,电机当前速度数值,在encoder.c中获取
int SpeedTarget = 300; //全局变量,速度目标值
int MotorOutput; //全局变量,电机输出
//1.通过TIM4读取电机脉冲并计算速度
void GetMotorPulse(void)
{
MotorSpeed = (short)(__HAL_TIM_GET_COUNTER(&htim4)/10);//TIM4计数器获得电机脉冲,该电机在10ms采样的脉冲/10则为实际转速的rpm
__HAL_TIM_SET_COUNTER(&htim4,0);//计数器清零
}
//2.增量式PID控制器
int Error_Last,Error_Prev;//上一次偏差值,上上次误差
int Pwm_add,Pwm;//PWM增量,PWM输出占空比
float Kp = 10.0, Ki = 0.9, Kd = 0.0;//PID系数
int SpeedInnerControl(int Speed,int Target)//速度内环控制
{
int Error = Speed - Target; //偏差 = 目标速度 - 实际速度
Pwm_add = Kp * (Error - Error_Last) + //比例
Ki * Error + //积分
Kd * (Error - 2.0f * Error_Last + Error_Prev); //微分
Pwm += Pwm_add; //原始量+增量=输出量
Error_Prev = Error_Last; //保存上上次误差
Error_Last = Error; //保存上一次偏差
if(Pwm > 100) Pwm = 100; //限制上下限,防止超出PWM量程
if(Pwm <-100) Pwm =-100;
return Pwm; //返回输出值
}
//3.电机电压和方向控制函数
void SetMotorVoltageAndDirection(int Pwm)
{
if(Pwm < 0)//如果是反转
{
HAL_GPIO_WritePin(BIN1_GPIO_Port, BIN1_Pin, GPIO_PIN_SET);//L298N反向
HAL_GPIO_WritePin(BIN2_GPIO_Port, BIN2_Pin, GPIO_PIN_RESET);
Pwm = (-Pwm);//如果计算值是负值,先取负得正,因为PWM寄存器只能是正值
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, Pwm);//输出
} else
{
HAL_GPIO_WritePin(BIN1_GPIO_Port, BIN1_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(BIN2_GPIO_Port, BIN2_Pin, GPIO_PIN_SET);
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_2, Pwm);
}
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim == &htim2)
{
//1.获取电机速度
GetMotorPulse();
//2.PID控制器,取回占空比
MotorOutput = SpeedInnerControl(MotorSpeed,SpeedTarget);
//3.将占空比导入至电机控制函数
SetMotorVoltageAndDirection(MotorOutput);
}
}
使用Keil5自带Debug调试
使用STM32Studio调试
用手尝试让电机停止,观察控制效果
按住RST键在放开,可以观察到电机启动的曲线