news 2026/10/16 22:02:00

STM32F407上FreeRTOS与LwIP多中间件整合实战:避坑指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
STM32F407上FreeRTOS与LwIP多中间件整合实战:避坑指南

简介:这是一份面向嵌入式开发者的STM32F407综合实战工程,整合FreeRTOS实时操作系统与LWIP协议栈,并完成文件系统移植,适合已具备一定STM32基础、希望打通网络通信与多任务调度的进阶学习者。工程以RMII接口搭配KSZ8031 PHY,通过修改PHY寄存器地址即可适配其他型号PHY,同时内置嵌入式WebServer用于整体功能验证,另附IO、CAN、USART等外设测试程序,可作为工业控制、物联网终端等场景的参考模板。压缩包共629个文件,约17.25MB,以155个h头文件与131个c源文件为核心代码,辅以Keil工程配置、编译中间文件及少量说明文档,结构完整便于二次开发。目前已有1005人学习下载。读者可从中获得FreeRTOS与LWIP协同移植的完整思路、PHY驱动适配方法、FATFS文件系统接入流程以及WebServer测试框架,并借助CAN、USART等例程快速验证硬件,是学习STM32F4网络与RTOS综合应用的实用参考。

1. 一块 F407 上塞进七个中间件:这套组合到底在解决什么问题

如果你手头有一块 STM32F407 的开发板,上面挂着 KSZ8031 以太网 PHY、SD 卡槽、DS18B20 温度传感器、CAN 收发器,还要跑 FreeRTOS 和 LwIP,那这篇文章就是写给你的。这套组合的典型场景是工业数据采集网关:通过 18B20 采集现场温度,通过 CAN 总线读取设备状态,通过 USART 对接上位机或调试终端,通过 SD 卡做本地数据存储,通过以太网把数据推到远端服务器,所有任务由 FreeRTOS 调度。听起来每个模块单独用都不难,但把它们塞进同一颗芯片、同一套 RTOS 里,问题就来了——PHY 初始化不成功、LwIP 跑着跑着就断、SD 卡和以太网抢总线、CAN 中断优先级和 RTOS 调度打架。我前后做过三版类似的板子,第一版调了将近两周才让以太网稳定收发,第二版才把 SDIO 和 LwIP 的冲突理清楚。下面按“先跑通单个模块,再整合,最后调稳定性”的路径,把每一步的命令、参数和踩坑点讲清楚。

2. 从裸机到 FreeRTOS:任务划分与优先级怎么定

2.1 为什么不能把所有逻辑塞进一个任务

很多人第一次用 FreeRTOS 会习惯性地创建一个任务,然后在里面轮询所有外设。这种做法在功能验证阶段能跑,但一旦加上 LwIP 和 SD 卡写入,就会出现“以太网收包不及时导致丢包”或者“SD 卡写入阻塞导致 CAN 报文溢出”的问题。正确的做法是按数据流和实时性要求拆任务。

我一般会拆成这几个任务:以太网接收任务(优先级最高,因为 LwIP 的ethernetif_input需要及时处理)、CAN 接收任务(次高,CAN 报文有硬件缓冲区但溢出后不可恢复)、温度采集任务(低频,1 秒一次即可)、SD 卡写入任务(低优先级,但需要较大的栈)、USART 命令解析任务(中等优先级,响应上位机指令)。优先级数值越大优先级越高,在FreeRTOSConfig.h里配置configMAX_PRIORITIES至少为 8。

// 任务优先级定义,数值越大优先级越高 #define TASK_PRIO_ETH_RX 6 // 以太网接收,必须最高 #define TASK_PRIO_CAN_RX 5 // CAN 接收,次高 #define TASK_PRIO_USART_CMD 4 // 串口命令解析 #define TASK_PRIO_TEMP 3 // 温度采集 #define TASK_PRIO_SD_WRITE 2 // SD 卡写入,最低 // 任务栈大小,单位是 word(4 字节) // LwIP 相关任务栈要 512 以上,SD 卡写入因为用了 FATFS 也要 512 #define TASK_STACK_ETH_RX 512 #define TASK_STACK_CAN_RX 256 #define TASK_STACK_USART 256 #define TASK_STACK_TEMP 256 #define TASK_STACK_SD_WRITE 512

这里的关键参数是栈大小。LwIP 的tcpip_thread和ethernetif_input如果栈不够,会直接进 HardFault,而且这种 HardFault 往往在运行几分钟后才出现,调试起来很痛苦。我的经验是:凡是调用 LwIP API 的任务,栈至少 512 word;凡是调用f_write的任务,栈至少 512 word,因为 FATFS 内部有较深的调用链。

2.2 中断优先级与 FreeRTOS 的配合

STM32F407 的中断优先级分组必须设置为NVIC_PRIORITYGROUP_4,即 4 位抢占优先级、0 位子优先级。FreeRTOS 的configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY一般设为 5,意味着抢占优先级高于 5 的中断不能调用FromISR结尾的 API。以太网和 CAN 的中断优先级要设得比这个值低(数值大),否则xQueueSendFromISR会触发断言。

// 在 main 里最先调用,设置中断优先级分组 HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4); // 以太网中断优先级,抢占优先级设为 6,允许调用 FromISR API HAL_NVIC_SetPriority(ETH_IRQn, 6, 0); HAL_NVIC_EnableIRQ(ETH_IRQn); // CAN 接收中断优先级,设为 7 HAL_NVIC_SetPriority(CAN1_RX0_IRQn, 7, 0); HAL_NVIC_EnableIRQ(CAN1_RX0_IRQn);

注意:如果以太网中断优先级设成 4 或更高,xQueueSendFromISR会直接触发configASSERT死循环,现象是程序卡在vPortValidateInterruptPriority里出不来。

3. RMII 接口驱动 KSZ8031:从 PHY 复位到 ping 通

3.1 硬件连接检查与 GPIO 配置

RMII 模式下,STM32F407 的 PA1 是 REF_CLK,PA2 是 MDIO,PA7 是 RMII_CRS_DV,PC1 是 MDC,PC4 是 RMII_RXD0,PC5 是 RMII_RXD1,PG11 是 RMII_TX_EN,PG13 是 RMII_TXD0,PG14 是 RMII_TXD1。KSZ8031 需要 50MHz 参考时钟,通常由 STM32 的 PA8 通过 MCO1 输出,或者由外部晶振提供。我用的板子是 PA8 输出 50MHz 给 PHY。

// 使能 GPIO 时钟 __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); __HAL_RCC_GPIOC_CLK_ENABLE(); __HAL_RCC_GPIOG_CLK_ENABLE(); // 配置 PA8 为 MCO1 输出 50MHz GPIO_InitTypeDef gpio = {0}; gpio.Pin = GPIO_PIN_8; gpio.Mode = GPIO_MODE_AF_PP; gpio.Pull = GPIO_NOPULL; gpio.Speed = GPIO_SPEED_FREQ_VERY_HIGH; gpio.Alternate = GPIO_AF0_MCO; HAL_GPIO_Init(GPIOA, &gpio); // 配置 MCO1 时钟源为 HSE,分频系数根据晶振频率计算 // 假设 HSE 为 8MHz,要输出 50MHz 需要 PLL 配置,这里用 PLLI2S 或直接旁路 // 更常见的做法是 PHY 用独立 50MHz 晶振,PA8 不输出 HAL_RCC_MCOConfig(RCC_MCO1, RCC_MCO1SOURCE_HSE, RCC_MCODIV_1);

如果 PHY 有独立的 50MHz 晶振,PA8 就不需要配置为 MCO。这一点在画板子时就要确认,否则调试时发现 PHY 没有时钟,会浪费很多时间。

3.2 PHY 复位与 LwIP 初始化顺序

KSZ8031 的复位引脚通常接在某个 GPIO 上,复位时序要求至少保持 10ms 低电平,然后拉高,等待 100ms 以上再访问 PHY 寄存器。LwIP 的ethernetif_init里会调用LAN8720_Init类似的 PHY 初始化函数,但 KSZ8031 的寄存器地址和 LAN8720 不同,需要自己写。

// PHY 复位,假设复位引脚接在 PD3 void KSZ8031_Reset(void) { HAL_GPIO_WritePin(GPIOD, GPIO_PIN_3, GPIO_PIN_RESET); HAL_Delay(20); // 至少 10ms,留余量 HAL_GPIO_WritePin(GPIOD, GPIO_PIN_3, GPIO_PIN_SET); HAL_Delay(150); // 等待 PHY 内部稳定 } // 读取 PHY ID,KSZ8031 的 ID 应该是 0x0022 开头 uint32_t KSZ8031_GetID(void) { uint32_t id = 0; id = ETH_ReadPHYRegister(0, PHY_REG_ID1); id = (id << 16) | ETH_ReadPHYRegister(0, PHY_REG_ID2); return id; }

LwIP 的初始化顺序是:lwip_init()→netif_add()→netif_set_default()→netif_set_up()。在netif_add时会调用ethernetif_init,里面完成 PHY 复位和 MAC 配置。如果 PHY 没复位成功,netif_set_up之后ping不通,但netif状态显示 up,这种“假 up”现象很常见。

3.3 验证以太网通路的三个命令

在 FreeRTOS 里跑 LwIP,建议先用ping验证链路层和网络层。在 PC 端执行:

# 假设板子 IP 设为 192.168.1.100 ping 192.168.1.100 -t # 如果 ping 不通,先看 ARP 表有没有板子的 MAC arp -a | findstr 192.168.1.100 # 用 Wireshark 抓包,过滤条件 arp || icmp

如果 ARP 请求发出去了但板子没回应,说明以太网接收中断没进,或者ethernetif_input没被调用。检查ETH_IRQHandler里是否调用了HAL_ETH_IRQHandler,以及HAL_ETH_RxCpltCallback里是否给了信号量让接收任务处理。

4. SDIO 挂 FATFS 与 LwIP 共存:总线冲突和 DMA 陷阱

4.1 SDIO 初始化与 FATFS 挂载

STM32F407 的 SDIO 外设支持 4 位宽总线,但和以太网共用 DMA 控制器时会有冲突。SDIO 的时钟分频在SDIO_INIT_CLK_DIV里设置,初始化阶段不能超过 400kHz,初始化完成后可以提高到 24MHz 或 48MHz。

// SDIO 初始化,注意 DMA 和中断优先级 void SDIO_Init(void) { hsd.Instance = SDIO; hsd.Init.ClockEdge = SDIO_CLOCK_EDGE_RISING; hsd.Init.ClockBypass = SDIO_CLOCK_BYPASS_DISABLE; hsd.Init.ClockPowerSave = SDIO_CLOCK_POWER_SAVE_DISABLE; hsd.Init.BusWide = SDIO_BUS_WIDE_4B; // 4 位宽 hsd.Init.HardwareFlowControl = SDIO_HARDWARE_FLOW_CONTROL_ENABLE; hsd.Init.ClockDiv = 2; // 48MHz / (2+2) = 12MHz,稳定后可改小 HAL_SD_Init(&hsd); } // FATFS 挂载 FATFS fs; FRESULT fres; fres = f_mount(&fs, "0:", 1); // 1 表示立即挂载 if (fres != FR_OK) { printf("f_mount failed: %d\r\n", fres); }

f_mount的第三个参数为 1 时会立即调用disk_initialize,如果 SD 卡没插好或者 SDIO 初始化失败,会返回FR_NOT_READY或FR_DISK_ERR。

4.2 SDIO 和以太网共用 DMA 的冲突处理

STM32F407 的 DMA1 和 DMA2 各有多个流。以太网 MAC 使用 DMA 自己的专用通道,不占用 DMA1/DMA2 的流,但 SDIO 使用 DMA2 的某个流。如果 LwIP 的memcpy和 SDIO 的 DMA 同时访问总线矩阵,会出现偶发的数据错误。我的做法是:SD 卡写入任务在调用f_write前获取一个互斥量,确保同一时间只有一个任务在操作 SDIO。

// SD 卡操作互斥量 SemaphoreHandle_t xSDMutex; // 写入任务里 if (xSemaphoreTake(xSDMutex, pdMS_TO_TICKS(1000)) == pdTRUE) { fres = f_open(&fil, "0:/data.csv", FA_OPEN_ALWAYS | FA_WRITE); if (fres == FR_OK) { f_lseek(&fil, f_size(&fil)); // 追加到末尾 f_printf(&fil, "%lu,%d.%d\r\n", tick, temp_int, temp_dec); f_close(&fil); } xSemaphoreGive(xSDMutex); } else { // 获取互斥量超时,记录错误 }

注意:f_printf在 FATFS 里默认可能没使能,需要在ffconf.h里把_FS_READONLY设为 0,_USE_STRFUNC设为 1 或 2。

4.3 掉电保护和文件系统一致性

工业现场经常直接断电,FATFS 在写入过程中断电会导致文件系统损坏。我一般会定期调用f_sync,并且在写入完成后关闭文件。如果对可靠性要求高,可以加一个超级电容或者铁电存储器做掉电检测,检测到掉电后立即f_sync并关闭文件。

// 掉电检测中断,优先级设为最高 void PVD_IRQHandler(void) { if (__HAL_PWR_GET_FLAG(PWR_FLAG_PVDO)) { // 立即同步文件系统 f_sync(&fil); f_close(&fil); // 停止所有写入任务 vTaskSuspend(xSDWriteTaskHandle); } }

5. 18B20、CAN、USART 的整合:时序、过滤器和中断

5.1 18B20 的微秒级时序与 RTOS 调度冲突

DS18B20 是单总线器件,复位脉冲要求拉低至少 480us,读写时隙在 60us 左右。在 FreeRTOS 里如果用vTaskDelay做延时,最小精度是 1 个 tick,通常 1ms,完全不够。必须用DWT或者TIM做微秒级延时。

// 用 DWT 做微秒延时 void DWT_Delay_us(uint32_t us) { uint32_t start = DWT->CYCCNT; uint32_t cycles = us * (SystemCoreClock / 1000000); while ((DWT->CYCCNT - start) < cycles); } // 18B20 复位 uint8_t DS18B20_Reset(void) { uint8_t presence; GPIO_InitTypeDef gpio = {0}; gpio.Pin = GPIO_PIN_0; gpio.Mode = GPIO_MODE_OUTPUT_OD; gpio.Pull = GPIO_NOPULL; gpio.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOB, &gpio); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET); DWT_Delay_us(500); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET); DWT_Delay_us(70); presence = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0); DWT_Delay_us(430); return presence; }

在读取温度时,要关中断或者用互斥量保护整个时序,否则一个中断进来就会打乱时隙。我的做法是把 18B20 的读取放在一个低优先级任务里,读取前taskENTER_CRITICAL(),读完后taskEXIT_CRITICAL(),临界区大约 1ms,对系统实时性影响可接受。

5.2 CAN 过滤器配置与接收队列

STM32F407 的 CAN1 有 28 个过滤器组,可以配置为掩码模式或列表模式。工业场景下通常只接收特定 ID 的报文,用掩码模式更灵活。

// CAN 过滤器配置,接收 ID 为 0x100~0x1FF 的标准帧 CAN_FilterTypeDef filter = {0}; filter.FilterBank = 0; filter.FilterMode = CAN_FILTERMODE_IDMASK; filter.FilterScale = CAN_FILTERSCALE_32BIT; filter.FilterIdHigh = 0x100 << 5; // 标准帧 ID 左移 5 位 filter.FilterIdLow = 0; filter.FilterMaskIdHigh = 0x700 << 5; // 掩码,0x700 表示高 3 位必须匹配 filter.FilterMaskIdLow = 0; filter.FilterFIFOAssignment = CAN_RX_FIFO0; filter.FilterActivation = ENABLE; HAL_CAN_ConfigFilter(&hcan1, &filter); // 启动 CAN HAL_CAN_Start(&hcan1); HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING);

在HAL_CAN_RxFifo0MsgPendingCallback里用xQueueSendFromISR把报文发给接收任务,不要在中断里做解析。

5.3 USART 命令解析与 DMA 接收

USART 用 DMA 接收不定长数据时,常用 IDLE 中断加 DMA 的方式。配置 DMA 为循环模式,在 IDLE 中断里计算接收长度。

// USART1 DMA 接收配置 uint8_t uart_rx_buf[256]; void USART1_Init(void) { // ... 省略 GPIO 和 USART 配置 HAL_UART_Receive_DMA(&huart1, uart_rx_buf, sizeof(uart_rx_buf)); __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE); } // IDLE 中断处理 void USART1_IRQHandler(void) { if (__HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE)) { __HAL_UART_CLEAR_IDLEFLAG(&huart1); uint32_t len = sizeof(uart_rx_buf) - __HAL_DMA_GET_COUNTER(huart1.hdmarx); // 把数据发给命令解析任务 BaseType_t xHigherPriorityTaskWoken = pdFALSE; xQueueSendFromISR(xUartQueue, &len, &xHigherPriorityTaskWoken); portYIELD_FROM_ISR(xHigherPriorityTaskWoken); } HAL_UART_IRQHandler(&huart1); }

6. 避坑与排查:这套组合最容易翻车的五个地方

6.1 以太网 ping 通但 TCP 连接不上

现象:PC 能 ping 通板子,但用 TCP 调试工具连接板子的 8080 端口一直失败。原因通常是 LwIP 的tcpip_thread栈溢出或者MEMP_NUM_TCP_PCB设得太小。解决:把lwipopts.h里的MEMP_NUM_TCP_PCB从默认的 5 改成 10,TCPIP_THREAD_STACKSIZE从 1024 改成 2048。

6.2 SD 卡写入一段时间后返回 FR_DISK_ERR

现象:系统运行几分钟后,f_write开始返回FR_DISK_ERR,重启后恢复。原因是 SDIO 的 DMA 和以太网 DMA 在总线矩阵上冲突,导致 SDIO 数据传输错误。解决:降低 SDIO 时钟到 12MHz,或者在sdio.c里把 SDIO 的 DMA 优先级设为最高,并在f_write前后加SCB_CleanDCache_by_Addr(如果开了 D-Cache)。

6.3 CAN 接收一段时间后不再进中断

现象:CAN 正常接收几分钟后,HAL_CAN_RxFifo0MsgPendingCallback不再触发。原因是 CAN 的接收 FIFO 溢出后没有正确清除标志位。解决:在回调里先读CAN_RI0R寄存器,再调用HAL_CAN_GetRxMessage,确保 FIFO 释放。另外检查CAN_IT_RX_FIFO0_OVERRUN是否使能,溢出时要有处理。

6.4 18B20 读数偶尔为 85 或 -127

现象:温度值偶尔跳变成 85 或 -127。85 是 DS18B20 的上电默认值,说明复位或转换命令没发成功;-127 是通信错误。原因是读取时序被中断打断。解决:把 18B20 读取放在临界区里,或者用硬件定时器触发读取,避免任务切换。

6.5 系统运行几小时后 HardFault

现象:系统运行几小时后进入 HardFault,看门狗复位。原因通常是某个任务的栈溢出,最常见的是 LwIP 的ethernetif_input任务或者 SD 卡写入任务。解决:在FreeRTOSConfig.h里使能configCHECK_FOR_STACK_OVERFLOW为 2,并在vApplicationStackOverflowHook里打印任务名。把 LwIP 相关任务栈加到 1024 word,SD 卡写入任务栈加到 768 word。

7. 用 FreeRTOS 的运行时统计和 LwIP 的统计计数器做长期稳定性验证

这套系统跑通不难,难的是连续跑 72 小时不出问题。我一般会在系统里加两个统计:FreeRTOS 的vTaskGetRunTimeStats和 LwIP 的stats_display。前者看每个任务的 CPU 占用,后者看丢包和内存错误。

// 使能 FreeRTOS 运行时统计 // 在 FreeRTOSConfig.h 里 #define configGENERATE_RUN_TIME_STATS 1 #define configUSE_STATS_FORMATTING_FUNCTIONS 1 #define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() // 用 TIM6 做统计时钟 #define portGET_RUN_TIME_COUNTER_VALUE() TIM6->CNT // 在某个低优先级任务里定期打印 void vStatsTask(void *pvParameters) { char buf[512]; while (1) { vTaskGetRunTimeStats(buf); printf("=== Task Stats ===\r\n%s\r\n", buf); stats_display(); // LwIP 统计 vTaskDelay(pdMS_TO_TICKS(60000)); // 每分钟一次 } }

vTaskGetRunTimeStats输出的格式是“任务名 运行时间 百分比”,如果某个任务占用超过 80%,说明它有阻塞或死循环。LwIP 的stats_display会打印mem、memp、pbuf等统计,如果memerr或pbuferr持续增长,说明内存池不够或者有泄漏。

我自己的习惯是:在实验室里用可调电源给板子供电,串口接一个日志工具,连续跑 72 小时,每 10 分钟记录一次任务栈剩余和 LwIP 错误计数。如果 72 小时后xPortGetFreeHeapSize没有明显下降,stats_display里的错误计数为 0,这套系统才算能拿去现场用。现场部署时再加一个硬件看门狗,喂狗逻辑放在优先级最低的任务里,确保所有高优先级任务都正常运行时才喂狗。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/16 22:00:08

IE自动跳转Edge不用重装:从不设置+IE模式+批量运维全解

简介&#xff1a;资源针对微软停止IE服务后打开IE自动跳转Edge的常见问题&#xff0c;给出完整解决思路&#xff0c;面向因企事业单位业务系统、老旧网站或特定网银登录场景而仍须使用IE浏览器的办公人员、系统管理员及网站测试人员。文档以docx格式编排&#xff0c;共1个文件&…

作者头像 李华
网站建设 2026/10/16 21:59:42

C#委托与事件:从delegate到EventHandler的机制与最佳实践

1. 委托的本来面目先说个我早年写代码的经历。那时候刚学会用public、private、class&#xff0c;以为把方法定义好、在哪都能随心调用&#xff0c;这个世界就通关了。结果第一次做Web API的时候&#xff0c;一个按钮点击事件怎么都接不到处理逻辑&#xff0c;排查到最后发现是…

作者头像 李华
网站建设 2026/10/16 21:58:50

传输网管入门:从TMN到E300,掌握SDH网管核心知识与实操

简介&#xff1a;这是一份面向传输网管初学者的入门参考&#xff0c;内容基于中兴通讯传输网管开发部内部培训PPT整理&#xff0c;系统讲解电信管理网&#xff08;TMN&#xff09;基础、SDH网管概述、信产部关于EMS的技术规范&#xff0c;以及E300网管系统实例。资源为单个PPT演…

作者头像 李华
网站建设 2026/10/16 21:55:33

STK 11自带案例从入门到改造:卫星仿真与覆盖分析实战

简介&#xff1a;STK11&#xff08;System Tool Kit 11&#xff09;是由AGI推出的空间系统模拟分析软件&#xff0c;在航天、国防、通信等领域应用广泛。这份压缩包内含其自带的应用案例&#xff0c;适合刚接触STK11的工程师与在校学生通过实例快速上手。包内共396个文件&#…

作者头像 李华
网站建设 2026/10/16 21:49:28

Rust自定义trait实战:行为契约、泛型设计与错误排查

说实话&#xff0c;在不少项目里我都见过一种尴尬场景&#xff1a;结构体写了一大堆&#xff0c;业务逻辑耦合在细节里&#xff0c;想换个底层实现就牵一发动全身。真正让我觉得代码开始变顺手的&#xff0c;是从我认真去写自定义Traits应用开始的。自定义trait&#xff0c;说白…

作者头像 李华
网站建设 2026/10/16 21:49:08

Dify应用提示词注入绕过手法与多层防御实践指南

做AI应用红队测试时&#xff0c;有一种现象我见得太多了&#xff1a;开发者在Dify里接了一个提示词注入检测节点&#xff0c;就觉得防护到位了&#xff0c;结果真正上手打一打&#xff0c;换几种表达方式就过了检测&#xff0c;系统提示词、知识库原文、工具调用权限全被套了出…

作者头像 李华