【FreeRTOS】创建任务_使用任务参数

news2024/11/26 2:26:50

在这里插入图片描述

参考《FreeRTOS入门与工程实践(基于DshanMCU-103).pdf》


文章目录

  • 前言
  • 编写任务函数
  • 创建任务
    • 任务
    • 保护措施
    • 写了个bug
    • 疑问
    • 遗留问题
    • 效果
    • freertos.c
  • 学习链接

前言

配套源码:06_create_task_use_params

我们创建3个任务,使用同一个函数,但是在LCD上打印不一样的信息。

3个任务使用同一个函数,但是他们运行的栈不一样,局部变量是不同的版本,不同的实体~


本次要完成的任务效果,在OLED上显示……如下图
在这里插入图片描述


编写任务函数

我们要在屏幕的(x,y)坐标处打印任务的名称,把这些写在一个函数的形参里,使用结构体来传递

根据描述定义这个结构体

struct TaskPrintInfo{
    uint8_t x;      //定义坐标x
    uint8_t y;      //定义坐标y
    char name[16];  //定义要打印输出的内容,最多显示16个字符
};

假设先打印Task1,这是5个字符,返回值是5,拿到这个返回值,并且在这个返回值的地方开始打印,打印一个冒号
然后再冒号的下一个地方打印计数值count
在这里插入图片描述
编写任务函数

void LCDPrintfTask(void *params)
{
    //将传入的参数,转换成 struct TaskPrintInfo 这个结构体
    struct TaskPrintInfo *pInfo = params;
    uint32_t count = 0; //定义一个计数值
    uint8_t length;     //长度
    
    while(1)
    {
        /* 打印信息 */
        
        length  = LCD_PrintString(pInfo->x, pInfo->y, pInfo->name); //在(x,y)处打印name里的内容,返回打印了多少个字符
        length += LCD_PrintString(length, pInfo->y, ":");           //从返回的那个长度开始打印一个冒号
        LCD_PrintSignedVal(length, pInfo->y, count++);              //在冒号的下一个位置开始打印计数值count
    }
}
  • 将传入的参数,转换成 struct TaskPrintInfo 这个结构体
  • 在(x,y)处打印name里的内容,返回打印了多少个字符
  • 从返回的那个长度开始打印一个冒号
  • 在冒号的下一个位置开始打印计数值count,并且count++

创建任务

先编写三个全局变量,用来传递参数

static struct TaskPrintInfo g_Task1Info = {0, 0, "Task1"};  // (0,0),Task1
static struct TaskPrintInfo g_Task2Info = {0, 3, "Task2"};  // (0,3),Task2
static struct TaskPrintInfo g_Task3Info = {0, 6, "Task3"};  // (0,6),Task3

将 g_Task1Info结构体 传给 LCDPrintfTask这个任务,那怎么传递呢?

  • 在创建任务的时候就进行参数传递,指定这个任务需要什么参数!!!

任务

    xTaskCreate(                //加返回值是 判断任务有没有创建成功
            LCDPrintfTask,      //孤勇者的函数
            "Task1",            //声音任务
            128,                //栈大小
            &g_Task1Info,       //传入的参数 g_Task1Info
            osPriorityNormal,   //优先级默认
            NULL                //任务句柄 无
            );
    xTaskCreate(                //加返回值是 判断任务有没有创建成功
            LCDPrintfTask,      //孤勇者的函数
            "Task2",            //声音任务
            128,                //栈大小
            &g_Task2Info,       //传入的参数 g_Task2Info
            osPriorityNormal,   //优先级默认
            NULL                //任务句柄 无
            );
    xTaskCreate(                //加返回值是 判断任务有没有创建成功
            LCDPrintfTask,      //孤勇者的函数
            "Task2",            //声音任务
            128,                //栈大小
            &g_Task3Info,       //传入的参数 g_Task3Info
            osPriorityNormal,   //优先级默认
            NULL                //任务句柄 无
            );

任务是轮流运行的,有可能LCD_PrintString运行时间比较长,LCD_PrintString没执行完成,又切换任务2,又切换任务3

在这里插入图片描述在这里插入图片描述
OLED的底层函数都是IIC,如果IIC被打断,那显示就不正常,所以我们需要加一些保护措施!

在这里插入图片描述


保护措施

加入全局变量保护一下,先定义这个变量g_LCDCanUse,默认是1,表示能使用LCD,0就不能使用了

static int g_LCDCanUse = 1; //默认=1 能使用LCD

在任务的函数里添加这个变量

void LCDPrintfTask(void *params)
{
    //将传入的参数,转换成 struct TaskPrintInfo 这个结构体
    struct TaskPrintInfo *pInfo = params;
    uint32_t count = 0; //定义一个计数值
    uint8_t length;     //长度
    
    while(1)
    {
        /* 打印信息 */
        if (g_LCDCanUse)        //g_LCDCanUse == 1 能使用LCD
        {
            g_LCDCanUse = 0;    // 在这里禁止其他任务使用LCD
            length  = LCD_PrintString(pInfo->x, pInfo->y, pInfo->name); //在(x,y)处打印name里的内容,返回打印了多少个字符
            length += LCD_PrintString(length, pInfo->y, ":");           //从返回的那个长度开始打印一个冒号
            LCD_PrintSignedVal(length, pInfo->y, count++);              //在冒号的下一个位置开始打印计数值count,并且count++
            g_LCDCanUse = 1;    //用完再恢复成1,表示可以继续使用LCD
        }
    }
}

这里没有用到同步互斥,只用到一个全局变量,也许是可行的!



写了个bug

烧录程序,这里OLED没有显示

在这里插入图片描述

原因是没有初始化OLED
在这里插入图片描述

在初始化MX_FREERTOS_Init里添加如下代码

void MX_FREERTOS_Init(void) {
  /* USER CODE BEGIN Init */
    LCD_Init();
    LCD_Clear();

  /* USER CODE END Init */

  /* USER CODE BEGIN RTOS_MUTEX */
  /* add mutexes, ... */
  /* USER CODE END RTOS_MUTEX */

加入初始化代码,烧录运行,又又又有bug,只有一个任务在运行,韦老师是只有任务3在运行,我的现象是只有任务1在运行
???在这里插入图片描述

修改的办法:在LCDPrintfTask任务函数里加入Delay即可,代码如下

void LCDPrintfTask(void *params)
{
    //将传入的参数,转换成 struct TaskPrintInfo 这个结构体
    struct TaskPrintInfo *pInfo = params;
    uint32_t count = 0; //定义一个计数值
    uint8_t length;     //长度
    
    LCD_Init();
	LCD_Clear();	// 清屏
    
    while(1)
    {
        /* 打印信息 */
        if (g_LCDCanUse)        //g_LCDCanUse == 1 能使用LCD
        {
            g_LCDCanUse = 0;    // 在这里禁止其他任务使用LCD
            length  = LCD_PrintString(pInfo->x, pInfo->y, pInfo->name); //在(x,y)处打印name里的内容,返回打印了多少个字符
            length += LCD_PrintString(length, pInfo->y, ":");           //从返回的那个长度开始打印一个冒号
            LCD_PrintSignedVal(length, pInfo->y, count++);              //在冒号的下一个位置开始打印计数值count,并且count++
            g_LCDCanUse = 1;    //用完再恢复成1,表示可以继续使用LCD
        }
        mdelay(500);
    }
}

现象:
在这里插入图片描述

这样我们就使用了同一个函数,创建了三个任务!三个任务里的count的值是局部变量,他们的值并不一定一样!


疑问

为什么不加延时mdelay函数,其他任务不能运行了呢?

如果不加延时函数
在这里插入图片描述

三个任务的结构都是打印函数,在Task3没打印完的时候,就进行任务切换,切换到Task1里,读取这个g_LCDCanUse变量值是0,不能进行打印!所以不能打印信息了,继续切换到Task2,也不能打印,再次切换回Task3的时候,能从上次切换出去的地方继续执行打印函数,执行完后g_LCDCanUse变量赋1,如果在这里没有瞬间切换出去,那么就继续执行这个任务了,继续循环,马上把g_LCDCanUse变量清零,执行打印函数,切换到其他任务,还是不能执行~~如此反复执行非常耗时的打印函数,所以就有bug

我们加上delay之后,在很长一段时间内这个g_LCDCanUse变量都是1,其他任务都是可以执行打印函数的,这样就比较简单的解决了这个问题。

在这里插入图片描述


遗留问题

  • 提问:==如何互斥地访问LCD?==使用全局变量,大概率可以,但是不是万无一失。(全局变量不可靠)
  • 提问:为什么先创建任务1,再创建任务2,再创建任务3,但是执行的顺序却不是123 ???为何是后面创建的task3先运行?

在这里插入图片描述

效果

在这里插入图片描述

freertos.c

/* USER CODE BEGIN Header */
#include "driver_led.h"
#include "driver_lcd.h"
#include "driver_mpu6050.h"
#include "driver_timer.h"
#include "driver_ds18b20.h"
#include "driver_dht11.h"
#include "driver_active_buzzer.h"
#include "driver_passive_buzzer.h"
#include "driver_color_led.h"
#include "driver_ir_receiver.h"
#include "driver_ir_sender.h"
#include "driver_light_sensor.h"
#include "driver_ir_obstacle.h"
#include "driver_ultrasonic_sr04.h"
#include "driver_spiflash_w25q64.h"
#include "driver_rotary_encoder.h"
#include "driver_motor.h"
#include "driver_key.h"
#include "driver_uart.h"
#include "music.h"

/**
  ******************************************************************************
  * File Name          : freertos.c
  * Description        : Code for freertos applications
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2023 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/
#include "FreeRTOS.h"
#include "task.h"
#include "main.h"
#include "cmsis_os.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN Variables */

BaseType_t ret; // long
static TaskHandle_t xSoundTaskHandle;           // void *  在全局变量里记录句柄

static StackType_t g_pucStackOfLightTask[128];  // 变量前缀的意思是 全局变量g 指针p uint8_t类型uc的StackOfLightTask 光任务的栈
StaticTask_t g_TCBofLightTask;                  // 光任务的TCB
static TaskHandle_t xLightTaskHandle;           // void *  在全局变量里记录句柄

static StackType_t g_pucStackOfColorTask[128];  // 变量前缀的意思是 全局变量g 指针p uint8_t类型uc的StackOfLightTask 色任务的栈
StaticTask_t g_TCBofColorTask;                  // 色任务的TCB
static TaskHandle_t xColorTaskHandle;           // void *  在全局变量里记录句柄

/* USER CODE END Variables */
/* Definitions for defaultTask */
osThreadId_t defaultTaskHandle;
const osThreadAttr_t defaultTask_attributes = {
  .name = "defaultTask",
  .stack_size = 128 * 4,
  .priority = (osPriority_t) osPriorityNormal,
};

/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN FunctionPrototypes */

struct TaskPrintInfo{
    uint8_t x;      //定义坐标x
    uint8_t y;      //定义坐标y
    char name[16];  //定义要打印输出的内容,最多显示16个字符
};

static struct TaskPrintInfo g_Task1Info = {0, 0, "Task1"};  // (0,0),Task1
static struct TaskPrintInfo g_Task2Info = {0, 3, "Task2"};  // (0,3),Task2
static struct TaskPrintInfo g_Task3Info = {0, 6, "Task3"};  // (0,6),Task3

static int g_LCDCanUse = 1; //默认=1 能使用LCD

void LCDPrintfTask(void *params)
{
    //将传入的参数,转换成 struct TaskPrintInfo 这个结构体
    struct TaskPrintInfo *pInfo = params;
    uint32_t count = 0; //定义一个计数值
    uint8_t length;     //长度
    
    LCD_Init();
	LCD_Clear();	// 清屏
    
    while(1)
    {
        /* 打印信息 */
        if (g_LCDCanUse)        //g_LCDCanUse == 1 能使用LCD
        {
            g_LCDCanUse = 0;    // 在这里禁止其他任务使用LCD
            length  = LCD_PrintString(pInfo->x, pInfo->y, pInfo->name); //在(x,y)处打印name里的内容,返回打印了多少个字符
            length += LCD_PrintString(length, pInfo->y, ":");           //从返回的那个长度开始打印一个冒号
            LCD_PrintSignedVal(length, pInfo->y, count++);              //在冒号的下一个位置开始打印计数值count,并且count++
            g_LCDCanUse = 1;    //用完再恢复成1,表示可以继续使用LCD
        }
        mdelay(500);
    }
}

/* USER CODE END FunctionPrototypes */

void StartDefaultTask(void *argument);

void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */

/**
  * @brief  FreeRTOS initialization
  * @param  None
  * @retval None
  */
void MX_FREERTOS_Init(void) {
  /* USER CODE BEGIN Init */
    LCD_Init();
    LCD_Clear();

  /* USER CODE END Init */

  /* USER CODE BEGIN RTOS_MUTEX */
  /* add mutexes, ... */
  /* USER CODE END RTOS_MUTEX */

  /* USER CODE BEGIN RTOS_SEMAPHORES */
  /* add semaphores, ... */
  /* USER CODE END RTOS_SEMAPHORES */

  /* USER CODE BEGIN RTOS_TIMERS */
  /* start timers, add new ones, ... */
  /* USER CODE END RTOS_TIMERS */

  /* USER CODE BEGIN RTOS_QUEUES */
  /* add queues, ... */
  /* USER CODE END RTOS_QUEUES */

  /* Create the thread(s) */
  /* creation of defaultTask */
  
//  defaultTaskHandle = osThreadNew(StartDefaultTask, NULL, &defaultTask_attributes);

  /* USER CODE BEGIN RTOS_THREADS */
  /* add threads, ... */
  
  
//  /* 创建任务:声 */
//  // 先创建一个动态分配内存的任务
//  ret = xTaskCreate(                //加返回值是 判断任务有没有创建成功
//            PlayMusic,          //孤勇者的函数
//            "SoundTask",        //声音任务
//            128,                //栈大小
//            NULL,               //无传入的参数
//            osPriorityNormal,   //优先级默认
//            & xSoundTaskHandle  //任务句柄
//            );

//  
//  /* 创建任务:光 */ 
//  // 创建一个静态分配内存的任务
//  xLightTaskHandle = xTaskCreateStatic(
//            Led_Test,           //LED测试函数,PC13以500ms间隔亮灭一次
//            "LightTask",        //光任务
//            128,                //栈大小,这里提供了栈的大小(长度)
//            NULL,               //无传入的参数
//            osPriorityNormal,   //优先级默认
//            g_pucStackOfLightTask,  // 静态分配的栈,一个buffer,这里只提供了首地址,长度就是栈的大小,最开始栈的类型不对,栈的类型uint32_t
//            &g_TCBofLightTask       // 取址TCB
//  );
//  


//  /* 创建任务:色 */ 
//  xColorTaskHandle = xTaskCreateStatic(
//            ColorLED_Test,           //LED测试函数,PC13以500ms间隔亮灭一次
//            "ColorTask",        //光任务
//            128,                //栈大小,这里提供了栈的大小(长度)
//            NULL,               //无传入的参数
//            osPriorityNormal,   //优先级默认
//            g_pucStackOfColorTask,  // 静态分配的栈,一个buffer,这里只提供了首地址,长度就是栈的大小
//            &g_TCBofColorTask       // 取址TCB
//  );


    xTaskCreate(                //加返回值是 判断任务有没有创建成功
            LCDPrintfTask,      //孤勇者的函数
            "Task1",            //声音任务
            128,                //栈大小
            &g_Task1Info,       //传入的参数 g_Task1Info
            osPriorityNormal,   //优先级默认
            NULL                //任务句柄 无
            );
    xTaskCreate(                //加返回值是 判断任务有没有创建成功
            LCDPrintfTask,      //孤勇者的函数
            "Task2",            //声音任务
            128,                //栈大小
            &g_Task2Info,       //传入的参数 g_Task2Info
            osPriorityNormal,   //优先级默认
            NULL                //任务句柄 无
            );
    xTaskCreate(                //加返回值是 判断任务有没有创建成功
            LCDPrintfTask,      //孤勇者的函数
            "Task2",            //声音任务
            128,                //栈大小
            &g_Task3Info,       //传入的参数 g_Task3Info
            osPriorityNormal,   //优先级默认
            NULL                //任务句柄 无
            );
  
  /* USER CODE END RTOS_THREADS */

  /* USER CODE BEGIN RTOS_EVENTS */
  /* add events, ... */
  /* USER CODE END RTOS_EVENTS */

}

/* USER CODE BEGIN Header_StartDefaultTask */

/**
  * @brief  Function implementing the defaultTask thread.
  * @param  argument: Not used
  * @retval None
  */
/* USER CODE END Header_StartDefaultTask */
void StartDefaultTask(void *argument)
{
  /* USER CODE BEGIN StartDefaultTask */
  /* Infinite loop */
  LCD_Init();
  LCD_Clear();
  
  for(;;)
  {
    //Led_Test();
    //LCD_Test();
	//MPU6050_Test(); 
	//DS18B20_Test();
	//DHT11_Test();
	//ActiveBuzzer_Test();
	//PassiveBuzzer_Test();
	//ColorLED_Test();
	IRReceiver_Test();  //影
	//IRSender_Test();
	//LightSensor_Test();
	//IRObstacle_Test();
	//SR04_Test();
	//W25Q64_Test();
	//RotaryEncoder_Test();
	//Motor_Test();
	//Key_Test();
	//UART_Test();
  }
  /* USER CODE END StartDefaultTask */
}

/* Private application code --------------------------------------------------*/
/* USER CODE BEGIN Application */

/* USER CODE END Application */


学习链接

学习视频:【FreeRTOS入门与工程实践 --由浅入深带你学习FreeRTOS(FreeRTOS教程 基于STM32,以实际项目为导向)】 【精准空降到 21:00】 https://www.bilibili.com/video/BV1Jw411i7Fz/?p=18&share_source=copy_web&vd_source=8af85e60c2df9af1f0fd23935753a933&t=1260

传送门


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1849236.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【昇思初学入门】第三天打卡

数据集Dataset 心得体会 昇思提供了丰富的数据集,文本、图像、音频等都有内置MindSpore的Pipeline设计和并行处理能力使得数据预处理更加高效可通过GeneratorDataset接口实现自定义方式的数据集加载可迭代的数据集,可以通过迭代的方式逐步获取数据样本…

【进阶篇-Day4:使用JAVA编写石头迷阵游戏】

目录 1、绘制界面2、打乱石头方块3、移动业务4、游戏判定胜利5、统计步数6、重新游戏7、完整代码: 1、绘制界面 上述思路是:使用一个二维数组存放图片的编号,然后在后持遍历即可获取对应的图片。 代码如下: package com.itheima.s…

异步FIFO

目录 描述 输入描述: 输出描述: 参考代码 描述 请根据题目中给出的双口RAM代码和接口描述,实现异步FIFO,要求FIFO位宽和深度参数化可配置。 电路的接口如下图所示。 双口RAM端口说明: 端口名 I/O 描述 wclk i…

centos中安装并设置vsftpd

vsftpd是一个可安装在linux上的ftp服务器软件。 一、安装 安装前保证服务器能上互联网。如果不能上网,看看能不能设法利用局域网代理上网。 sudo yum -y install vsftpd二、配置 1、修改配置文件 cd /etc/vsftpd #修改之前记得备份!!&am…

D触发器(D Flip-Flop)与D锁存器(D Latch)

1 基础概念 我们先来简单回顾一下D触发器(D flip-flop)和D锁存器(D latch)的概念,以及它们在数字电路中的作用。 1.1 D触发器(D Flip-Flop) D触发器是一种数字存储器件,它在时钟信号…

深入理解计算机系统 CSAPP 家庭作业6.46

理解题意:G是有向图g的邻接矩阵 G[j*dim i] G[j*dim i] || G[i*dim j]; 通过i和j遍历G中的所有元素,||运算将遍历到的元素对称起来. 下面我们来优化col_convert(int *G, int dim) : void col_convert(int N, int G[N][N], int bsize) {if(bsize < 0 || bsize > N…

Elasticsearch基础(一):阿里云Elasticsearch简介

文章目录 阿里云Elasticsearch简介 一、什么是阿里云Elasticsearch 1、开源Elasticsearch 2、阿里云Elasticsearch 3、阿里云Elasticsearch介绍 4、总结 二、 阿里云Elasticsearch组件 1、X-Pack&#xff08;商业版扩展包&#xff09; 2、 Beats&#xff08;数据采集中…

调试器接口是什么?

目录 一、调试器接口 1.1 什么是下载调试器&#xff1f; 1.2 JTAG标准/协议 1.3 SWD标准 一、调试器接口 1.1 什么是下载调试器&#xff1f; 简单来讲&#xff0c;它就是一种能把PC端发送的命令&#xff08;通过USB协议&#xff09;转换为MCU能理解的语言&#xff08;SWD协…

媒体邀约有啥要注意的

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 媒体宣传加速季&#xff0c;100万补贴享不停&#xff0c;一手媒体资源&#xff0c;全国100城线下落地执行。详情请联系胡老师。 媒体邀约是邀请媒体参与活动或报道的重要过程&#xff0c…

【Proteus仿真】【Arduino单片机】基于物联网新能源电动车检测系统设计

文章目录 一、功能简介二、软件设计三、实验现象联系作者 一、功能简介 本项目使用Proteus8仿真Arduino单片机控制器&#xff0c;使用LCD1602液晶显示模块、WIFI模块、蜂鸣器、LED按键、ADC、DS18B20温度传感器等。 主要功能&#xff1a; 系统运行后&#xff0c;LCD1602显示温…

外星人Alienware m15R7 原厂Windows11系统

装后恢复到您开箱的体验界面&#xff0c;包括所有原机所有驱动AWCC、Mydell、office、mcafee等所有预装软件。 最适合您电脑的系统&#xff0c;经厂家手调试最佳状态&#xff0c;性能与功耗直接拉满&#xff0c;体验最原汁原味的系统。 原厂系统下载网址&#xff1a;http://w…

JavaFX 下拉框

组合框允许用户选择几个选项之一。用户可以滚动到下拉列表。组合框可以是可编辑和不可编辑的。 创建组合框 以下代码将选项列表包装到ObservableList中&#xff0c;然后使用observable列表实例化ComboBox类。 ObservableList<String> options FXCollections.observab…

区块链媒体发布推广秘籍大揭秘-华媒舍

区块链技术迅猛发展&#xff0c;成为全球瞩目的热门领域。随之而来的是区块链媒体的兴起&#xff0c;成为传播和推广区块链知识、项目和应用的重要平台。本文将揭示区块链媒体发布推广的秘籍&#xff0c;为读者深入了解该领域提供详尽科普介绍。 一、什么是区块链媒体&#xff…

Docker:安装RediSearch全文搜索

1、简述 在本文中&#xff0c;我们将介绍如何使用Docker快速、简便地安装RediSearch&#xff0c;Redis的全文搜索模块。RediSearch提供了高效的全文搜索功能&#xff0c;通过Docker安装&#xff0c;可以轻松地在任何环境中部署和管理RediSearch。 官网地址&#xff1a;https:/…

18.cobra框架了解

目录 概述举例安装实践实践 概述 github cobra cobra 快速的实现一个命令行客户端&#xff0c;命令行解析工具。 cobra 中的主要概念 -Commands 表示执行运作-Args 执行参数-Flags 这些运作的标识符 举例 git clone 命令 git clone https://github.com/spf13/cobra.git -…

白嫖游戏指南,Epic喜加二:《Freshly Frosted》《Rumble Club》

前言 Epic喜加二&#xff1a;《Freshly Frosted》《Rumble Club》《Freshly Frosted》简介&#xff1a; 《Rumble Club》简介&#xff1a; 前言 接下来有时间会分享一些游戏相关可以白嫖的资源&#xff0c;包括游戏本体、游戏素材资源等等。 有需要的小伙伴可以关注这个专栏&…

文件批量改名利器:一键实现文件名中字母统一转为大写,让文件管理更高效有序!

在日常工作和生活中&#xff0c;我们经常会遇到需要批量重命名文件的情况。尤其是当文件名中包含字母时&#xff0c;如果希望将所有字母统一更改为大写&#xff0c;传统的逐个修改方式无疑会耗费大量时间。不过&#xff0c;有了高效的文件批量改名工具&#xff0c;这一难题将迎…

【C++】平衡二叉树(AVL树)的实现

目录 一、AVL树的概念二、AVL树的实现1、AVL树的定义2. 平衡二叉树的插入2.1 按照二叉排序树的方式插入并更新平衡因子2.2 AVL树的旋转2.2.1 新节点插入较高左子树的左侧&#xff08;LL平衡旋转&#xff09;2.2.2 新节点插入较高右子树的右侧&#xff08;RR平衡旋转&#xff09…