本文对应的视频:第五集《正弦微步与 V/f 映射》。 代码工程:
通过网盘分享的文件:CW32L010步进电机正弦微步驱动器.zip
链接: https://pan.baidu.com/s/1pR0wOT3D30N38uOFXtpbDg?pwd=L010 提取码: L010
一、引言
常规方波整步驱动每换一次相,绕组电流整体跳变,磁场方向随之阶跃 90° 电气角,转子承受一次电磁冲击,表现为运行噪声与振动。本文以正弦微步替代方波换相,将每个电周期细分到 64 步,并在电压模式开环下建立转速与振幅的映射关系。(本篇内容部分涉及动态展示,如有误区可前往观看配套视频)
二、磁场方向由两相电流的比值决定
步进电机的转子是一圈永磁体,定子上绕有 A、B 两相绕组,两相在空间上正交,相差 90° 电气角。单相通电时,该相产生磁场,转子永磁体受异极相吸作用转向磁场方向。
转子受到的是两相磁力的合力,合成磁场的方向由两相电流的比值决定:
A 相电流大,磁场偏向 A 相轴;B 相电流大,磁场偏向 B 相轴。两相电流连续变化,磁场方向连续旋转。
位置与速度是两个独立的量:位置由两相电流的比值决定,速度由微步推进的间隔决定。
三、整步与微步的步距
方波整步将一个电周期分为 4 步,依次为 A 相通电、B 相通电、反向 A 相通电、反向 B 相通电。每一步的电流在切换瞬间完成跳变,磁场方向随之跳变 90° 电气角。
一个电周期对应一个齿距 7.2° 机械角,按绕组换相的节拍,一个电周期由四步完成,因此整步驱动的机械角(也就是步进角)为
微步则在整步驱动的基础上,将一个电周期分为 64 步,其实际步进角为
换相冲击的能量与转角偏差的平方成正比。步距角缩小到 1/16,单步冲击能量降至 1/256。
0.1125° 为理论值,实际可达的定位精度受电流分辨率与齿槽转矩限制
iA-iB 平面给出定性差别(图 2):整步只有 4 个离散点,构成菱形,磁场方向只能跳变;微步是 64 个点构成的正圆,方向连续变化。
电气角与机械角不可混用。 一个电周期等于 360° 电气角、4 个整步、64 个微步,也等于一个齿距 7.2° 机械角。整步的 90° 与微步的 5.625° 是电气角,整步的 1.8° 与微步的 0.1125° 是机械角。一些将5.625° 当作机械角是常见误区。
步数由此确定:整步 200 步/转,微步 3200 步/转。
四、正弦电流的构造
正弦电流的实现依赖占空比对绕组平均电压的控制。18 kHz 的 PWM 驱动MOS在绕组两端加载方波电压,绕组电感滤除高频成分,只剩每段的平均值。占空比决定平均值大小,逐个微步抬高目标值,得到的是阶梯逼近的正弦曲线。
正弦值由一张 64 项的表给出。CW32L010 没有三角函数外设,内核也无硬件浮点单元,正弦涉及浮点运算,放在微秒级的中断里不划算,故采用查表方式。
表中只存绝对值,正负号由极性表给出。 正弦的绝对值以 180° 为周期重复,表长本可减半。本实现仍存满 64 项,后 32 项与前 32 项重复,作用是让索引计算保持线性,省掉折返分支。极性表是一张 64 项的字节数组:索引 0~31 为 0,电流走正半周;索引 32~63 为 1,电流走负半周。
B 相复用 A 相的表。 B 相需要余弦,余弦等于相位增加 90° 的正弦:
90° 除以每微步 5.625° 等于 16,因此 B 相索引为 A 相索引加 16。索引加 16 可能超出 63,需要取模。64 是 2⁶,取模运算可以写成按位与:
uint8_t iA = s_motor.stepIndex;uint8_t iB = (iA + 16) & 0x3F; /* B 相 = A 相 +90° 电气角 */uint16_t ccrA = (uint16_t)(((uint32_t)s_sineAbsTable[iA] * s_motor.amplitude) >> 12);uint16_t ccrB = (uint16_t)(((uint32_t)s_sineAbsTable[iB] * s_motor.amplitude) >> 12);SetPhaseOutput(TIMER_CH_AH, TIMER_CH_AL, ccrA, s_sinePolarity[iA]);SetPhaseOutput(TIMER_CH_BH, TIMER_CH_BL, ccrB, s_sinePolarity[iB]);
& 0x3F 将高位清零,结果落在 0~63。常规写法 % 64 在 M0+ 上要调用除法例程,耗时几十个周期;按位与是单周期指令。表长取 64 而非 32,正是为了让这个掩码成立。B 相复用同一张表还省掉了第二张 128 字节的余弦表,避免两表不一致。
五、中断内的定点数运算
表值按定点数存储。正弦值原本是 0~1 的小数,照原样存表则中断内要做浮点乘法;改存整数则要做归一化除法。两种方法在 M0+ 上都不划算:
浮点乘法。
-
- CW32L010 内核无硬件浮点单元,一次浮点乘法调用软件例程,耗时几十个周期且不固定,中断的执行时间随之波动。
常数除法。
-
-
- Cortex-M0+ 属 ARMv6-M 架构,没有一次算出 64 位乘积的指令。编译器将常数除法优化为魔数乘法的前提是取乘积高位,缺少这条指令,优化无法生成,只能调用
__aeabi_uidiv
- 。
-
满幅取 2 的幂,除法退化为移位。 表值满幅取 4096 即 2¹²,归一化变成右移 12 位:
/* 归一化: 表值 × 振幅 >> 12 */uint16_t ccr = (uint16_t)(((uint32_t)s_sineAbsTable[i] * amplitude) >> 12);
表值由下式生成:
用整数表示小数的方法称为定点数,放大的倍数称为定标系数。定标系数取 2 的幂,归一化采用移位而非除法。
乘法的位宽需要确认。 表值最大 4096,振幅最大 2667,乘积为 10,924,032,小于 2³²,32 位无符号乘法不溢出。代码中的 (uint32_t) 强制转换不可省:两个操作数若在 16 位下相乘,高位会被截断。
一次微步的运算量固定。Motor_ExecuteStep 在步进定时器中断中调用,全程只有查表、一次乘法、一次移位与四次寄存器写入,约 5 μs。步进间隔由转速决定:
n为转速(RPM),3200 为每转微步数。100 RPM 对应 187 μs,200 RPM 对应 94 μs,5 μs 的负载占比分别为 2.7% 与 5.3%。
单步耗时数据来自 motor_step.c 中的注释
六、V/f 映射与两层约束
绕组是电感,电流不能突变。每个微步,两相电流从一个值过渡到下一个值,步进间隔就是留给电流完成过渡的时间窗口。由电感伏安特性
施加电压越高,电流变化率越大。转速升高,步进间隔缩短,留给电流建立的时间减少;电流未达目标值就切到下一步,磁力不及预期,表现为失步。转速升高时每步时间缩短,而非延长。补偿手段是提高电压,转速翻倍对应每步时间大致减半,电压需要大致翻倍才能避免失步。这是构建V/f映射的根本原因。
转速、电压的标定结果以结构体数组形式给出:
static const struct {uint16_t rpm; /* 转速 (转/分钟) */uint16_t amp; /* 振幅 (CCR 值, 0~TIMER_ARR_VAL) */} s_vfMap[] = {{ 0, 50 }, /* 静止保持力矩 (微电流锁轴) */{ 30, 400 },{ 60, 650 },{ 100, 1000 }, /* ← 实测标定点 */{ 150, 1600 },{ 200, 2200 }, /* ← 实测标定点, 最高档 */};
0 RPM 档取 50 是为静止时保留保持力矩。查询值落在两档之间时按区间线性插值。
100 RPM 与 200 RPM 两个标定点来自本板实测,其余档位由线性插值给出
映射表表只确定振幅取多少,不保证振幅是否安全。 需要设计两层约束将振幅钳在安全区间内:
下限。
-
- 振幅不得低于当前转速的查表值,防止手动调小导致失步。
上限。
- 由标定得到的空转电流反推当前转速允许的最大振幅。超过上限,空转电流逼近过流阈值,可能触发过载保护。
下限: 不允许低于当前转速对应的自动振幅 (防失步) */if (s_motor.autoAmplitude > 0 && ccr < s_motor.autoAmplitude)ccr = s_motor.autoAmplitude;/* 上限: 用标定表反推当前转速的最大合法振幅 */if (s_motor.rpm > 0){uint16_t ampMax = Motor_GetAmplitudeMax(s_motor.rpm);if (ccr > ampMax) ccr = ampMax;}
上限之所以存在,是因为空转电流随振幅上升。振幅超过上限时,空转电流可能超过 1.2 A 而触发过载保护停转。
量纲陷阱:过流阈值 1040 是 ADC 计数,振幅轴的单位是 CCR(0~2667),两者量纲不同。约束关系应由振幅上限表达,不可混轴作图。
查表按区间线性插值:
/* 线性插值: amp = a0 + (rpm-r0)/(r1-r0) × (a1-a0) */for (i = 1; i < VF_MAP_SIZE; i++){if (rpm <= s_vfMap[i].rpm){uint32_t r0 = s_vfMap[i - 1].rpm, r1 = s_vfMap[i].rpm;uint32_t a0 = s_vfMap[i - 1].amp, a1 = s_vfMap[i].amp;return (uint16_t)(a0 + ((rpm - r0) * (a1 - a0)) / (r1 - r0));}}
这里的除法没有换成移位:除数 (r1 - r0) 是运行时变量,编译器无法做魔数优化;而该函数运行在毫秒级任务中,不在中断内,几十个周期的开销可以接受。
开环是 V/f 表存在的根本原因。 本驱动板只有一颗采样电阻,测到的是两相电流的合成值,没有逐相独立采样,只能采用电压模式开环。没有反馈,每个转速对应的电压必须提前算准。电流模式闭环需要硬件支持逐相独立采样,属后续改进方向。
七、驱动频率取 18 kHz
PWM 频率高于 20 kHz 时开关噪声超出人耳听觉上限。本驱动板的下管由 MCU 的 IO 口直接驱动,没有栅极驱动器,开关沿较慢;开关沿慢则单次开关损耗大,频率越高单位时间开关次数越多,总损耗越大。频率过低则增加运行噪音,如在 10 kHz 附近出现机械振动与可闻啸叫。
两端都有代价,18kHz的取值由扫频测试结果确定:从 10 kHz 起以 500 Hz 为步长向上扫频,每个频点评估噪声与发热,18 kHz 的综合表现最好。
*扫频结论来自本板实测听感与发热评估,不同电机结果有所差异
与第一集的因果链一致。 省掉栅极驱动芯片后开关沿变慢,开关损耗随频率上升更快,20 kHz 不可用,取值退到 18 kHz。
八、小结
本篇讲解了正弦微步的驱动逻辑与 V/f 映射的建立方法,可以总结为以下五点:
- 由两相电流的比值确定合成磁场方向,位置与速度解耦整步 4 步走完一个电周期,正弦微步为 64 步,微步驱动下的单步冲击能量降至整步驱动的 1⁄256正弦表只存绝对值,极性表给出正负,B 相以索引加 16 复用余弦满幅取 2¹² 使归一化除法退化为右移,中断内全程整数运算V/f 映射补偿转速升高导致的电流建立时间不足,兼作振幅上下限钳位
扫码加入QQ群3群| 610403240
12