3、电机控制硬件接口:增量式编码器接口、霍尔传感器接口、PWM输出与电流采样
好,咱们进入第三讲。这一讲全是硬功夫——硬件接口。
做电机控制,说白了就是三件事:知道转子在哪儿、告诉功率管怎么开关、把电流读回来。这三件事分别对应编码器/霍尔、PWM输出、电流采样。我这些年踩过的坑,有一半都出在这几个接口上。
3.1 增量式编码器接口
增量式编码器,我习惯叫它“增量码盘”。它不告诉你绝对位置,只告诉你“动了多少”。
核心信号就两路:A相和B相。 相位差90度,正转A超前B,反转B超前A。有些编码器还有Z相——一圈一个脉冲,用来找零点。
在CANopenNode里,编码器数据通常映射到对象字典的0x6000系列。但底层驱动你得自己写。
关键点: 编码器接口的实时性要求很高。我一般用定时器的编码器模式,硬件自动计数,CPU只管读值。
拿STM32举例,配置代码大概这样:
// 定时器编码器模式配置
TIM_EncoderInterfaceConfig(TIM2, TIM_ENCODERMODE_TI12,
TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);
TIM_EncoderInterfaceConfig(TIM3, TIM_ENCODERMODE_TI12,
TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);
// 使能定时器
TIM_Cmd(TIM2, ENABLE);
TIM_Cmd(TIM3, ENABLE);
嗯,这里要注意:编码器线数。比如2500线的编码器,经过4倍频后,一圈就是10000个脉冲。你的位置变量得够大,别溢出。
我的习惯: 位置变量用32位有符号整型。一圈10000个脉冲,32位能记42万圈,够用了。
避坑指南: 我曾经遇到过编码器线缆太长导致信号抖动。后来加了差分接收器(比如AM26LS32),问题解决。记住:编码器信号超过1米,必须用差分传输。
3.2 霍尔传感器接口
霍尔传感器,说白了就是三个开关。120度安装,每个霍尔输出高低电平,组合起来就是6个状态。
霍尔接口比编码器简单,但有个坑——安装角度偏差。理论上霍尔应该精确120度,但实际总有误差。这个误差会导致换相不准,电机噪音大。
我一般这么处理:
- 上电先读霍尔状态,确定初始扇区
- 运行时检测霍尔跳变,记录时间戳
- 用时间戳估算速度,做速度闭环
霍尔信号进MCU,我建议用外部中断。每个霍尔引脚配一个中断,上升沿和下降沿都触发。这样能最快响应换相。
警告: 霍尔信号容易受电机电磁干扰。我习惯在霍尔电源脚加100nF电容,信号线对地加10kΩ下拉电阻。别问我为什么,问就是吃过亏。
在CANopenNode里,霍尔状态可以映射到0x6002子索引。但更常见的做法是:霍尔只用于启动时的初始位置检测,运行后切换到编码器。
3.3 PWM输出
PWM输出,就是告诉功率管什么时候开、什么时候关。核心参数就三个:频率、占空比、死区时间。
频率怎么选? 我一般遵循这个原则:
- 有刷电机:20kHz,避开人耳听觉范围
- 无刷电机:16kHz-20kHz,兼顾效率和噪音
- 步进电机:20kHz-40kHz,细分驱动时用高频
死区时间呢?说白了就是上下管不能同时导通。我习惯设成1μs,对于大部分MOSFET都够用。
代码示例(STM32高级定时器):
// PWM配置 - 中心对齐模式
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
TIM_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_CenterAligned1;
TIM_TimeBaseStructure.TIM_Period = 4200; // 20kHz @ 168MHz
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
// 死区时间设置 - 1μs
TIM_BDTRInitTypeDef TIM_BDTRInitStructure;
TIM_BDTRInitStructure.TIM_DeadTime = 168; // 168个时钟周期
TIM_BDTRInit(TIM1, &TIM_BDTRInitStructure);
我的经验: 中心对齐模式比边沿对齐模式好。虽然计算复杂点,但电流纹波小,电机噪音也小。
3.4 电流采样
电流采样,是FOC控制的核心。没有准确的电流值,什么算法都是白搭。
采样方式有三种:
| 方式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 单电阻采样 | 成本低,只需一个采样电阻 | 算法复杂,低速时采样不准 | 低成本方案 |
| 双电阻采样 | 两相电流直接测量,算法简单 | 需要两个ADC通道 | 通用FOC |
| 三电阻采样 | 三相电流独立测量,精度最高 | 成本高,PCB面积大 | 高性能伺服 |
我个人最常用双电阻采样。性价比最高,算法也不复杂。
采样时机很关键。 必须在PWM的中间点采样,这时候电流最稳定。我习惯用定时器的触发事件来启动ADC,硬件自动采样,不用CPU干预。
核心要点: 电流采样要跟PWM同步。PWM周期中间点触发ADC,采样保持时间至少500ns。采样电阻选10mΩ,放大倍数50-100倍,把电流信号放大到ADC的满量程范围。
避坑指南: 我曾经遇到过采样值跳变的问题。查了两天才发现是PCB走线问题——采样电阻的Kelvin连接没做好。记住:采样电阻必须用四线制接法,电流路径和电压检测路径分开。
在CANopenNode里,电流值通常映射到0x6003和0x6004,分别对应U相和V相电流。W相电流可以通过计算得到(三相电流之和为零)。
好了,这一讲就到这里。硬件接口是电机控制的根基,基础打牢了,后面的算法才能跑得稳。下一讲我们开始聊CANopenNode的协议栈移植,那才是真正的好戏开场。