写一个基于DSPIC系列单片机的位置单闭环PID控制有刷直流电机正反转,且电机不带编码器的完整程序,假设电机驱动芯片L298N,且利用霍尔传感器捕捉电机转的圈数
时间: 2023-07-15 07:15:04 浏览: 111
以下是一个基于DSPIC33EP系列单片机的位置单闭环PID控制有刷直流电机正反转的完整程序,假设电机驱动芯片为L298N,利用霍尔传感器捕捉电机转的圈数。
```
#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
// 定义PID参数
#define Kp 1.0
#define Ki 0.5
#define Kd 0.2
// 定义电机相关参数
#define PWM_PERIOD 3999 // PWM周期
#define PWM_DEADBAND 50 // 死区时间
#define HALL_SENSOR_CNT_PER_REV 6 // 每圈霍尔传感器数量
#define MOTOR_GEAR_RATIO 50 // 减速比
#define MOTOR_MAX_RPM 6000 // 电机最大转速
#define MOTOR_MAX_SPEED (MOTOR_MAX_RPM / 60 * HALL_SENSOR_CNT_PER_REV / MOTOR_GEAR_RATIO) // 电机最大速度
// 定义PID控制器状态
struct pid_state {
float target_pos; // 目标位置
float current_pos; // 当前位置
float last_error; // 上次误差
float integral_error; // 积分误差
};
// 初始化PID状态
void pid_init(struct pid_state *pid, float target_pos) {
pid->target_pos = target_pos;
pid->current_pos = 0;
pid->last_error = 0;
pid->integral_error = 0;
}
// 计算PID输出
float pid_compute(struct pid_state *pid, float current_pos) {
float error = pid->target_pos - current_pos;
pid->integral_error += error;
float derivative_error = error - pid->last_error;
pid->last_error = error;
float output = Kp * error + Ki * pid->integral_error + Kd * derivative_error;
return output;
}
int main() {
// 初始化IO口
TRISBbits.TRISB0 = 0; // PWM输出口
TRISBbits.TRISB1 = 1; // 霍尔传感器输入口
// 初始化PWM模块
PTCONbits.PTEN = 0; // 关闭PWM模块
PTCONbits.PTCKPS = 1; // 时钟分频位1:4
PTCONbits.PTOPS = 0; // 输出分频位1:1
PTPER = PWM_PERIOD; // 设置PWM周期
PWMCON1bits.PEN1H = 1; // P1H输出使能
PWMCON1bits.PEN1L = 1; // P1L输出使能
PWMCON2bits.POL1H = 0; // P1H非反相输出
PWMCON2bits.POL1L = 0; // P1L非反相输出
PWMCON2bits.DTC = 0b10; // 死区时间选择
IOCON1bits.PENH = 1; // PWM1H引脚设置为PWM输出
IOCON1bits.PENL = 1; // PWM1L引脚设置为PWM输出
IOCON1bits.PMOD = 0b11; // PWM1H/PWM1L引脚设置为PWM输出
// 初始化PID控制器
struct pid_state pid;
pid_init(&pid, 0);
// 初始化电机转速
float motor_speed = 0;
// 进入主循环
while (1) {
// 读取霍尔传感器状态
int hall_a = PORTBbits.RB1;
int hall_b = PORTBbits.RB2;
int hall_c = PORTBbits.RB3;
int hall_state = hall_a + hall_b * 2 + hall_c * 4;
// 计算电机转速
motor_speed = (float)MOTOR_MAX_SPEED / HALL_SENSOR_CNT_PER_REV * (float)hall_state / MOTOR_GEAR_RATIO;
// 计算PID输出
float pid_output = pid_compute(&pid, motor_speed);
// 根据PID输出调整电机PWM占空比
if (pid_output > 0) {
// 正转
PWMCON1bits.PEN1H = 0; // 关闭反相输出使能
PWMCON1bits.PEN1L = 1; // 打开非反相输出使能
PDC1 = (unsigned int)(pid_output / 100 * (float)PWM_PERIOD); // 设置PWM占空比
} else if (pid_output < 0) {
// 反转
PWMCON1bits.PEN1H = 1; // 打开反相输出使能
PWMCON1bits.PEN1L = 0; // 关闭非反相输出使能
PDC1 = (unsigned int)(-pid_output / 100 * (float)PWM_PERIOD); // 设置PWM占空比
} else {
// 停止
PWMCON1bits.PEN1H = 0; // 关闭反相输出使能
PWMCON1bits.PEN1L = 0; // 关闭非反相输出使能
PDC1 = 0; // 设置PWM占空比为0
}
}
return 0;
}
```
阅读全文