PIC18F87J50开发板直流电机驱动与PID控制实战
📅 2026/7/8 14:34:07
👁️ 阅读次数
📝 编程学习
1. EasyPIC PRO v7a开发板与PIC18F87J50芯片的硬件适配
EasyPIC PRO v7a是一款支持双电压(3.3V和5V)的通用型开发板,这个特性使其能够兼容市面上绝大多数PIC系列微控制器。板载的PIC18F87J50是一款高性能8位MCU,具有128KB闪存和近4KB RAM,特别适合电机控制应用。
开发板上已经集成了电机驱动所需的关键外设接口:
- 4个可配置PWM输出通道
- 10位ADC模数转换器
- 多个数字I/O端口
- 板载稳压电路可直接为电机供电
注意:虽然开发板支持5V操作,但连接外部电机时建议使用独立电源,避免开发板电源过载。
2. 直流电机驱动电路设计
2.1 H桥驱动原理
控制直流电机正反转需要H桥电路,常见方案有:
- 分立元件搭建:使用4个MOSFET(如IRF540N)构成全桥
- 集成驱动芯片:L298N(2A)或DRV8871(3.6A)等
对于PIC18F87J50的3.3V逻辑电平,需要确保驱动芯片兼容低电压控制。实测中,带光耦隔离的L298N模块表现稳定,接线方式如下:
| 开发板引脚 | L298N接口 | 功能说明 |
|---|---|---|
| RD0 | IN1 | 方向控制1 |
| RD1 | IN2 | 方向控制2 |
| RC2 | ENA | PWM调速 |
| +12V | VCC | 电机电源 |
| GND | GND | 共地 |
2.2 电流保护设计
直流电机启动时会产生5-10倍额定电流的冲击,必须添加:
- 快恢复二极管(如1N5822)续流保护
- 0.1μF陶瓷电容并联在电机两端滤波
- 自恢复保险丝(如16V/5A)串联在电源回路
3. 电机控制固件开发
3.1 PWM配置代码示例
// 初始化PWM模块 void PWM_Init(void) { PR2 = 0xFF; // PWM周期= (PR2+1)*4*Tosc*TMR2预分频 T2CON = 0b00000100; // TMR2开启,预分频1:1 CCP1CON = 0b00001100; // PWM模式 CCPR1L = 0x80; // 50%占空比初始值 TRISCbits.TRISC2 = 0; // CCP1引脚输出 } // 调速函数 void SetMotorSpeed(uint8_t speed) { if(speed > 100) speed = 100; CCPR1L = (uint8_t)((float)PR2 * speed / 100.0); }3.2 方向控制逻辑
通过两个GPIO实现H桥的使能控制:
#define MOTOR_FWD() {LATDbits.LATD0=1; LATDbits.LATD1=0;} #define MOTOR_REV() {LATDbits.LATD0=0; LATDbits.LATD1=1;} #define MOTOR_STOP() {LATDbits.LATD0=0; LATDbits.LATD1=0;} void Motor_Ctrl(uint8_t dir, uint8_t speed) { switch(dir) { case 0: MOTOR_STOP(); break; case 1: MOTOR_FWD(); break; case 2: MOTOR_REV(); break; } SetMotorSpeed(speed); }4. 闭环速度控制实现
4.1 编码器信号采集
对于带编码器的直流电机,可通过以下方式获取转速:
- 正交编码器接口:使用PIC18F87J50的CCP模块捕获脉冲
- 霍尔传感器:配置Timer1作为计数器
// 编码器脉冲计数初始化 void Encoder_Init(void) { T1CON = 0b10000111; // 外部时钟源,1:256预分频 TMR1H = TMR1L = 0; // 计数器清零 } // 读取当前转速(RPM) uint16_t GetMotorRPM(void) { uint16_t counts = (TMR1H << 8) | TMR1L; TMR1H = TMR1L = 0; // 计数器复位 return (counts * 60) / ENCODER_PPR; // PPR=编码器每转脉冲数 }4.2 PID调速算法实现
增量式PID控制代码示例:
typedef struct { float Kp, Ki, Kd; float lastError, integral; } PID_Controller; float PID_Update(PID_Controller *pid, float setpoint, float actual) { float error = setpoint - actual; float derivative = error - pid->lastError; pid->integral += error; float output = pid->Kp * error + pid->Ki * pid->integral + pid->Kd * derivative; pid->lastError = error; return output; } // 使用示例 PID_Controller speedPID = {0.8, 0.05, 0.1, 0, 0}; uint8_t targetRPM = 1000; void ControlLoop(void) { uint16_t actualRPM = GetMotorRPM(); float pwm = PID_Update(&speedPID, targetRPM, actualRPM); SetMotorSpeed((uint8_t)constrain(pwm, 0, 100)); }5. 系统优化与调试技巧
5.1 PWM频率选择
直流电机控制的PWM频率建议范围:
- 有刷电机:5kHz-20kHz(超过20kHz可能因MOSFET开关损耗降低效率)
- 无刷电机:8kHz-16kHz(需匹配电调规格)
计算公式: [ F_{PWM} = \frac{F_{osc}}{4 \times (PR2+1) \times N} ] 其中N为TMR2预分频值(1/4/16)
5.2 抗干扰布线要点
- 电机电源与MCU电源完全隔离
- 信号线使用双绞线或屏蔽线
- 所有数字地单点连接到电源地
- 在MCU电源引脚就近放置0.1μF去耦电容
5.3 常见问题排查
电机抖动不转:
- 检查H桥使能信号逻辑是否正确
- 测量PWM引脚实际输出波形
- 确认电源电压满足电机启动需求
转速控制不稳定:
- 调整PID参数(先用纯P调节,稳定后再加I和D)
- 检查编码器连接是否松动
- 增加速度采样滤波算法
我在实际项目中发现,对于12V/2A以下的直流电机,使用L298N模块时建议:
- 在ENABLE引脚串联100Ω电阻保护MCU
- 电机电源端并联470μF电解电容
- 调试时先用示波器观察PWM波形,再连接电机
编程学习
技术分享
实战经验