S32K1xx MCAL之SPI模块配置——片选、时钟、数据的正确打开方式
目录一、SPI基础知识回顾1.1 SPI四线制1.2 SPI四种工作模式二、MCAL SPI核心概念Sequence / Job / Channel2.1 Channel通道2.2 Job作业2.3 Sequence序列三、EB Tresos配置流程3.1 Mcu时钟配置3.2 Spi配置3.2.1 SpiGeneral3.2.2 SpiChannel3.2.3 SpiExternalDevice3.2.4 SpiJob3.2.5 SpiSequence3.2.6 SpiPhyUnit四、代码实现五、测试在车载嵌入式开发中SPI串行外设接口凭借其高速、全双工、简单易用的特点被广泛用于传感器数据采集、存储芯片读写、外围设备控制等场景。S32K1xx系列MCU的MCAL微控制器抽象层提供了标准化的Spi驱动能够方便地配置多路SPI通信并且精确控制通信速率、数据格式和片选时序。本文基于 S32K118 和 EB tresos 配置工具详细介绍如何使用MCAL的Spi模块正确配置片选CS极性、时钟SCLK极性和相位、数据传输位宽等关键参数实现主从设备间的稳定通信并给出完整的代码示例。一、SPI基础知识回顾1.1 SPI四线制SPI协议使用主从架构通过四个主要信号线完成全双工通信⚠️注意CS信号通常是低电平有效但有些器件可能相反配置时一定要查清楚器件手册。1.2 SPI四种工作模式时钟极性CPOL和时钟相位CPHA的组合定义了四种SPI模式关键主从设备的SPI模式配置必须一致否则通信将失败二、MCAL SPI核心概念Sequence / Job / Channel在MCAL SPI驱动中有三个核心概念需要理解2.1 Channel通道软件层面的概念与硬件物理通道无关主要负责Buffer的配置一个Channel可以同时属于多个Job2.2 Job作业和外设绑定一个Job下面可以有多个Channel且至少有一个Channel一个Job可以同时属于多个Sequence2.3 Sequence序列传输的基本单元只能操作Sequence一个Sequence下面可以有多个Job且至少有一个Job同一个Sequence下的多个Job拥有相同的优先级要点传输以Sequence为单位发起一个Sequence完成需要其下所有Job和所有Channel都传输完成。三、EB Tresos配置流程3.1 Mcu时钟配置S32K1的LPSPI时钟源可以选择系统时钟、SOSCDIV2_CLK、SIRCDIV2_CLK、FIRCDIV2_CLK这里选择FIRCDIV2_CLK作为LPSPI0的时钟源增加LPSPI0的参考时钟3.2 Spi配置3.2.1 SpiGeneralSpiChannelBuffersAllowed控制着每个SpiChannel的数据是存放在驱动内部还是由上层应用来提供。内部缓冲区 (IB)数据和缓存都由Spi驱动自己管理和维护外部缓冲区 (EB)数据和缓存的指针由上层应用通过API提供驱动直接操作上层应用指定的内存。配置为2即 IB和EB都支持SpiLevelDelivered用于决定SPI驱动支持同步传输、异步传输还是两者都支持。配置为2即两者都支持SpiCPUClockRef时钟配置为FIRCDIV2_CLK3.2.2 SpiChannel增加两个SpiChannelSpiDataWidth用于指定每次传输的数据位宽也就是每一帧数据有多少个比特位SpiIbNBuffers生效的前提是该通道的SpiChannelType被设置为了IB(Internal Buffer)。这个参数的值就是该通道内部缓冲区的大小3.2.3 SpiExternalDevice增加一个ExternalDeviceSpiBaudrate波特率设置SpiCsIdentifier为一个具体的 SPI 从设备指定它所连接的那个硬件片选CS引脚SpiCsPolarity 用于指定片选CS信号的有效电平极性——也就是告诉驱动这个从设备需要CS引脚拉高还是拉低才算被选中SpiCsSelection决定了片选CS信号的控制方式——是交给SPI硬件外设自动管理还是由MCAL驱动通过GPIO软件模拟控制SpiDataShiftEdge定义了 SPI 数据的移位边沿。LEADING在时钟信号的第一个边沿前沿移位数据TRAILING在时钟信号的第二个边沿后沿移位数据⚙️ 与 CPHA 的关系及配置误区一个常见的误解是将 SpiDataShiftEdge 等同于 CPHA时钟相位但实际上它与 CPHA 的配置相反SpiDataShiftEdge 定义的是“数据改变”的边沿而非“数据采样”的边沿。当 SpiDataShiftEdge 配置为 TRAILING后沿移位时实际上对应的是 CPHA 0在第一个边沿采样第二个边沿改变数据。反之当配置为 LEADING前沿移位时对应的是 CPHA 1在第二个边沿采样第一个边沿改变数据。SpiEnableCs片选使能SpiShiftClockIdleLevel: 用于指定 SPI 时钟信号SCLK在空闲状态时的电平——也就是没有数据传输时时钟线是保持高电平还是低电平。这个参数直接对应 SPI 协议中的 CPOL3.2.4 SpiJob增加一个Job定义用什么参数传关联 ExternalDevice、优先级SpiJobPriority 的值范围是 0~3数值越大优先级越高。3.2.5 SpiSequenceSpiSequence是 MCAL SPI 驱动中最高层的配置容器也是用户在应用层直接操作的对象。它把多个SpiJob按顺序组装成一个完整的传输任务用户只需调用 Spi_AsyncTransmit(SequenceID) 或 Spi_SyncTransmit(SequenceID)驱动就会自动按顺序执行该 Sequence 下的所有 Job。增加一个SpiSequence指定job3.2.6 SpiPhyUnitSpiPhyUnit 是MCAL SPI驱动中最底层的硬件抽象单元直接对应 S32K1xx 芯片上的一个具体LPSPI硬件外设实例如 LPSPI0、LPSPI1。在 EB Tresos 中它配置的是这个 SPI 硬件模块本身怎么工作而不是某个从设备怎么通信。SpiPhyUnitMode主模式SpiPhyUnitSync用于决定该SPI硬件单元是否支持同步阻塞传输模式。它控制着调用 Spi_SyncTransmit() 时CPU 要不要一直等到传输完成才能干别的事。SpiPhyUnitClockRef参考时钟配置四、代码实现测试代码采用同步传输模式在一个sequence中传输一个job一个job中传输两个channel数据#includeS32K118.h#includes32_core_cm0.h#includeMcu.h#includePort.h#includeDio.h#includeGpt.h#includeMcal.h#includeCDD_Mcl.h#includeCan.h#includeWdg.h#includePwm.h#includeSpi.h#includeS32K118_features.h//#define Enable_Wdg#defineEnable_Spi#ifdefined(__ghs__)#define__INTERRUPT_SVC__interrupt#define__NO_RETURN_Pragma(ghs nowarning 111)#elifdefined(__ICCARM__)#define__INTERRUPT_SVC__svc#define__NO_RETURN_Pragma(diag_suppressPe111)#elifdefined(__GNUC__)#define__INTERRUPT_SVC__attribute__((interrupt(SVC)))#define__NO_RETURN#else#define__INTERRUPT_SVC#define__NO_RETURN#endif#defineS32K11x_SERIES1/** S32_NVIC - Size of Registers Arrays */#defineS32_NVIC_ISER_COUNT1u#defineS32_NVIC_ICER_COUNT1u#defineS32_NVIC_ISPR_COUNT1u#defineS32_NVIC_ICPR_COUNT1u#defineS32_NVIC_IPR_COUNT8u/** S32_NVIC - Register Layout Typedef */typedefstruct{__IOuint32_tISER[S32_NVIC_ISER_COUNT];/** Interrupt Set Enable Register, array offset: 0x0, array step: 0x4 */uint8_tRESERVED_0[124];__IOuint32_tICER[S32_NVIC_ICER_COUNT];/** Interrupt Clear Enable Register, array offset: 0x80, array step: 0x4 */uint8_tRESERVED_1[124];__IOuint32_tISPR[S32_NVIC_ISPR_COUNT];/** Interrupt Set Pending Register, array offset: 0x100, array step: 0x4 */uint8_tRESERVED_2[124];__IOuint32_tICPR[S32_NVIC_ICPR_COUNT];/** Interrupt Clear Pending Register, array offset: 0x180, array step: 0x4 */uint8_tRESERVED_3[380];__IOuint32_tIPR[S32_NVIC_IPR_COUNT];/** Interrupt Priority Register n, array offset: 0x300, array step: 0x4 */}S32_NVIC_Type,*S32_NVIC_MemMapPtr;#defineS32_NVIC_BASE(0xE000E100u)/** Peripheral S32_NVIC base pointer */#defineS32_NVIC((S32_NVIC_Type*)S32_NVIC_BASE)/** Array initializer of S32_NVIC peripheral base addresses */#defineS32_NVIC_BASE_ADDRS{S32_NVIC_BASE}/** Array initializer of S32_NVIC peripheral base pointers */#defineS32_NVIC_BASE_PTRS{S32_NVIC}#defineFEATURE_NVIC_PRIO_BITS(2U)externuint32_t__VECTOR_RAM[((uint32_t)(LPUART0_RxTx_IRQn))16U1U];externuint32_t__VECTOR_TABLE[((uint32_t)(LPUART0_RxTx_IRQn))16U1U];externuint32_t__DATA_ROM[];externuint32_t__DATA_END[];typedefvoid(*isr_t)(void);voidINT_SYS_EnableIRQ(IRQn_Type irqNumber){S32_NVIC-ISER[(uint32_t)(irqNumber)5U](uint32_t)(1UL((uint32_t)(irqNumber)(uint32_t)0x1FU));}voidINT_SYS_InstallHandler(IRQn_Type irqNumber,constisr_tnewHandler,isr_t*constoldHandler){constuint32_t*aVectorRam(uint32_t*)__VECTOR_RAM;constuint32_t*aVectorTable(uint32_t*)__VECTOR_TABLE;constuint32_t*aDataRom(uint32_t*)__DATA_ROM;constuint32_t*aDataRam(uint32_t*)__DATA_END;if((aVectorRam!aVectorTable)||(aDataRomaDataRam)){uint32_t*pVectorRam(uint32_t*)__VECTOR_RAM;/* Save the former handler pointer */if(oldHandler!(isr_t*)0){*oldHandler(isr_t)pVectorRam[((int32_t)irqNumber)16];}pVectorRam[((int32_t)irqNumber)16](uint32_t)newHandler;}}voidINT_SYS_SetPriority(IRQn_Type irqNumber,uint8_tpriority){uint8_tshift(uint8_t)(8U-FEATURE_NVIC_PRIO_BITS);if((int32_t)irqNumber0){uint32_tintVectorId((uint32_t)(irqNumber)0xFU);uint32_tregIdintVectorId/4U;/* Compute pointer to SHPR register - avoid MISRA violation. */#ifdefined(S32K11x_SERIES)volatileuint32_t*shpr_reg_ptr((regId2U)?(volatileuint32_t*)S32_SCB-SHPR2:(volatileuint32_t*)S32_SCB-SHPR3);uint8_tpriByteShift(uint8_t)(((uint8_t)(intVectorId)0x3U)3U);/* Clear the old value from the register */*shpr_reg_ptr~(0xFFULpriByteShift);/* Set Priority for Cortex-M0P System Interrupts */*shpr_reg_ptr|((uint32_t)(((((uint32_t)priority)shift))0xFFUL))priByteShift;#elsevolatileuint8_t*shpr_reg_ptr((regId1U)?(volatileuint8_t*)S32_SCB-SHPR1:((regId2U)?(volatileuint8_t*)S32_SCB-SHPR2:(volatileuint8_t*)S32_SCB-SHPR3));/* Set Priority for Cortex-M4 System Interrupts */shpr_reg_ptr[intVectorId%4U](uint8_t)(((((uint32_t)priority)shift))0xffUL);#endif/* defined (S32K11x_SERIES) */}else{/* Set Priority for device specific Interrupts */#ifdefined(S32K11x_SERIES)uint32_tiprVectorId(uint32_t)(irqNumber)2U;uint8_tpriByteShift(uint8_t)((((uint8_t)irqNumber)0x3U)3U);/* Clear the old value from the register */S32_NVIC-IPR[iprVectorId]~(0xFFULpriByteShift);S32_NVIC-IPR[iprVectorId]|((uint32_t)(((((uint32_t)priority)shift))0xFFUL))priByteShift;#elseS32_NVIC-IP[(uint32_t)(irqNumber)](uint8_t)(((((uint32_t)priority)shift))0xFFUL);#endif/* defined (S32K11x_SERIES) */}}voidCan_TxMessage(void){Can_PduType TxPdu;uint8 TxMessage[8]{0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88};TxPdu.id0x456;TxPdu.swPduHandle0;TxPdu.length8;TxPdu.sdu(uint8*)TxMessage[0];Can_Write((Can_HwHandleType)CanHardwareObject_TX,(Can_PduType*)TxPdu);}voidTask_10ms(void){Dio_FlipChannel(DioConf_DioChannel_PTC_6);#ifdefEnable_WdgWdg_SetTriggerCondition(100);#endif}voidWdg_IsrNotification0(void){Wdg_SetTriggerCondition(100);}uint8CAN_PdurReceiveCallout(void){returnTRUE;}voidCan_ErrorNotification(void){uint32 i0;i;}voidCanFD_ErrorNotification(void){uint32 i0;i;}externISR(LPIT_0_ISR);externISR(FTM_0_ISR);externISR(Wdg_Wdog0_Isr);uint8_tSPI_IB[8]{0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55};uint8_tSPI_IB2[4]{0x11,0x11,0x11,0x11};intmain(void){/* module init */Mcu_Init(Mcu_Config);Mcu_InitClock(0U);Port_Init(Port_Config);Mcl_Init(Mcl_Config);Gpt_Init(Gpt_Config);Can_Init(Can_Config);Pwm_Init(Pwm_Config);Pwm_SetDutyCycle(PwmChannel_0,(uint16)0x2000);#ifdefEnable_SpiSpi_Init(Spi_Config);//初始化Spi模块#endif#ifdefEnable_WdgWdg_Init(Wdg_Config);Wdg_SetTriggerCondition(100);#endif/* Gpt Enable */Gpt_StartTimer(GptConf_GptChannelConfiguration_GptChannelConfiguration_10msTask,240000);Gpt_EnableNotification(GptConf_GptChannelConfiguration_GptChannelConfiguration_10msTask);Can_SetControllerMode(CanConf_CanController_CanController_0,CAN_CS_STARTED);#ifdefEnable_WdgWdg_SetMode(WDGIF_SLOW_MODE);#endifINT_SYS_SetPriority(LPIT_IRQn,3);#ifdefEnable_WdgINT_SYS_SetPriority(FTM0_Ch0_Ch7_IRQn,2);INT_SYS_SetPriority(WDOG_IRQn,1);#endif/* Interrupt Enable */INT_SYS_EnableIRQ(LPIT_IRQn);INT_SYS_InstallHandler(LPIT_IRQn,LPIT_0_ISR,NULL_PTR);#ifdefEnable_WdgINT_SYS_EnableIRQ(FTM0_Ch0_Ch7_IRQn);INT_SYS_InstallHandler(FTM0_Ch0_Ch7_IRQn,FTM_0_ISR,NULL_PTR);INT_SYS_EnableIRQ(WDOG_IRQn);INT_SYS_InstallHandler(WDOG_IRQn,Wdg_Wdog0_Isr,NULL_PTR);#endif/* CAN TX message */Can_TxMessage();#ifdefEnable_SpiSpi_WriteIB(SpiConf_SpiChannel_SpiChannel_0,SPI_IB[0]);//设置channel0 IB buffer数据Spi_WriteIB(SpiConf_SpiChannel_SpiChannel_1,SPI_IB2[0]);//设置channel0 IB buffer数据Spi_SyncTransmit(SpiConf_SpiSequence_SpiSequence_0);//Spi同步传输#endifwhile(1){Can_MainFunction_Mode();Can_MainFunction_Write();Can_MainFunction_Read();Can_MainFunction_BusOff();#ifdefEnable_SpiSpi_MainFunction_Handling();//Spi周期处理函数#endif}}五、测试运行测试代码观察MOSI波形。可以看到前8个字节为0x55后4个字节为0x11。

相关新闻

【数学建模】SHAP 算法:从 Shapley Value 到机器学习模型可解释性

【数学建模】SHAP 算法:从 Shapley Value 到机器学习模型可解释性

【数学建模】SHAP 算法:从 Shapley Value 到机器学习模型可解释性 摘要 机器学习模型预测结果往往难以解释。尤其是在金融风控、医疗诊断、推荐系统、广告排序等场景中,我们不仅关心模型“预测了什么”,更关心模型“为什么这样预测”。 SH…

2026/7/19 15:59:17阅读更多 →
【数学建模】结构方程模型 SEM 详解

【数学建模】结构方程模型 SEM 详解

【数学建模】结构方程模型 SEM 详解 文章目录【数学建模】结构方程模型 SEM 详解一、什么是结构方程模型?二、SEM 的核心思想1. 测量模型2. 结构模型三、SEM 中的重要概念1. 观测变量2. 潜变量3. 路径系数4. 因子载荷5. 测量误差四、SEM 的基本模型类型1. 验证性因子…

2026/7/19 15:59:17阅读更多 →
自变量机器人官网与开源生态深度研究:产品与 WALL 体系全景

自变量机器人官网与开源生态深度研究:产品与 WALL 体系全景

自变量机器人官网与开源生态深度研究:产品与 WALL 体系全景 目录 公司与官网结构WALL 模型体系产品矩阵:量子与灵巧手应用场景与能力叙事开源生态:GitHub 与 Hugging Face具亮计划与开发者支持官网信息完整度与研究含义参考资料与免责声明

2026/7/19 15:59:17阅读更多 →
ngx_output_chain_get_buf

ngx_output_chain_get_buf

1 定义 ngx_output_chain_get_buf 函数 定义在 src/core/ngx_output_chain.cstatic ngx_int_t ngx_output_chain_get_buf(ngx_output_chain_ctx_t *ctx, off_t bsize) {size_t size;ngx_buf_t *b, *in;ngx_uint_t recycled;in ctx->in->buf;size ctx->buf…

2026/7/20 0:15:05阅读更多 →
互联网大厂常见Java面试题及答案汇总(2026持续更新)

互联网大厂常见Java面试题及答案汇总(2026持续更新)

金九银十即将来袭,又是一个跳槽的好季节,准备跳槽的同学都摩拳擦掌准备大面好几场,今天为大家准备了互联网面试必备的 1 到 5 年 Java 面试者都需要掌握的面试题,分别 JVM,并发编程,MySQL,Tomca…

2026/7/20 0:15:05阅读更多 →
python数据可视化技巧的100个练习 -- 31. 类别数据的点图

python数据可视化技巧的100个练习 -- 31. 类别数据的点图

重要性★★★☆☆ 难度★★☆☆☆ 你是一家零售公司的数据分析师。你的经理要求你可视化最近产品发布的客户满意度评级分布。评级是分类的,范围从“非常不满意”到“非常满意”。创建一个点图以显示每个评级类别的频率。使用 Python 进行数据处理和可视化。在代码中生成输入…

2026/7/20 0:13:05阅读更多 →
智能体走进物理世界,千里科技携舱驾协同成果亮相WAIC 2026

智能体走进物理世界,千里科技携舱驾协同成果亮相WAIC 2026

在2026世界人工智能大会(WAIC 2026)举办期间,千里科技董事长、阶跃星辰董事长印奇作为特邀嘉宾出席大会开幕式并在大会主论坛(上午场)发表主题演讲《当智能体进入物理世界》。在印奇看来,"智能体"…

2026/7/20 0:13:05阅读更多 →
商汤大装置发布“技术-生态-商业”闭环布局,共启“国产AI基础设施规模化商用元年”

商汤大装置发布“技术-生态-商业”闭环布局,共启“国产AI基础设施规模化商用元年”

7月18日,在WAIC 2026商汤科技 “基座大模型架构创新与生态合作论坛”上,商汤科技联合创始人、大装置事业群总裁杨帆发表《智变共生——加速AI基础设施持续升级》主题演讲,系统呈现了商汤大装置国产AI基础设施“技术-生态-商业”闭环布局&…

2026/7/20 0:13:05阅读更多 →
2026郑州美发学校避坑指南:拆解5种教学方式,谁在“流水线”谁在“真传技”?

2026郑州美发学校避坑指南:拆解5种教学方式,谁在“流水线”谁在“真传技”?

2026年想在郑州学美发,很多零基础学员最先搜索的问题就是:郑州美发学校哪家好?这个问题没有一个只看学校名字就能得出的答案。因为不同学校的课程方向、学习周期、教学方式和适合人群并不一样。有的更适合零基础,有的偏向发型师进修,还有的只做某一项短期技术培训。对于完全没…

2026/7/20 0:11:05阅读更多 →
Go语言静态资源打包方案对比与实践指南

Go语言静态资源打包方案对比与实践指南

1. 项目背景与核心需求在Go语言开发中,我们经常需要处理静态资源文件的打包问题。无论是Web应用的模板文件、前端资源,还是配置文件、证书等,都需要随程序一起分发。传统做法是将这些文件与编译后的二进制文件放在同一目录下,但这…

2026/7/19 0:01:04阅读更多 →
Go语言实现高性能LDAP认证服务的架构与实践

Go语言实现高性能LDAP认证服务的架构与实践

1. 项目背景与核心价值LDAP(轻量级目录访问协议)作为企业级身份认证的黄金标准,已经服务了超过80%的财富500强公司。我在金融科技领域实施统一认证体系时,发现传统Java方案存在启动慢、内存占用高等痛点。而Go语言凭借其协程并发模…

2026/7/19 0:01:04阅读更多 →
【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

更多请点击: https://intelliparadigm.com 第一章:AI面试官实战指南的核心价值与适用场景 AI面试官并非替代人类HR的“黑箱工具”,而是以可解释、可审计、可迭代的方式,赋能招聘全链路的关键基础设施。其核心价值在于将主观经验沉…

2026/7/19 0:01:04阅读更多 →
2026 WAIC:努比亚二代“豆包手机”NaviX Ultra亮相,智能体验全面升级!

2026 WAIC:努比亚二代“豆包手机”NaviX Ultra亮相,智能体验全面升级!

7月18日智东西消息,在2026 WAIC期间,努比亚联合字节豆包打造的二代“豆包手机”努比亚NaviX Ultra首次亮相,相比一代有诸多升级。智能体手机理念中兴通讯终端事业部总裁、努比亚总裁倪飞表示,智能体手机要从人操作手机变为手机帮人…

2026/7/20 0:01:04阅读更多 →
努比亚NaviX Ultra亮相WAIC,智能体手机能否让用户生活更简单?

努比亚NaviX Ultra亮相WAIC,智能体手机能否让用户生活更简单?

努比亚NaviX Ultra:外观与功能双升级在2026 WAIC期间,首次亮相的努比亚NaviX Ultra吸引了众多目光。它是努比亚联合字节豆包打造的二代“豆包手机”,与一代努比亚M153相比,外观设计变化较大。其机身背部搭载横向排布的大尺寸影像模…

2026/7/20 0:01:04阅读更多 →
C# 将逗号分割的字符串转换为long,并添加到List<long>

C# 将逗号分割的字符串转换为long,并添加到List<long>

目录 方法1:使用Split和Convert.ToInt64 方法2:使用LINQ的Select和ToList 方法3:使用TryParse进行异常安全转换(推荐) 如果您喜欢此文章,请收藏、点赞、评论,谢谢,祝您快乐每一天…

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

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

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

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

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

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

2026/7/19 14:50:26阅读更多 →
AI生图工具怎么选?2026年6月版实测对比

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

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

2026/7/19 18:50:36阅读更多 →