STM32 HAL库编码器测速全解析:从硬件连接到速度计算与调试
1. 项目缘起为什么编码器测速是嵌入式开发的必修课在电机控制、机器人底盘、智能小车这些嵌入式项目里实时、准确地获取电机转速是决定系统性能的基石。你可能会说用霍尔传感器或者红外对管不也能测速吗确实可以但那通常只适用于低速、精度要求不高的场合。一旦涉及到需要精确位置控制、快速响应或者需要知道旋转方向的场景比如平衡车的轮子、机械臂的关节光电或磁电编码器就成了不二之选。编码器输出的是一系列正交脉冲信号A相和B相。电机转得越快脉冲频率就越高电机的转向则通过A、B两相的相位关系来判定。STM32的定时器其编码器接口模式就是为高效处理这类信号而生的硬件外设。它能自动根据A、B相的边沿和电平关系在后台更新计数器的值方向正就加方向反就减完全不需要CPU频繁中断去数脉冲。这个“后台自动处理”的能力是软件模拟解码无法比拟的它解放了CPU让系统有更多资源去处理控制算法等核心任务。然而很多初学者甚至一些有经验的开发者在从标准库转向HAL库时会在这里卡壳。HAL库的封装层次更高API更抽象如果只照着CubeMX生成的代码跑很可能遇到计数器值不对、速度计算为0或者出现巨大跳变的问题。网上很多教程只给步骤却不讲清楚HAL库底层配置寄存器时到底做了什么以及速度计算中那几个关键参数定时器周期、采样频率、编码器线数到底怎么影响最终结果。这篇文章我就结合自己多次在平衡车、云台等项目上的踩坑经验把STM32 HAL库下定时器编码器模式测速的里里外外讲透让你不仅能配置出来更能理解每一个参数背后的意义遇到问题能自己排查。2. 硬件连接与定时器选型你的编码器接对了吗在写代码之前硬件连接是第一步也是最容易出错的一步。编码器通常有A、B、Z三相输出我们测速主要用A和B。Z相是零位信号一圈一个脉冲用于绝对位置校准在简单测速中可以不用。2.1 信号类型与接口匹配常见的编码器输出信号有集电极开路OC和推挽输出两种。对于OC输出的编码器很多是NPN型STM32的IO口需要配置为上拉输入模式或者外部接上拉电阻到VCC否则无法读到高电平。推挽输出的编码器则可以直接连接。我强烈建议无论编码器本身是什么输出都在STM32的输入引脚外部加上一个1k-10k的上拉电阻这是一个很好的防干扰习惯。编码器信号线最好使用双绞线并远离电机电源线以减少电磁干扰。2.2 STM32定时器的编码器模式能力不是所有STM32定时器都支持编码器模式。通常通用定时器TIM2, TIM3, TIM4, TIM5和高级定时器TIM1, TIM8都支持。以最常用的STM32F103C8T6为例它的TIM1、TIM2、TIM3、TIM4都支持编码器接口。在CubeMX中当你为一个定时器选择“Encoder Mode”时其对应的两个通道通常是CH1和CH2会自动被配置为输入模式。这里有一个关键点编码器模式会占用定时器的全部功能。一旦启用编码器模式这个定时器就不能再用于PWM输出、输入捕获等其他功能了。所以规划定时器资源时要提前考虑好。2.3 接线与CubeMX配置实例假设我们使用TIM3的通道1PA6和通道2PA7来接编码器的A、B相。打开CubeMX选择你的STM32型号。找到TIM3在“Combined Channels”中选择“Encoder Mode”。此时PA6和PA7的引脚模式会自动变为“Input Pullup”如果你之前没配置的话。我建议这里保持默认的上拉同时在硬件上也加上拉电阻双重保险。关键参数配置在下面的“Parameter Settings”里Counter Mode: 选择“Up”或“Down”其实在编码器模式下意义不大因为计数方向由硬件自动控制。通常选“Up”即可。Counter Period (ARR): 这是定时器的自动重装载值也是计数器的最大值。这个值决定了计数器的“量程”。设置太小高速时容易溢出设置太大影响速度计算的分辨率。对于16位定时器最大值是65535。一个常见的初始值是65535先保证不溢出后续再优化。Encoder Mode: 这是核心它有四个选项Encoder Mode TI1: 仅在TI1CH1的边沿计数。Encoder Mode TI2: 仅在TI2CH2的边沿计数。Encoder Mode TI1 and TI2(上升沿): 在TI1和TI2的上升沿都计数。这是最常用的模式分辨率最高4倍频。电机转一圈编码器输出N个脉冲在此模式下计数器会变化4*N次。Encoder Mode TI1 and TI2(下降沿): 在TI1和TI2的下降沿都计数。同样也是4倍频。 绝大多数情况下我们选择“Encoder Mode TI1 and TI2”以获得最高的精度。预分频器PSC在编码器模式下这个参数通常设置为0即不分频。因为编码器模式下的时钟源是外部引脚信号PSC是对内部时钟的分频不作用于外部信号。保持为0即可。最后别忘了在NVIC Settings中开启TIM3的全局中断如果需要在计数器溢出时处理的话。对于测速我们通常用另一个定时器定时比如1ms去读取计数器的值所以TIM3本身的中断不一定需要。配置完成后生成代码。HAL库会帮我们初始化好定时器和GPIO。3. HAL库编码器模式驱动原理解析生成了代码我们得知道HAL库在背后做了什么。打开stm32f1xx_hal_tim.c找到HAL_TIM_Encoder_Init函数。它主要做了以下几件事配置定时器的基础时基单元TIMx-PSC, TIMx-ARR。根据我们选择的EncoderMode配置输入捕获通道的极性、滤波器和预分频。最关键的一步设置从模式控制器SMCR的SMS位。编码器模式对应SMS3。同时它会根据EncoderMode设置TI1S位以及通道的输入选择映射CCMR1寄存器。使能定时器的计数器TIMx-CR1 | TIM_CR1_CEN。简单来说硬件层面的逻辑是编码器信号直接驱动了定时器的计数逻辑。当A、B相有边沿变化时硬件会自动判断方向并递增或递减计数器CNT。整个过程完全由硬件完成不消耗CPU时间。3.1 如何读取速度和方向测速的本质是“单位时间内的脉冲数”。方向直接读取定时器状态寄存器中的方向位。对于STM32F1可以检查TIMx-CR1寄存器的DIR位0向上计数1向下计数。HAL库提供了__HAL_TIM_GET_DIRECTION(htimx)宏来获取。更简单直接的方法是读取当前的计数器值CNT与上一次的值比较。如果CNT变大说明正向转动变小则反向转动。速度脉冲数我们需要在固定的时间间隔T比如10ms内读取两次计数器的值。速度Speed (CNT_current-CNT_last) /T。这里的Speed单位是“脉冲数/秒”。注意这里的脉冲数已经是经过编码器模式倍频后的计数值。3.2 计数器溢出处理这是第一个大坑。我们的计数器CNT是16位的范围是0~ARR通常设为65535。当电机正转CNT加到65535后再来一个脉冲它会变成0溢出。如果我们直接用CNT_current - CNT_last计算当发生溢出时比如CNT_last65000CNT_current100计算结果会是100-65000 -64900一个巨大的负数导致速度计算错误。处理溢出有两种方法使用定时器溢出中断开启定时器的更新中断溢出中断。在中断服务函数中维护一个软件计数器如tim_overflow_cnt。当CNT从ARR溢出到0时tim_overflow_cnt当CNT从0下溢到ARR时tim_overflow_cnt--。那么总的计数值 tim_overflow_cnt * (ARR1) CNT_current。这种方法精度高但增加了中断负担。限制采样时间内的最大脉冲数更常用的方法是合理选择采样周期T和编码器分辨率确保在T时间内最大的脉冲变化量不会超过ARR的一半即32767。这样即使发生了一次溢出我们也能通过判断差值的符号来修正。计算公式是delta CNT_current - CNT_last; if(delta 32767) delta - 65536; else if(delta -32767) delta 65536;。这种方法在软件上处理简单对大多数中低速应用足够可靠。我个人的项目里只要规划得当基本都用这种方法。4. 从脉冲到实际转速参数计算与代码实现得到了单位时间内的脉冲数delta_pulse这还不是我们最终想要的转速。我们需要将其转换为更有物理意义的单位例如转/分钟RPM。4.1 转换公式推导假设delta_pulse: 采样周期T内读取到的脉冲变化量已处理溢出。T: 采样周期单位是秒s。例如10ms就是0.01s。PPR: 编码器本身的线数即电机旋转一圈编码器输出的物理脉冲数。注意不是计数器变化的次数。倍频数: 我们在TIM配置中选择的编码器模式对应的倍频数。如果选择“TI1 and TI2”模式倍频数为4。那么采样周期内的转速转/秒 (delta_pulse / 倍频数) / PPR / T转速转/分钟RPM (delta_pulse / 倍频数) / PPR / T * 60简化一下RPM (delta_pulse * 60) / (PPR * 倍频数 * T)4.2 一个完整的测速模块代码示例我们使用TIM3作为编码器接口TIM2产生一个10ms的定时中断来定期计算速度。首先在main.c或你的驱动文件里定义一些全局变量// 编码器相关 extern TIM_HandleTypeDef htim3; // CubeMX生成的TIM3句柄 int32_t encoder_total_pulse 0; // 用于累积计数值处理溢出后 int16_t encoder_last_cnt 0; // 上一次的CNT值 float motor_rpm 0.0; // 计算得到的转速 // 编码器参数 #define ENCODER_PPR 13 // 我的电机编码器是13线 #define ENCODER_MULTIPLY 4 // 4倍频 #define SPEED_SAMPLE_TIME 0.01f // 采样周期10ms然后在TIM2的10ms中断服务函数中HAL_TIM_PeriodElapsedCallback进行速度计算void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if (htim-Instance TIM2) { // 10ms定时器 int16_t encoder_cur_cnt __HAL_TIM_GET_COUNTER(htim3); // 读取当前CNT值 int16_t encoder_diff encoder_cur_cnt - encoder_last_cnt; // 处理计数器溢出假设ARR65535 if (encoder_diff 32767) { encoder_diff - 65536; } else if (encoder_diff -32767) { encoder_diff 65536; } encoder_total_pulse encoder_diff; // 累积总脉冲可用于计算位置 encoder_last_cnt encoder_cur_cnt; // 更新上一次值 // 计算转速 RPM (delta_pulse * 60) / (PPR * 倍频数 * T) motor_rpm (encoder_diff * 60.0f) / (ENCODER_PPR * ENCODER_MULTIPLY * SPEED_SAMPLE_TIME); // 可选低通滤波让速度值更平滑 // motor_rpm_filtered 0.8 * motor_rpm_filtered 0.2 * motor_rpm; } }4.3 启动与停止在main函数的初始化部分需要启动编码器定时器和采样定时器// 启动编码器定时器 HAL_TIM_Encoder_Start(htim3, TIM_CHANNEL_ALL); // 启动10ms定时器中断 HAL_TIM_Base_Start_IT(htim2);5. 调试技巧与常见问题排查即使代码写好了你可能还是会遇到速度值为0、跳动大或者方向反的问题。别急按照以下步骤排查。5.1 基础信号检查首先确保硬件信号是好的。用示波器或者逻辑分析仪查看连接到PA6和PA7的编码器A、B相信号。电机缓慢转动时你应该能看到两路相位差90度的方波。如果没有信号检查编码器供电、接地以及上拉电阻。5.2 计数器值检查在调试器中或者通过串口打印实时查看__HAL_TIM_GET_COUNTER(htim3)的值。手动缓慢转动电机观察这个值是否随着转动均匀地增加或减少。如果值不变可能的原因有GPIO配置错误虽然CubeMX自动配置了但检查一下生成的代码确认PA6和PA7的模式确实是GPIO_MODE_INPUT并且上拉。定时器未启动确认调用了HAL_TIM_Encoder_Start。编码器模式选择错误确认是“TI1 and TI2”模式。如果选择成只在TI1边沿计数那么只有A相能触发计数在某些接线方式下可能导致计数不灵敏。如果计数器值变化但方向与预期相反最简单的解决办法是调换A、B相的接线。或者你也可以通过修改CubeMX中两个通道的“Polarity”来反转计数方向但调换线更直观。5.3 速度计算异常排查如果计数器值变化正常但计算出的motor_rpm不对检查参数反复核对ENCODER_PPR电机铭牌或手册上找、ENCODER_MULTIPLY一定是4、SPEED_SAMPLE_TIME单位是秒这三个参数。我见过太多人在这里栽跟头把PPR写成倍频后的值或者采样时间单位弄错。检查数据类型encoder_diff是int16_t但在计算公式(encoder_diff * 60.0f) / (ENCODER_PPR * ENCODER_MULTIPLY * SPEED_SAMPLE_TIME)中60.0f和SPEED_SAMPLE_TIME使得整个表达式是浮点数运算。如果写成整数除法结果永远是0。确保计算过程或接收结果的变量是float或double类型。采样时间过短如果采样时间T太短比如1ms而电机转速又很低那么encoder_diff可能经常为0导致速度计算为0或跳变很大。适当加长采样时间如10ms, 20ms或者采用M法测速固定时间测脉冲数结合T法测速测量固定脉冲数的时间的混合策略来提高低速下的精度。5.4 抗干扰与软件滤波实际项目中电机启停、PWM噪声都可能导致编码器信号有毛刺引起计数器偶尔跳变。除了硬件上做好滤波在CubeMX中可以配置输入滤波器的参数ICFilter软件上的滤波也必不可少。一阶低通滤波如上文代码注释所示对计算出的motor_rpm进行滤波可以平滑曲线。motor_rpm_filtered a * motor_rpm_filtered (1-a) * motor_rpm其中a是滤波系数0~1越接近1滤波效果越强但延迟也越大。通常取0.7~0.9。滑动平均滤波维护一个速度值的数组每次计算的速度存入数组输出时取平均值。这种方法也能有效平滑噪声。6. 进阶话题高精度与多电机协同当你的项目要求更高比如需要更高精度的位置信息或者要同时控制多个带编码器的电机时需要考虑更多。6.1 使用32位计数器或软件扩展对于高速电机或高分辨率编码器16位计数器65535可能很快溢出。一些高性能的STM32型号如F4、H7系列的定时器支持32位计数器。如果只能用16位定时器就必须使用前面提到的“溢出中断软件扩展”法将计数器扩展到32位甚至64位确保长时间运行不会丢失脉冲。6.2 利用DMA自动搬运计数器值为了进一步提高实时性和减少CPU干预可以配置DMA来定期由另一个定时器触发将编码器定时器的CNT寄存器值搬运到内存数组中。CPU只需要在需要时去处理这个数组中的数据即可。这在多电机控制或需要极高同步性的场景下非常有用。6.3 多电机编码器资源规划一个定时器只能接一个编码器。如果需要控制多个电机就需要多个支持编码器模式的定时器。在芯片选型和原理图设计时就要算好。例如控制一个双轮差速小车至少需要两个通用定时器如TIM3和TIM4。如果还有云台电机可能需要TIM1或TIM8。6.4 位置闭环控制的初步思路得到了准确的速度和方向结合总脉冲数encoder_total_pulse它代表了累积的位置信息你已经具备了实现位置闭环和速度闭环控制的基础。你可以设定一个目标速度RPM然后用PID控制器根据当前速度motor_rpm与目标速度的差值来计算并调整电机的PWM占空比这就是速度环。更进一步你可以设定一个目标位置总脉冲数用PID控制电机使encoder_total_pulse趋向目标值这就是位置环。编码器提供的反馈是这一切闭环控制的前提。从我个人的经验来看把编码器测速调稳定是整个运动控制项目成功的一半。它提供的反馈是否准确、及时直接决定了你的PID参数能不能调好系统是否稳定。开始时多在硬件连接、参数核对和基础调试上下功夫后面做高级控制时会事半功倍。最后一个小建议把所有关键的参数如PPR、倍频数、采样时间、滤波系数都定义为宏或变量放在头文件里并加上清晰的注释这样调试时修改起来非常方便也不容易遗忘。

相关新闻

STM32 GPIO寄存器CRL/CRH详解:从原理到实战配置

STM32 GPIO寄存器CRL/CRH详解:从原理到实战配置

1. 项目概述:为什么GPIO寄存器是STM32开发的基石如果你刚开始接触STM32,可能已经习惯了用HAL库或者标准库里的HAL_GPIO_WritePin和HAL_GPIO_ReadPin这样的函数来操作引脚。点个灯、读个按键,几行代码就搞定了,感觉挺方便。但当你开…

2026/7/29 4:33:10阅读更多 →
PHP preg_match()安全绕过实战:5种方法解析与防御指南

PHP preg_match()安全绕过实战:5种方法解析与防御指南

1. 项目概述:为什么preg_match()会成为安全防线上的“阿喀琉斯之踵”?在PHP安全领域,preg_match()函数就像一位尽职的门卫,它通过正则表达式来检查用户输入是否符合预期,是防御代码注入、命令执行等攻击的常见手段。无…

2026/7/29 4:33:10阅读更多 →
EtherCAT从站开发:对象字典与动态PDO映射详解

EtherCAT从站开发:对象字典与动态PDO映射详解

1. EtherCAT从站开发基础与对象字典概述在工业自动化领域,EtherCAT因其卓越的实时性能和灵活的拓扑结构已成为主流现场总线协议之一。作为从站开发者,理解对象字典的运作机制是基础中的基础。0x1600和0x1A00这两个索引地址分别对应PDO(过程数…

2026/7/29 4:33:10阅读更多 →
全志ARM Linux内核编译实战:从环境搭建到系统启动全流程

全志ARM Linux内核编译实战:从环境搭建到系统启动全流程

1. 项目缘起:为什么我们要从零编译ARM Linux内核?如果你手头有一块全志方案的开发板,比如Orange Pi Zero 2或者Orange Pi 5,并且已经玩腻了官方提供的现成镜像,那么“从零开始编译并启动一个自己定制的Linux内核”这个…

2026/7/29 5:47:35阅读更多 →
国产AI数据大屏生成工具推荐(政企电商+3D展厅)

国产AI数据大屏生成工具推荐(政企电商+3D展厅)

这两年“国产替代”喊得响,我们公司作为一家有国资背景的供应链企业,所有数字化系统都得过“信创”这一关。数据大屏又是公司的门面——既要给领导汇报用,又要放在展厅给客户看,还得满足电商部门的实时作战需求。我花了大半年时间…

2026/7/29 5:47:35阅读更多 →
RK3568裸机显示驱动实战:VOP2与IEP配置详解

RK3568裸机显示驱动实战:VOP2与IEP配置详解

1. 项目概述:在RK3568裸机环境下探索显示与图像增强最近在折腾ROC-RK3568-PC这块板子,目标是在完全脱离操作系统(也就是我们常说的“裸机”或“Bare Metal”)的环境下,把它的显示系统跑起来。项目标题里的“裸机19”大…

2026/7/29 5:47:35阅读更多 →
工业物联网通信方案:LTE Cat 1模块与Cortex-M4 MCU实战

工业物联网通信方案:LTE Cat 1模块与Cortex-M4 MCU实战

1. 工业级物联网通信的核心挑战与解决方案在工业自动化、远程监控和智能设备管理领域,稳定可靠的物联网通信一直是系统设计的核心难点。传统Wi-Fi和蓝牙方案在复杂工业环境中经常面临信号干扰、温度波动和电源不稳定等问题。这正是LARA-R6401D-00B蜂窝通信模块与TM4…

2026/7/29 5:47:35阅读更多 →
树莓派交互式表情显示器:GDW变脸项目全解析

树莓派交互式表情显示器:GDW变脸项目全解析

1. 项目概述:GDW变脸,一个树莓派驱动的交互式表情显示器最近在折腾一个挺有意思的小项目,我把它叫做“GDW变脸”。这个名字听起来有点玄乎,但其实核心就是一个基于树莓派的、能够根据外部触发条件动态切换显示内容的交互式装置。简…

2026/7/29 5:47:35阅读更多 →
DF BEETLE控制器深度解析:ESP32-S3核心在嵌入式物联网中的极致应用

DF BEETLE控制器深度解析:ESP32-S3核心在嵌入式物联网中的极致应用

1. 项目概述:当“小身材”遇上“大作为”在嵌入式开发和物联网项目里,我们总在寻找一个完美的平衡点:性能要足够强劲,能跑得动复杂的逻辑和算法;体积要足够小巧,能塞进各种奇形怪状的壳子里;接口…

2026/7/29 5:45:34阅读更多 →
覆盖国产 + 海外 + 开源模型,OpenClaw 2.7.9 Windows/Mac 双端部署详解

覆盖国产 + 海外 + 开源模型,OpenClaw 2.7.9 Windows/Mac 双端部署详解

🔹 工具基础介绍 OpenClaw 是开源生态中一款实用性较强的本地智能工具,凭借本地离线运行、可视化图形操作和任务自动化三大核心特性,赢得了众多用户的青睐。与普通在线对话AI工具不同,它属于能够直接操控本机软硬件的智能数字员工…

2026/7/28 4:06:39阅读更多 →
伺服阀焊完微漏毁整机?精密激光焊接三关锁住高压

伺服阀焊完微漏毁整机?精密激光焊接三关锁住高压

所谓液压伺服阀体的精密激光焊接,是用激光束对阀座壳体(通常为不锈钢或铝合金)进行密封焊接,使阀体在21-35MPa的高压液压油或压缩气体中长期运行而不发生介质泄漏。液压伺服阀是高端液压系统的"大脑"。从航空航天飞行控…

2026/7/28 2:08:06阅读更多 →
D2DX:三步实现《暗黑破坏神2》高清宽屏体验的终极指南

D2DX:三步实现《暗黑破坏神2》高清宽屏体验的终极指南

D2DX:三步实现《暗黑破坏神2》高清宽屏体验的终极指南 【免费下载链接】d2dx D2DX is a complete solution to make Diablo II run well on modern PCs, with high fps and better resolutions. 项目地址: https://gitcode.com/gh_mirrors/d2/d2dx 你是否还在…

2026/7/28 1:38:28阅读更多 →
28. Agent 执行到一半想暂停?用 interrupt 给它设个“关卡“!

28. Agent 执行到一半想暂停?用 interrupt 给它设个“关卡“!

28. Agent 执行到一半想暂停?用 interrupt 给它设个“关卡“! 在构建复杂的 Agent 系统时,我们经常会遇到这样的场景:Agent 正在执行一个多步骤的任务,比如“下单购买商品”,但执行到一半时,我们…

2026/7/29 0:01:46阅读更多 →
自律同行,突破无界!NANK南卡正式官宣曾舜晞成为品牌代言人

自律同行,突破无界!NANK南卡正式官宣曾舜晞成为品牌代言人

近日,国际专注开放式技术研发的声学品牌Nank南卡,正式官宣实力艺人曾舜晞担任品牌代言人。消息一经发出便轰动全网。为什么耳机品牌不选择流量明星、老牌歌手?而且是选择曾舜晞?让我们一起来探索一下!比起短期的流量&a…

2026/7/29 0:01:46阅读更多 →
【RT-DETR多模态创新改进】CVPR 2025 | 独家特征融合创新改进篇 | 引入RLAB残差线性注意力模块,有效融合并强调多尺度特征,多种改进点,适合红外与可见光融合目标检测任务,有效涨点

【RT-DETR多模态创新改进】CVPR 2025 | 独家特征融合创新改进篇 | 引入RLAB残差线性注意力模块,有效融合并强调多尺度特征,多种改进点,适合红外与可见光融合目标检测任务,有效涨点

一、本文介绍 🔥本文在RT-DETR多模态融合目标检测中引入RLAB残差线性注意力模块,可在不同模态特征交互阶段进行多次残差细化,使可见光、红外等特征在尺度、语义和空间位置上更好对齐;随后将细化特征与解码器输出拼接并生成Q、K、V,通过线性注意力自适应强化关键通道、目…

2026/7/29 0:01:46阅读更多 →
YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

YOLOv8推理性能优化:从1.2FPS到35FPS的全链路加速实践

如果你在部署 YOLOv8 时,发现推理速度只有可怜的 1-2 FPS,而别人的演示视频却能跑到 30 FPS 以上,那么问题很可能不在模型本身,而在于你的整个处理链路。很多开发者拿到一个训练好的 YOLOv8 模型后,会直接使用官方示例…

2026/7/28 20:22:24阅读更多 →
Coze与Dify对比指南:低代码AI应用开发从入门到实战

Coze与Dify对比指南:低代码AI应用开发从入门到实战

1. 从零到一:为什么你需要了解 Coze 和 Dify?如果你对 AI 应用开发感兴趣,但一看到“大模型”、“智能体”、“工作流”这些词就头疼,觉得门槛太高,那这篇文章就是为你准备的。很多开发者,包括我自己&#…

2026/7/29 4:31:51阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

AI生图工具怎么选?2026年6月版实测对比

做自媒体的朋友应该都有体会:配图一直是个让人头疼的问题。2026年,AI生图工具已经非常成熟了,但工具太多反而不知道怎么选。以下是截至2026年6月我对主流AI生图工具的实测对比。Midjourney V8.1:速度之王2026年6月11日&#xff0c…

2026/7/28 2:35:58阅读更多 →