尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
基于STM32两路步进电机控制:定时器PWM与梯形加减速实现双轴同步
简介基于STM32的两路步进电机控制代码主要面向嵌入式初学者、硬件工程师及相关专业学生解决双电机独立调速、方向切换与精确定位问题可覆盖工业自动化产线、3D打印、机器人关节驱动、科研仪器移动平台等典型应用。压缩包内共129个文件以.c/.h源码为核心同时包含Keil工程配置、编译链接输出、调试配置与辅助脚本整体约2.76MB文件归类清楚导入工程后即可对照阅读。程序利用定时器PWM输出精确控制两路步进电机完整实现了电机初始化、速度设置、方向切换、停止等基础操作并加入多任务调度与中断处理函数便于根据现场需求调整工作模式。目前已有184人学习下载代码注释详尽、结构清晰可直接作为双电机控制原型也能为后续扩展闭环速度控制或位置插补提供良好基础。1. 基于 stm32 两路步进电机控制代码从最小系统到双轴同步两路步进电机控制难点从来不是“让它转”而是“让两路按你的节奏转”。脉冲频率决定了速度脉冲总数决定了位移而两路脉冲之间的时序关系决定了轨迹。单独点动一路电机任何一个开发板都能做到但真正的工程问题在于当两路电机需要在不同速度下协同运动时加减速过程怎么衔接两路同时启停的误差怎么控制中断里改频率会不会丢脉冲这些问题背后的核心机制都是对 STM32 定时器资源的使用方式。本文基于 HAL 库从脉冲产生、加减速建模到双轴协调给出一套可以直接落地的控制代码思路。适合正在做小型雕刻机、绘图仪、云台或送料机构的嵌入式工程师也适合用 STM32 做毕设、但对运动控制细节还不够清楚的同学。2. 两路步进电机的硬件选型与定时器资源分配2.1 先决定驱动方式STEP/DIR 接口是最省心的方案步进电机的驱动接口大体分三类相位驱动两相四线直接由 MCU 输出相位逻辑、STEP/DIR 脉冲接口、以及串行总线接口如 EtherCAT 步进电机驱动器。在 STM32 项目里最常见、也最可靠的是 STEP/DIR 方式——MCU 只需要输出两路信号STEP 脉冲和 DIR 方向电平剩下的电流斩波、相序切换全交给驱动器完成。这种方式的好处是代码量小、实时性要求低。MCU 不需要关心电机绕组的通电顺序只需要保证 STEP 脉冲的频率精准、边缘干净。对两路控制来说选一个带两个定时器的 STM32 型号就可以开始干活。比较常用的配置是 STM32F103RCT6 或 STM32F407VET6前者便宜够用后者适合后续扩展编码器闭环。2.2 定时器分配一路电机独占一个定时器不要共用两路步进电机控制代码的第一个设计决策是给每路电机分配独立的定时器。我不建议用同一个定时器的两个通道分别输出两路 PWM原因是这两路电机的转速往往不同占空比和频率需要独立调整共用定时器时修改一个通道的分频值会影响另一路。推荐分配方案如下电机定时器输出通道复用引脚F103说明电机 XTIM2CH1PA0输出比较模式或 PWM 模式电机 YTIM3CH1PA6与 TIM2 完全独立备用TIM4CH1PB6可用于第三轴或点动频率输出这个分配方案的核心原则每个定时器的更新事件频率只由本路电机的目标速度决定互不干扰。PA0 和 PA6 在 F103 上都是 5V 容忍引脚可以直接接常见驱动板的脉冲输入口。2.3 驱动器接口电路STEP/DIR 信号不要直接怼进去STEP/DIR 接口的输入侧一般有光耦隔离输入端需要串联限流电阻。以 DRV8825 和 A4988 这类常见驱动板为例STEP 和 DIR 引脚内部是光耦的阳极额定电流约 5~15mA。如果 STM32 的 GPIO 是 3.3V 输出串一个 330Ω 到 1kΩ 的电阻比较稳妥。上拉和下拉也要处理。DIR 引脚悬空时电平不确定电机可能在上电瞬间反转一下所以初始化时要把 DIR 引脚设置成推挽输出并强制拉低或拉高。常见做法是把 DIR 和 STEP 引脚都初始化为推挽输出初始电平为低。接线顺序上我习惯在代码里把两个电机的 STEP 引脚分别命名为 X_STEP 和 Y_STEP用宏定义管脚不要散落硬编码#define X_STEP_PIN GPIO_PIN_0 #define X_STEP_PORT GPIOA #define X_DIR_PIN GPIO_PIN_1 #define X_DIR_PORT GPIOA #define Y_STEP_PIN GPIO_PIN_6 #define Y_STEP_PORT GPIOA #define Y_DIR_PIN GPIO_PIN_7 #define Y_DIR_PORT GPIOA这里把 STEP 和 DIR 放在同一个 GPIO 端口是为了后面可以用GPIOB-BSRR这类寄存器操作来提升翻转速度。初始化时把两个端口都配成推挽复用模式复用功能选定时器的输出通道。3. 用定时器 PWM 生成步进脉冲频率即速度3.1 为什么用 PWM 模式而不是 IO 翻转加延时新手很容易写出“置高、延时、置低、再延时”的点动脉冲代码这种方法点动一次没问题但连续运动时有两个致命缺陷延时函数的精度会被中断打断CPU 被占用后无法同时处理两路电机的逻辑。正确做法是让定时器硬件自己产生脉冲。配置成 PWM 模式设置占空比为 50%改变 ARR自动重装载值就能改变脉冲频率而脉冲频率直接对应电机转速。修改 ARR 只需要一次寄存器写入不需要停掉定时器。脉冲频率和电机转速的换算公式转速转/分 脉冲频率Hz× 60 ÷ 细分数 ÷ 电机每转步数比如 1.8° 步距角的电机驱动器设置 16 细分那么电机转一圈需要 3200 个脉冲。如果给 32kHz 的脉冲频率转速就是 32,000 × 60 / 3200 600 转/分。3.2 HAL 库的定时器 PWM 初始化三步走用 CubeMX 生成工程时只需要做三件事把 TIM2 的 CH1 配成 PWM Generation把 TIM3 的 CH1 也配成 PWM GenerationTIM2 的时钟源选内部时钟预分频值设 0ARR 随便给个初值后面在代码里动态改。生成工程后在main.c里补充void Motor_PWM_Init(void) { TIM_OC_InitTypeDef sConfigOC {0}; // TIM2 初始化72MHz 时钟预分频 0ARR 初值 1000 htim2.Init.Prescaler 0; htim2.Init.CounterMode TIM_COUNTERMODE_UP; htim2.Init.Period 1000; htim2.Init.ClockDivision TIM_CLOCKDIVISION_DIV1; htim2.Init.AutoReloadPreload TIM_AUTORELOAD_PRELOAD_ENABLE; HAL_TIM_PWM_Init(htim2); sConfigOC.OCMode TIM_OCMODE_PWM1; sConfigOC.Pulse 500; // 50% 占空比 sConfigOC.OCPolarity TIM_OCPOLARITY_HIGH; sConfigOC.OCFastMode TIM_OCFAST_DISABLE; HAL_TIM_PWM_ConfigChannel(htim2, sConfigOC, TIM_CHANNEL_1); // 启动 PWM 输出但先不输入脉冲 HAL_TIM_PWM_Start(htim2, TIM_CHANNEL_1); __HAL_TIM_SET_AUTORELOAD(htim2, 0); // ARR 设为 0此时不产生脉冲 }Prescaler设为 0 意味着定时器时钟是 72MHz每计数一个数耗时约 13.9ns。Period即 ARR决定脉冲频率的基数Pulse设为 ARR 的一半就得到 50% 占空比。后面动态调速时只改PeriodPulse要同步改否则占空比会漂移。3.3 动态改频修改 ARR 的安全方式在运动控制中速度是连续变化的所以 ARR 也会被频繁改写。这里有一个容易踩坑的点如果直接__HAL_TIM_SET_AUTORELOAD()修改 ARR而定时器正在计数途中可能导致一次计数周期长度异常产生一个不规则脉冲进而导致电机抖动。稳妥做法是先改 ARR 再改 Pulse利用重装载预装载机制让新值在下一个更新事件生效void Motor_SetFreq(TIM_HandleTypeDef *htim, uint32_t ch, uint32_t freq_hz) { uint32_t arr 72000000UL / freq_hz; if (arr 2) arr 2; __HAL_TIM_SET_AUTORELOAD(htim, arr - 1); __HAL_TIM_SET_COMPARE(htim, ch, (arr - 1) / 2); }arr 72,000,000 / freq是反推定时器计数上限的过程。比如要 30kHz 脉冲频率ARR 就是 2399。如果 ARR 设得太小小于 2定时器溢出太快脉冲宽度会小于驱动器的光耦响应时间所以加了保护上限频率。脉冲输出阶段的 CPU 占用几乎为零剩下的算力可以用来做运动规划、编码器读取、串口通信。这也为后面两路电机同时运动留出了余量。4. 梯形加减速两路电机不丢步的关键算法4.1 为什么要加减速步进电机的力矩-频率特性不允许突变步进电机的输出力矩随脉冲频率升高而下降。频率突变时电机的转子惯性会让它跟不上磁场变化进入失步状态——表现为电机不动但脉冲还在发或者电机震动、异响。这里的“失步”对两路电机来说尤其危险如果两路各自失步不同步XY 轨迹就会歪掉且无法自恢复。梯形加减速是最实用、最容易实现的曲线。它把运动过程分成三个阶段加速段、匀速段、减速段。加速段频率线性上升减速段线性下降。扭矩需求在这个过程中是恒定的不超过电机的启动频率限制。4.2 加减速参数计算加速度值和步数怎么定给定目标频率 ( f_{\text{max}} )Hz、启动频率 ( f_{\text{start}} )Hz、加速度 ( acc )Hz/s加速段的总步数可以用下面的关系推导加速段脉冲数:steps_acc (f_max² - f_start²) / (2 * acc)比如 ( f_{\text{start}} ) 取 500Hz( f_{\text{max}} ) 取 20000Hz加速度取 100000Hz/s那么加速步数是(20000² - 500²) / (2 × 100000) 1998.75 ≈ 1999 步这个数值的意义是在前 1999 个脉冲里频率从 500Hz 线性升到 20kHz。如果总步数小于 2 × 1999说明没有匀速段只能做“三角形加减速”——峰值频率达不到目标值需要重新计算。4.3 两路电机共用一张加减速表节省计算量的设计梯形加减速最常见的实现方式是在定时器更新中断里改写 ARR每个中断周期把频率增加一个固定步长。对两路电机来说如果各自独立计算中断里的浮点运算会占掉不少时间如果共用一张预先算好的频率-步数查找表就只需要做一次表查询加一次乘除法。我一般把频率表按加速步数分成固定段数比如 100 段或 200 段// 预计算的加减速查找表数组下标是加速阶段当前位置 // 表里的值是 ARR 寄存器值已经换算好 uint16_t accel_table[ACCEL_TABLE_SIZE]; uint16_t decel_table[ACCEL_TABLE_SIZE]; void Motor_GenerateAccelTable(uint32_t f_start, uint32_t f_max, uint32_t acc, uint32_t timer_clk) { uint32_t steps_acc (f_max * f_max - f_start * f_start) / (2 * acc); float f_cur; for (int i 0; i ACCEL_TABLE_SIZE; i) { // 当前阶段的目标频率 f_cur (float)(f_max - f_start) * i / ACCEL_TABLE_SIZE f_start; // 反算 ARR accel_table[i] (uint16_t)(timer_clk / f_cur); } }这里用线性频率递增对应的 ARR 值是非线性的——因为在计数器时钟固定时频率和 ARR 成反比。用查找表可以避免中断里做除法。表格生成只需要在系统初始化时调用一次后续运动过程中中断里只做数组取值和比较。4.4 中断服务函数里的两路联动实现两路电机共用一个定时器中断来做状态机更新比每路单独开一个中断更利于同步。这里可以用 TIM4 作为“调度节拍”定时器每毫秒触发一次中断在中断里推进两路电机的加减速状态和脉冲频率更新void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if (htim-Instance TIM4) { // 电机 X 的状态机推进 if (x_motor.state ! MOTOR_IDLE) { Motor_TrapezoidTick(x_motor, htim2); } // 电机 Y 的状态机推进 if (y_motor.state ! MOTOR_IDLE) { Motor_TrapezoidTick(y_motor, htim3); } } }Motor_TrapezoidTick内部逻辑是判断当前已走步数处于加速段、匀速段还是减速段查表得到该阶段的目标频率写入对应定时器的 ARR如果已经走完总步数关闭 PWM 输出并置状态为 IDLE。这里的关键参数是步数计数器。每个 PWM 周期对应一个步进脉冲所以步数计数应该由 PWM 定时器的更新中断来统计而不是在 TIM4 的中断里数数。如果两路共用 TIM4 做频率推进那么每路各自独立计数互不堵塞。5. 两路电机同步同时启停、实时调速与脉冲当量校准5.1 同时启动用寄存器级操作避免几微秒级的偏差两路电机需要同时启动时如果代码里先启动 TIM2 再启动 TIM3两路之间会差几个到几十个微秒。在大多数应用里这个误差无所谓但在激光雕刻或绘图场景下这个偏差会直接体现在对角线不直上。同步启动的常用做法是把两路的 ARR、Pulse、分频值全部准备好然后对两个定时器同时执行启动命令。寄存器级别可以这样处理void Motor_StartBothSync(void) { // 先完成所有参数的写入 __HAL_TIM_SET_AUTORELOAD(htim2, x_arr); __HAL_TIM_SET_COMPARE(htim2, TIM_CHANNEL_1, x_arr / 2); __HAL_TIM_SET_AUTORELOAD(htim3, y_arr); __HAL_TIM_SET_COMPARE(htim3, TIM_CHANNEL_1, y_arr / 2); // 使用位带或 BSRR 同时使能两个定时器 TIM2-CR1 | TIM_CR1_CEN; TIM3-CR1 | TIM_CR1_CEN; }TIMx-CR1的 CEN 位是定时器使能位。两行赋值语句在 Cortex-M3 上是两条存储指令间隔只有几个时钟周期配合 D-Cache如果芯片有无需担心一致性问题。对 F103 来说这两个定时器挂在不同总线桥上注意先使能对应 RCC 时钟。__HAL_TIM_SET_*系列宏本身就带内存屏障效果写完后读回可以保证寄存器写入完成再启动。5.2 运动过程中的调速主站下发的目标频率怎么平滑切换在两轴插补或在线调速的场景中外部主机比如上位机通过串口会不断下发新的目标速度。如果直接在中断里把当前 ARR 改成新值电机就会承受一次频率跳变。这里的做法是把新目标速度存到一个“目标变量”里然后在 TIM4 的调度中断中对当前频率执行步进式逼近每秒最多变化多少由加速度上限决定void Motor_SetTargetFreq(Motor_t *motor, uint32_t target_freq) { motor-target_freq target_freq; } void Motor_SpeedRamp(Motor_t *motor) { int32_t diff (int32_t)motor-target_freq - (int32_t)motor-current_freq; int32_t max_step motor-acc_per_tick; // 每个调度周期的最大频率变化量 if (diff max_step) motor-current_freq max_step; else if (diff -max_step) motor-current_freq - max_step; else motor-current_freq motor-target_freq; // 写入硬件 Motor_SetFreq(motor-htim, motor-channel, motor-current_freq); }这种“斜坡逼近”的思路与主机通信的频率无关不管下发的速度是突变的还是渐变的电机的实际频率始终贴着加速度上限走不会超出电机的动态响应能力。acc_per_tick由加速度设定值和 TIM4 中断频率换算得来比如调度周期是 1ms、加速度是 100000Hz/s那acc_per_tick就是 100Hz。5.3 脉冲当量把“脉冲数”翻译成“毫米或度数”两路电机控制代码最终要面对的问题往往不是“多少个脉冲”而是“走多远”。脉冲当量是每个脉冲对应的机械位移或角度。常见计算公式脉冲当量 丝杠导程 ÷ 细分数 ÷ 电机每转步数× 传动比例如丝杠导程 5mm电机 200 步/转驱动器 8 细分传动比 1:1则每个脉冲对应的位移是5mm ÷ (200 × 8) 0.003125mm如果目标位移是 10mm需要的脉冲数就是 10 ÷ 0.003125 3200 个。在代码里我把脉冲当量作为float常量存放在电机结构体中所有对外接口都使用“毫米”作为单位内部换算成“步数”再来驱动定时器typedef struct { float pulse_per_mm; // 每毫米脉冲数 uint32_t current_steps; // 当前累计步数 uint32_t target_steps; // 目标步数 uint8_t dir; // 方向 TIM_HandleTypeDef *htim; uint32_t channel; } Motor_t; // 匀速段走指定距离 void Motor_MoveDistance(Motor_t *motor, float distance_mm) { int32_t steps (int32_t)(distance_mm * motor-pulse_per_mm); motor-target_steps motor-current_steps steps; }注意脉冲当量的单位。我习惯统一存每毫米脉冲数而不是每脉冲毫米数因为前者在主控端处理时全是乘法性能更好。如果使用 EtherCAT 步进电机驱动器或闭环步进驱动器它们的电子齿轮比也可以换算到这个模型里只是把“驱动器细分”换成“电子齿轮比分母”。5.4 两路协调的极限插补不是本方案能解决的本节方案解决的是两路电机“各走各的但协同启停”的典型需求如果两路需要严格按直线或圆弧轨迹联动比如 3D 打印机式联动那属于插补算法范畴。插补要求在每个时间片内精确分配两路电机的脉冲数代码模型完全不同——CPU 需要在每个调度周期根据插补方程计算两路各自的脉冲增量。标题中的“两路步进电机控制”我更倾向于理解成“两路独立但要协调”的控制。如果确实需要插补建议引入外部运动控制芯片或支持插补的驱动器。反之如果只是做点位运动——走到一个目标位置再走到下一个位置——本文的方案已经完备。6. 实战排错电机抖动、丢步反转和发热的定位方法6.1 用逻辑分析仪验证脉冲频率不要凭耳朵听两路步进电机接入后如果表现异常抖动、啸叫、反转第一件事是测波形而不是改代码参数。用带解码功能的逻辑分析仪分别夹住 X_STEP 和 Y_STEP 引脚看脉冲频率是否与预期一致。重点看两个指标单个脉冲宽度是否稳定相邻脉冲间隔是否有周期性波动。脉冲宽度不稳定最常见原因是 ARR 和 Pulse 更新时机不对——例如先改了 Pulse 后改了 ARR导致一个周期内占空比偏移。脉冲间隔周期性波动通常是因为中断抢占——如果使用了HAL_Delay或者高优先级中断打断 PWM 更新中断频率表推进就会卡顿。排查时把 TIM4 的中断优先级设为低于 PWM 定时器的更新中断这样频率推进可以被实时响应而不会影响正在输出的脉冲。6.2 回原点时方向不对不要改接线改 DIR 逻辑两路电机如果安装了限位开关回原点是个绕不开的需求。常见现象是电机反方向冲向限位——也就是回原方向反了。处理这个问题不要重新接电机相线或调换驱动器的 DIR 线代码里直接反转方向逻辑即可#define MOTOR_DIR_INVERT 1 // 设为 0 时方向正常设为 1 时取反 void Motor_SetDirection(Motor_t *motor, uint8_t dir) { #if MOTOR_DIR_INVERT dir !dir; #endif HAL_GPIO_WritePin(motor-dir_port, motor-dir_pin, dir ? GPIO_PIN_SET : GPIO_PIN_RESET); }同时要注意回原点过程中如果碰到限位开关电机会立刻停止。频繁启停对电机冲击较大一个实用的小技巧是在回原点的低速段使用较低的加速度值让电机平滑地贴上限位再反向脱离。6.3 电机发热但不走检查细分开关和电流设定电机发热严重但扭矩明显不足是驱动器电流设定和细分设置常见的组合问题。多数驱动器如 DRV8825、DM542上有拨码开关分别控制细分倍数和输出电流。如果细分拨码设错比如代码按 16 细分计算脉冲数实际上驱动板工作在 8 细分那么目标位置会偏一半而且电机运行噪音偏大。电流设定请按照电机铭牌上的额定电流调整不要盲目调大。42 步进电机常见额定电流在 1.2A~1.7A 之间57 步进电机在 2A~3A 左右。驱动器上的 VREF 电压和电流之间的关系因驱动板而异需要按对应驱动芯片数据手册换算例如 A4988 的 VREF 电流峰值 × 2.5 × 采样电阻通常为 0.1Ω。调完电流后用手触摸电机外壳如果温度超过 70°C说明电流过大或电机长时间堵转。6.4 低速抖动和共振调整细分是立竿见影的手段步进电机在低频段存在共振区通常在 150Hz~300Hz 之间表现为电机在某个固定频率附近剧烈抖动甚至失步。这个问题的根源是步进电机本身的转距-频率特性与机械系统的共振耦合不是你代码里的 bug。推荐两个处理方向一是提高驱动器细分比如从 8 细分改为 16 或 32 细分让每个脉冲对应的机械角度变小共振能量减弱二是在软件层面对加减速表的起点做处理不要在共振频率段长时间匀速运行。我在实际项目里通常用“两步跳跃法”规避共振区——把加减速表里的起始频率设到 500Hz 附近如果机械结构在 200Hz 附近共振直接把加速段的起始频率跳过去不做平滑过渡。这个做法的代价是启动瞬间会有轻微冲击但在大多数轻载应用中完全可以接受。本文还有配套的精品资源点击获取
RELATED

相关推荐

条形码生成工具怎么选?

条形码生成工具怎么选?

商品条码是产品进入商超、电商平台和跨境渠道的基础通行证。很多企业在起步阶段会先接触在线条形码生成工具,用来预览条码样式或做内部测试。但真正要用于正式流通的商品,仅靠临时生成的条码并不够,还需要完成合规备案与编码申请。 在线生成工…

📅 2026/9/16 16:13:51
微信小程序LBS实战:从定位到附近美食POI检索与排序

微信小程序LBS实战:从定位到附近美食POI检索与排序

简介:微信小程序开发学习者可参考这份完整的附近美食餐厅查询案例,资源围绕地图定位、餐厅列表展示与信息详情等核心页面展开,适合初步掌握小程序语法、希望结合真实场景练习前后端交互的读者。压缩包共39个文件,体积仅99KB&#…

📅 2026/9/16 16:13:51
C/C++实现散列表通讯录:散列函数与冲突处理详解

C/C++实现散列表通讯录:散列函数与冲突处理详解

简介:基于C/C语言散列表实现的通讯录系统课程设计资料包,面向需要完成课程设计、大作业或初学散列表的计算机专业学生。项目以电话号码和用户名为关键字分别建立散列表,实现记录录入、冲突处理、按号码或姓名快速查找与显示,并进一…

📅 2026/9/16 16:08:50
MORE NEWS

更多资讯

📰

在 Linux 上使用 rbenv 安装与管理 Ruby:完整安装指南

在 Linux 上使用 rbenv 安装与管理 Ruby:完整安装指南 【免费下载链接】curriculum The open curriculum for learning web development 项目地址: https://gitcode.com/GitHub_Trending/cu/curriculum 本文档对应 The Odin Project 开源课程(本仓…

📰

Rekor 可插拔类型(Pluggable Types)机制深度解析:透明日志条目 Schema 插件体系与 BuildKit 中的落地实践

Rekor 可插拔类型(Pluggable Types)机制深度解析:透明日志条目 Schema 插件体系与 BuildKit 中的落地实践 【免费下载链接】buildkit concurrent, cache-efficient, and Dockerfile-agnostic builder toolkit 项目地址: https://gitcode.co…

📰

长沙市POI数据处理实战:从7z解压到DEM叠加分析

简介:一份面向GIS分析、城市规划、商业选址与交通研究人员的长沙市2020年POI数据集包,内含30米分辨率DEM数字高程模型、长沙市区县/街道等行政区划边界,以及shp和Excel两种格式的兴趣点数据。POI覆盖餐饮、购物、医疗保健、政府机构、住宿服务…

📰

C++实现结构光激光中心线亚像素提取

简介:本资源是一套基于C实现的线结构光视觉传感器标定核心代码,面向机器视觉、工业检测及光学测量方向的研究生与工程师,聚焦激光光条中心线的高精度提取问题。项目完整实现了多格式图像解码(BMP/JPG/PCX/GIF)、大津法…

📰

Carbon Web Components 的 `cds-code-snippet` 渲染原理与快照测试深度解析

Carbon Web Components 的 cds-code-snippet 渲染原理与快照测试深度解析 【免费下载链接】carbon A design system built by IBM 项目地址: https://gitcode.com/GitHub_Trending/carbo/carbon 导读 cds-code-snippet 是 IBM Carbon Design System 在 Web Components …

📰

mlx-audio 中的 Dramabox 语音合成:基于 LTX DiT + Gemma 编码器的 48 kHz 立体声 TTS 与参考音频克隆实现

mlx-audio 中的 Dramabox 语音合成:基于 LTX DiT Gemma 编码器的 48 kHz 立体声 TTS 与参考音频克隆实现 【免费下载链接】mlx-audio A text-to-speech (TTS), speech-to-text (STT) and speech-to-speech (STS) library built on Apples MLX framework, providing…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬