FreeRTOS 学习笔记

FreeRTOS 学习笔记

开篇引言

FreeRTOS作为轻量级实时操作系统,广泛适配物联网、工业控制、消费电子等嵌入式场景,本文聚焦FreeRTOS通用核心,整合概念,助力快速掌握核心逻辑和实操方法。

核心概念

掌握核心概念是FreeRTOS实操的基础,以下表格按"概念-定义-关键特性-通用场景"整理。

概念名称 核心定义 关键特性 通用应用场景
RTOS(实时操作系统) 为嵌入式系统设计的操作系统,能按优先级或时间约束响应外部事件,保证任务在规定时间内完成,区别于裸机开发 任务调度、实时响应、资源管理,轻量级适配嵌入式硬件 多任务并行处理、对响应时间有严格要求的场景(工业控制器、智能家居网关、车载终端)
任务(Task) FreeRTOS中最小的执行单元,本质是独立的函数,拥有专属堆栈和优先级,由调度器管理执行顺序 独立运行、可被抢占/挂起/恢复,与其他任务共享硬件资源 功能拆解为独立任务(传感器采集、数据处理、网络上报)
空闲任务(Idle Task) 调度器启动时自动创建的系统任务,优先级为0(最低),是系统无就绪任务时唯一运行的任务 优先级固定为0、不可删除,可自定义钩子函数(Idle Hook) 释放动态删除任务的内存(需开启configSUPPORT_DYNAMIC_ALLOCATION)、低优先级后台清理、系统状态监控
任务控制块(TCB) 每个任务的核心数据结构,存储任务优先级、堆栈指针、状态、句柄、通知值等关键信息 系统自动维护(动态创建)/手动分配(静态创建),是任务调度的核心依据 内核底层调度
vTaskDelay vs vTaskDelayUntil 两种任务延时API:vTaskDelay是相对延时(从调用时刻开始延时),vTaskDelayUntil是绝对延时(按固定周期执行) 相对延时受任务调度影响,绝对延时保证固定执行周期 vTaskDelay(非周期性任务,如按键响应后延时);vTaskDelayUntil(周期性任务,如100ms固定周期采集传感器)
任务状态(就绪态/运行态/阻塞态/挂起态) 任务生命周期的四种状态:就绪(等待调度)、运行(正在执行)、阻塞(等待事件/时间)、挂起(被动暂停) 状态可切换,调度器仅选就绪态任务执行,阻塞/挂起不占CPU 任务等待串口数据(阻塞)、手动暂停任务(挂起)、高优先级抢占低优先级(就绪→运行)


图1 FreeRTOS任务状态切换示意图

概念名称 核心定义 关键特性 通用应用场景
任务调度器 FreeRTOS内核核心组件,负责根据调度策略选择就绪态中最高优先级任务执行,是任务切换的核心逻辑 可抢占式设计,支持优先级调整,空闲时运行空闲任务 所有多任务场景的核心调度(紧急报警任务优先执行)
调度器挂起/恢复 全局暂停/恢复任务调度的操作,挂起期间所有任务切换停止,仅当前任务运行 任务级操作(非中断安全),挂起时长需极短,不可嵌套挂起 批量修改内核对象(如队列、信号量)时的原子操作
调度策略(抢占式/协作式/时间片) 抢占式(高优先级立即抢占低优先级)、协作式(任务主动释放CPU)、时间片(同优先级轮流执行) 抢占式保证实时性,协作式降低切换开销,时间片适配同优先级公平执行 抢占式(紧急报警)、协作式(低实时性统计)、时间片(同优先级多传感器采集)


图2 FreeRTOS三种调度策略对比图

概念名称 核心定义 关键特性 通用应用场景
互斥锁(Mutex) 特殊的二值信号量,用于资源互斥访问,具备优先级继承机制 有所有权、优先级继承,解决优先级反转,不可中断使用 多任务访问共享内存/Flash存储区
递归互斥锁(Recursive Mutex) 允许同一任务多次获取的互斥锁,需对应次数释放 所有权专属、递归获取/释放,优先级继承 嵌套函数中访问共享资源(多子函数访问同一外设)
事件组(Event Group) 多位二进制标志位集合,实现多事件同步,支持等待单个/多个事件触发 多事件批量管理、按位触发/等待,支持阻塞 等待多传感器就绪、系统初始化完成事件汇总
软件定时器(Software Timer) 基于系统时钟节拍实现的定时器,在定时器服务任务中执行回调函数,无需硬件定时器 轻量级、可单次/周期触发,回调函数不可阻塞 定时采集传感器、定时上报设备状态
堆栈(Task Stack) 每个任务专属内存空间,保存任务上下文、局部变量、函数调用栈 大小可配置,溢出导致系统崩溃,有独立堆栈指针 所有任务配置(数据处理任务需更大堆栈)
优先级(Task Priority) 任务重要程度标识,数值越大优先级越高,调度器优先执行高优先级就绪任务 可动态调整,同优先级按时间片调度,高优先级可抢占 紧急报警(高优先级)、数据采集(中优先级)、日志打印(低优先级)
中断管理(FreeRTOS与硬件中断交互) 硬件中断触发后,通过中断安全API与任务交互,ISR优先级高于所有任务 ISR中禁止阻塞,需用FromISR系列API,可触发任务切换 外部按键中断上报事件、串口接收中断传递数据
临界区(Critical Section) 不可被中断/调度的代码段,用于保护共享资源,防止数据错乱 需最短化执行时间,分任务级(关调度)和中断级(关中断) 多任务修改全局变量、任务与中断共享计数器
FreeRTOS内核 核心层包含任务调度器、内核对象、时钟管理、内存管理四大组件,基于时钟节拍驱动 可裁剪、可移植,核心逻辑与硬件解耦 所有FreeRTOS应用的基础,移植时仅适配底层接口
内存管理方案(heap_1~heap_5) FreeRTOS提供5种内存分配方案,基于静态/动态内存实现,适配不同嵌入式场景的内存约束 heap_1:仅分配不释放,无碎片;heap_2:可分配释放,不合并碎片;heap_3:封装标准malloc/free;heap_4:可分配释放+合并碎片(最常用);heap_5:heap_4基础上支持非连续内存块 heap_1(只读存储器/无释放场景);heap_4(绝大多数通用场景);heap_5(多块离散内存)


图3 FreeRTOS内存管理方案对比图

概念名称 核心定义 关键特性 通用应用场景
队列(Queue) 基于FIFO的异步通信机制,实现任务间/任务与中断间的数据传递,支持不同数据类型 解耦任务、支持阻塞等待、数据拷贝传递 传感器数据→处理任务、中断事件→应用层任务
信号量(二值/计数) 用于同步/互斥的轻量级机制,二值(0/1)控制资源独占,计数统计可用资源数 无所有权、支持阻塞等待,不可解决优先级反转;多级反转需优先级天花板机制补充 二值信号量(串口独占访问)、计数信号量(有限网络连接管理)
任务通知(Task Notifications) FreeRTOS轻量级同步/通信机制,每个任务对应一个32位通知值,可实现信号量、事件、轻量数据传递功能 资源占用少(无额外内核对象)、比队列更高效、支持覆盖/递增/存储等通知模式 轻量事件触发(按键中断通知任务)、单任务数据传递(小数据量参数传递)


图4 FreeRTOS内核核心组件关系图

核心操作流程

以下操作流程适用于所有适配FreeRTOS的芯片,仅以STM32F103为例补充实操细节,核心逻辑通用,聚焦"怎么做、用什么API、注意什么"。

1. FreeRTOS内核初始化与启动

  • 操作流程
    1. 硬件层:初始化系统时钟,配置FreeRTOS Tick依赖的硬件定时器;
    2. 内核初始化:初始化调度器、空闲任务、定时器服务任务;
    3. 创建应用任务:启动调度器前至少创建一个用户任务;
    4. 启动调度器:FreeRTOS开始管理任务执行。
  • 核心API
    • vTaskStartScheduler():启动调度器;
    • xTaskGetSchedulerState():获取调度器状态;
    • 底层适配:配置SysTick/硬件定时器为Tick时钟(通用逻辑)。
  • 关键注意事项
    1. Tick频率(configTICK_RATE_HZ)建议100-1000Hz,过高增加CPU开销;
    2. 启动调度器前必须初始化系统时钟,否则Tick异常;
    3. 空闲任务自动创建,需保证内存充足。
  • 常见坑点排查
    1. 调度器启动失败→检查系统时钟初始化是否完成、堆内存是否充足;
    2. Tick时钟异常→检查硬件定时器/SysTick配置是否匹配configTICK_RATE_HZ。
  • 示例:STM32F103配置72MHz系统时钟,SysTick设为1ms Tick,创建"LED闪烁任务"后启动调度器。

2. 任务管理

  • 操作流程
    1. 定义任务函数(无限循环+无返回值);
    2. 创建任务(指定堆栈、优先级、句柄);
    3. 任务自动进入就绪态,调度器择机执行;
    4. 按需挂起/恢复/删除任务。
  • 核心API
    • 动态创建:xTaskCreate();
    • 静态创建:xTaskCreateStatic()(需手动分配堆栈/任务控制块);
    • 管理API:vTaskDelete()/vTaskSuspend()/vTaskResume()、vTaskPrioritySet()。
  • 关键注意事项
    1. 任务函数必须无限循环,不可返回;
    2. 堆栈大小需结合局部变量、函数调用深度配置;
    3. 中断中禁止调用任务管理API。
  • 动态vs静态创建对比
    • 动态创建:自动分配内存,代码简洁,但有内存碎片风险;
    • 静态创建:手动分配内存,无碎片,适合高可靠/内存受限场景。


图5 任务动态创建与静态创建对比流程图

  • 常见坑点排查

    1. 任务创建失败→用xPortGetFreeHeapSize()检查堆内存、堆栈大小是否配置合理;
    2. 任务卡死→检查是否有死循环、阻塞时间设为portMAX_DELAY且事件未触发;
    3. 堆栈溢出→启用configCHECK_FOR_STACK_OVERFLOW,调试观察堆栈使用量。
  • 示例

    • 动态创建:创建"数据采集任务(优先级2)"和"数据处理任务(优先级3)",处理任务优先执行;
    • 静态创建:定义静态堆栈数组uint8_t ledTaskStack[512]和任务控制块StaticTask_t ledTaskTCB,调用xTaskCreateStatic()创建LED闪烁任务。

3. 队列操作

  • 操作流程
    1. 创建队列(指定长度、数据项大小);
    2. 任务/中断发送数据(可设阻塞时间);
    3. 任务接收数据(可设阻塞时间);
    4. 按需删除队列。
  • 核心API
    • 动态创建:xQueueCreate();
    • 静态创建:xQueueCreateStatic();
    • 收发API:xQueueSend()/xQueueReceive()、xQueueSendFromISR()、vQueueDelete()。
  • 关键注意事项
    1. 阻塞时间单位为系统Tick(如1ms/Tick时,100即100ms);portMAX_DELAY表示永久等待(直到事件触发),需注意:中断中阻塞时间必须设为0;
    2. 大数据传递建议用指针(保证内存有效);
    3. 中断中发送数据阻塞时间需设为0。
  • 常见坑点排查
    1. 队列接收不到数据→检查发送方阻塞时间、数据类型是否匹配、队列是否创建成功;
    2. 中断中发送失败→检查是否使用FromISR API、阻塞时间是否设为0;
    3. 队列满导致数据丢失→合理配置队列长度、设置发送阻塞时间。
  • 示例:采集任务将温湿度结构体通过队列发送给处理任务,采集端阻塞10ms,处理端永久等待。

4. 信号量与互斥锁操作

  • 操作流程
    1. 创建对象(二值/计数信号量、互斥锁、递归互斥锁);
    2. 任务获取对象(可设阻塞时间);
    3. 任务释放对象;
    4. 按需删除对象。
  • 核心API
    • 动态创建:xSemaphoreCreateBinary()/CreateCounting()/CreateMutex();
    • 静态创建:xSemaphoreCreateMutexStatic()/xSemaphoreCreateBinaryStatic();
    • 操作API:xSemaphoreTake()/Give()、xSemaphoreTakeRecursive()/GiveRecursive()、vSemaphoreDelete()。
  • 关键注意事项
    1. 互斥锁不可在中断中使用,信号量可通过FromISR释放;
    2. 优先级继承仅适用于互斥锁:低优先级任务持有互斥锁时,高优先级任务请求该锁会临时提升低优先级任务的优先级,避免中优先级任务抢占导致高优先级任务长期阻塞;多级反转需优先级天花板机制;
    3. 避免死锁:固定资源获取顺序、设置阻塞时间。
  • 常见坑点排查
    1. 死锁→检查资源获取顺序是否混乱、是否未设置阻塞超时;
    2. 优先级反转未解决→确认使用互斥锁而非普通二值信号量;
    3. 信号量释放失败→检查是否为当前任务持有(互斥锁/递归互斥锁)。
  • 示例:多任务访问串口,通过二值信号量实现独占访问。

5. 中断与FreeRTOS交互

  • 操作流程
    1. 配置中断源,设置中断优先级(低于configMAX_SYSCALL_INTERRUPT_PRIORITY);
    2. 编写ISR,通过中断安全API与任务交互;
    3. 任务层处理中断事件;
    4. 快速退出ISR,不阻塞。
  • 核心API
    • xQueueSendFromISR()/xSemaphoreGiveFromISR():中断中发送数据/释放信号量;
    • portYIELD_FROM_ISR():中断中触发任务切换;
    • taskENTER_CRITICAL_FROM_ISR():中断级临界区保护。
  • 关键注意事项
    1. ISR中禁止调用阻塞API;
    2. 高优先级中断无法使用FreeRTOS API;
    3. ISR逻辑需极简,复杂处理放任务中。
  • 常见坑点排查
    1. ISR中API调用崩溃→检查中断优先级是否高于configMAX_SYSCALL_INTERRUPT_PRIORITY;
    2. 中断事件未触发任务→检查portYIELD_FROM_ISR()是否调用、任务阻塞时间是否合理;
    3. 临界区执行时间过长→简化ISR内逻辑,仅保留事件上报。
  • 示例:STM32F103按键中断触发后,ISR释放二值信号量,任务获取后切换LED状态。

6. 软件定时器操作

  • 操作流程
    1. 启用configUSE_TIMERS,初始化定时器服务任务;
    2. 创建定时器(指定周期、触发模式、回调函数);
    3. 启动/停止/重置定时器;
    4. 按需删除定时器。
  • 核心API
    • xTimerCreate():创建定时器;
    • xTimerStart()/Stop()/Reset():启动/停止/重置;
    • vTimerDelete():删除。
  • 关键注意事项
    1. 回调函数运行在服务任务中,不可调用阻塞API;
    2. 服务任务优先级建议设为中等(高于普通业务、低于紧急任务),避免抢占核心业务;
    3. 回调函数执行时间需极短。
  • 常见坑点排查
    1. 定时器不触发→检查configUSE_TIMERS是否启用、服务任务是否有足够堆栈;
    2. 回调函数卡死→检查是否调用了阻塞API(如vTaskDelay());
    3. 定时精度低→提高Tick频率或改用硬件定时器(高精度场景)。
  • 示例:500ms周期定时器翻转LED,单次定时器上报初始化完成事件。

7. FreeRTOS内存管理配置

  • 操作流程
    1. 选择内存方案(推荐heap_4,适配90%场景);
    2. 配置堆大小(configTOTAL_HEAP_SIZE),基于芯片RAM总量预留20%余量;
    3. 初始化内存堆(vPortDefineHeapRegions()仅heap_5需用);
    4. 任务/对象创建时自动分配内存,按需释放(仅heap_2/4/5支持)。
  • 核心API
    • pvPortMalloc()/vPortFree():通用内存分配/释放;
    • xPortGetFreeHeapSize():查看剩余堆内存(调试必备);
    • vPortDefineHeapRegions():heap_5配置非连续内存。
  • 关键注意事项
    1. heap_1/2/4/5是FreeRTOS内置,heap_3依赖编译器malloc;
    2. 堆大小不足会导致xTaskCreate()返回pdFAIL,需用xPortGetFreeHeapSize()排查;
    3. 避免频繁分配/释放(heap_2易产生碎片,heap_4可缓解)。
  • 常见坑点排查
    1. 内存分配失败→检查configTOTAL_HEAP_SIZE是否足够、内存方案是否匹配释放需求;
    2. 内存碎片过多→改用heap_4、减少频繁动态创建/删除、核心对象用静态创建;
    3. heap_5使用异常→检查vPortDefineHeapRegions()配置的内存块是否合法。
  • 示例:STM32F103(64KB RAM)配置heap_4,堆大小设为32KB,创建任务后用xPortGetFreeHeapSize()监控剩余内存,避免溢出。

8. 任务通知操作

  • 操作流程
    1. 创建目标任务(需保留任务句柄);
    2. 配置通知模式(覆盖/递增/存储等);
    3. 发送通知:任务/中断向目标任务发送通知;
    4. 接收通知:目标任务阻塞等待通知,处理后清除通知值。
  • 核心API
    • 信号量模式发送:xTaskNotifyGive();
    • 通用模式发送:xTaskNotify();
    • 中断安全发送:xTaskNotifyFromISR();
    • 接收通知:xTaskNotifyWait()。
  • 关键注意事项
    1. 每个任务仅对应一个32位通知值,重复发送会覆盖/递增(依模式而定);
    2. 不支持多任务向同一任务发送"不同类型"通知(需通过通知值位拆分实现);
    3. 接收通知时阻塞时间建议设为合理值,避免永久阻塞。
  • 常见坑点排查
    1. 任务接收不到通知→检查目标任务句柄是否正确、通知模式是否匹配;
    2. 通知值异常→检查发送端是否重复发送导致覆盖;
    3. 中断发送无响应→检查是否调用portYIELD_FROM_ISR()触发任务切换。
  • 示例:STM32F103按键中断触发后,ISR通过xTaskNotifyFromISR()向LED任务发送通知,LED任务调用xTaskNotifyWait()阻塞等待,收到通知后切换LED亮灭状态。

常见问题

一、概念理解类

1. 什么是RTOS?与裸机开发的核心区别是什么?
  • :RTOS是嵌入式实时操作系统,核心能力是按优先级/时间约束调度任务,保证实时响应。与裸机的核心区别:裸机是单线程轮询/中断处理,代码耦合度高;RTOS是多任务并发,调度器自动管理任务,任务解耦,可保证高优先级任务实时响应。
  • 延伸:简单外设控制可用裸机,多任务/高实时性场景必须用RTOS;FreeRTOS仅占几KB RAM/ROM,适配多数嵌入式芯片。
2. FreeRTOS中任务的四种状态是什么?状态之间如何切换?
  • :就绪态、运行态、阻塞态、挂起态。切换逻辑:就绪→运行(调度器选择)、运行→就绪(高优先级抢占)、运行→阻塞(等待事件)、阻塞→就绪(事件发生)、任意→挂起(vTaskSuspend())、挂起→就绪(vTaskResume())。
  • 延伸:阻塞态有超时时间,挂起态需主动恢复;空闲任务始终处于就绪态。
3. 什么是临界区?FreeRTOS中如何保护临界区?
  • :临界区是不可被中断/调度的代码段,用于保护共享资源。FreeRTOS分两种保护方式:任务级(taskENTER_CRITICAL(),关调度)、中断级(taskENTER_CRITICAL_FROM_ISR(),关中断)。
  • 延伸:临界区执行时间需最短,否则降低系统实时性。

二、实操逻辑类

1. FreeRTOS支持哪些任务调度策略?各自的适用场景是什么?
  • :①抢占式调度:高优先级立即抢占低优先级,适用于紧急任务(报警、故障处理);②协作式调度:任务主动释放CPU,适用于低实时性场景(数据统计);③时间片调度:同优先级轮流执行,适用于同优先级多任务公平执行(多传感器采集)。
  • 延伸:FreeRTOS默认开启抢占式+时间片,协作式极少单独使用。
2. FreeRTOS中任务堆栈的作用是什么?如何合理配置任务堆栈大小?
  • :堆栈作用:保存任务上下文、存储局部变量/函数调用栈、中断嵌套临时栈。配置方法:①按局部变量、函数调用深度、中断嵌套估算;②启用堆栈溢出检测,调试观察使用量;③经验值:简单任务128-256字节,复杂任务512-1024字节。
  • 延伸:堆栈过大浪费内存,过小导致溢出;可通过map文件+调试工具优化。
3. FreeRTOS的中断安全API和普通API有什么区别?使用时需注意什么?
  • :区别:①命名:中断安全API后缀FromISR;②实现:中断安全API禁用调度、不阻塞,普通API可阻塞。注意事项:①中断中必须用FromISR API;②阻塞时间设为0;③高优先级中断无法使用FreeRTOS API。
  • 延伸:中断中调用API后,可通过portYIELD_FROM_ISR()触发任务切换。
4. 软件定时器的工作原理是什么?使用时的核心注意事项是什么?
  • :原理:基于系统Tick时钟,由定时器服务任务管理,到期后在服务任务中执行回调函数。注意事项:①回调函数不可调用阻塞API;②服务任务优先级合理配置(中等优先级为宜);③回调函数执行时间极短。
  • 延伸:软件定时器无硬件依赖,高精度定时需用硬件定时器+中断。
5. 任务通知和队列的核心区别是什么?各自的适用场景是什么?
  • :区别:①资源占用:任务通知无额外内核对象,队列需独立创建;②效率:任务通知比队列更高效;③功能:队列支持多任务收发/大数据传递,任务通知仅单任务接收/小数据量。场景:任务通知(轻量事件触发、单任务小数据传递);队列(多任务大数据通信)。
  • 延伸:资源受限场景优先用任务通知,复杂多任务通信用队列。
6. 为什么中断中不能调用阻塞API?
  • :FreeRTOS的阻塞API(如xQueueReceive、xSemaphoreTake)会触发任务切换,但中断上下文(ISR)无任务栈,无法保存/恢复上下文;且中断优先级高于所有任务,阻塞会导致系统卡死。

三、工程问题类

1. 队列和信号量的核心区别是什么?请分别举例说明应用场景
  • :区别:①队列用于数据传递,信号量用于同步/互斥;②队列有数据缓冲区,信号量无数据;③队列无所有权,信号量(互斥锁)有所有权。场景:队列(传感器数据传递)、信号量(串口独占访问)。
  • 延伸:信号量可看作"长度1、数据大小0的特殊队列"。
2. 如何避免FreeRTOS中的死锁问题?
  • :死锁是多任务互相等待资源导致无法执行。避免方法:①固定资源获取顺序;②设置阻塞超时时间;③减少互斥锁嵌套;④资源独占时长最小化。
  • 延伸:可通过调试工具监控任务阻塞状态,定位死锁原因。
3. 事件组和队列的应用场景有何不同?
  • :事件组管理"多个事件的触发状态",适合"只关心事件是否发生"的场景(等待多传感器就绪);队列传递"具体数据",适合"需要传递信息"的场景(串口数据传递)。
  • 延伸:事件组是无数据的同步机制,队列是有数据的通信机制。

四、内核原理类

1. 什么是优先级继承?FreeRTOS的互斥锁为什么需要支持优先级继承?
  • :优先级继承:低优先级任务持有互斥锁时,高优先级任务请求该锁,低优先级任务优先级临时提升到高优先级,直到释放锁。互斥锁需要优先级继承是为了解决优先级反转问题(高优先级等待低优先级,中优先级抢占低优先级,导致高优先级迟迟无法执行)。
  • 延伸:优先级继承仅解决两级反转,多级反转需优先级天花板机制。
  • 案例:①创建高优先级任务A、中优先级任务B、低优先级任务C;②C持有互斥锁,A请求该锁进入阻塞;③B抢占C执行,导致A迟迟无法运行(优先级反转);④启用互斥锁优先级继承后,C的优先级临时提升到A的级别,B无法抢占,C执行完释放锁,A立即执行,解决反转。


图6 优先级继承实操案例示意图

2. FreeRTOS内核的核心组件有哪些?各自的作用是什么?
  • :①任务调度器:选择高优先级就绪任务执行,负责上下文切换;②内核对象管理:管理队列、信号量等同步通信对象;③时钟管理:实现Tick时钟、延时、定时器;④内存管理:为任务/对象分配释放内存。
  • 延伸:内核可裁剪,内存管理有5种方案,可按需选择(heap_4适配绝大多数场景)。

总结

FreeRTOS学习核心逻辑:先通过概念速查掌握基础,再按通用实操流程落地,最后用常见问题巩固知识点。核心操作逻辑跨芯片通用,建议结合任意适配芯片实操,聚焦"调度、同步、通信"三大核心,即可快速上手FreeRTOS。

推荐工具:

  1. FreeRTOS官方文档:https://www.freertos.org/
  2. STM32CubeIDE:https://www.st.com/zh/development-tools/stm32cubeide.html
  3. 韦东山FreeRTOS文档:https://rtos.100ask.net/zh/FreeRTOS/DShanMCU-F103/
相关推荐
我的xiaodoujiao3 小时前
使用 Python 语言 从 0 到 1 搭建完整 Web UI自动化测试学习系列 45--生成项目需要的requirements.txt依赖文件
python·学习·测试工具·pytest
BlackWolfSky3 小时前
鸿蒙中级课程笔记8—Native适配开发
笔记·华为·harmonyos
AI视觉网奇3 小时前
ue 模拟说话
笔记·学习·ue5
好奇龙猫3 小时前
【人工智能学习-AI入试相关题目练习-第十五次】
人工智能·学习
晚霞的不甘3 小时前
Flutter for OpenHarmony全面升级「今日运势」 应用的视觉与交互革新
前端·学习·flutter·前端框架·交互
孞㐑¥3 小时前
算法—链表
开发语言·c++·经验分享·笔记·算法
BlackWolfSky3 小时前
鸿蒙中级课程笔记7—给应用添加通知
笔记·华为·harmonyos
学嵌入式的小杨同学3 小时前
【Linux 封神之路】文件操作 + 时间编程实战:从缓冲区到时间格式化全解析
linux·c语言·开发语言·前端·数据库·算法·ux
EverydayJoy^v^3 小时前
RH134学习进程——十一.管理网络安全
学习·安全·web安全