freertos——任务通知知识总结与任务通知模拟及信号量实验、消息邮箱实验、事件标志组实验

1.任务通知概念

任务通知:用来通知任务的,任务控制块中的结构体成员变量 ulNotifiedValue就是这个通知值,不需要另外创建一个结构体可以直接接受别人发过来的通知
在这里插入图片描述

2.任务通知的优势及劣势

任务通知的优势:
效率更高 :使用任务通知向任务发送事件或数据比使用队列、事件标志组或信号量快得多
使用内存更小:使用其他方法时都要先创建对应的结构体,使用任务通知时无需额外创建结构体

任务通知的劣势:
无法发送数据给ISR:ISR没有任务结构体,所以无法给ISR发送数据。但是ISR可以使用任务通知的功能,发数据给任务。
无法广播给多个任务:任务通知只能是被指定的一个任务接收并处理
无法缓存多个数据:任务通知是通过更新任务通知值来发送数据的,任务结构体中只有一个任务通知值,只能保持一个数据。
发送受阻不支持阻塞:发送方无法进入阻塞状态等待

3.任务结构体中任务通知值和通知状态

typedef  struct  tskTaskControlBlock 
{… …#if ( configUSE_TASK_NOTIFICATIONS  ==  1 )volatile  uint32_t    ulNotifiedValue [ configTASK_NOTIFICATION_ARRAY_ENTRIES ];volatile  uint8_t      ucNotifyState [ configTASK_NOTIFICATION_ARRAY_ENTRIES ];endif… …
} tskTCB;
#define  configTASK_NOTIFICATION_ARRAY_ENTRIES	1  	/* 定义任务通知数组的大小, 默认: 1

一个是 uint32_t 类型,用来表示通知值
一个是 uint8_t 类型,用来表示通知状态

4 任务通知状态

#define taskNOT_WAITING_NOTIFICATION ( ( uint8_t ) 0 ) /* 任务未等待通知 /
#define taskWAITING_NOTIFICATION ( ( uint8_t ) 1 ) /
任务在等待通知 /
#define taskNOTIFICATION_RECEIVED ( ( uint8_t ) 2 ) /
任务在等待接收 */
未等待通知:初始化状态
等待通知:接收方已经准备好了(调用了接收任务通知函数),等待发送方给个通知
等待接收:发送方已经发送出去(调用了发送任务通知函数),等待接收方接收

5.任务通知API函数

1)发送通知相关API函数
在这里插入图片描述
注意;发送通知API函数可以用于任务和中断服务函数中
BaseType_t xTaskGenericNotify( TaskHandle_t xTaskToNotify,
UBaseType_t uxIndexToNotify,
uint32_t ulValue,
eNotifyAction eAction,
uint32_t * pulPreviousNotificationValue)
在这里插入图片描述
2)接收任务通知相关API函数
在这里插入图片描述
1)#define ulTaskNotifyTake( xClearCountOnExit , xTicksToWait )
ulTaskGenericNotifyTake( ( tskDEFAULT_INDEX_TO_NOTIFY ),
( xClearCountOnExit ),
\ ( xTicksToWait ) )
形参: uxIndexToWaitOn 任务的指定通知(任务通知相关数组成员)
xClearCountOnExit 指定在成功接收通知后,将通知值清零或减 1,
pdTRUE:把通知值清零;
pdFALSE:把通知值减一
xTicksToWait 阻塞等待任务通知值的最大时间

返回值:0 接收失败
其他 接收成功,返回任务通知的通知值

2)#define xTaskNotifyWait( ulBitsToClearOnEntry, \
ulBitsToClearOnExit, \
pulNotificationValue, \
xTicksToWait)
xTaskGenericNotifyWait( tskDEFAULT_INDEX_TO_NOTIFY,
\ ( ulBitsToClearOnEntry ),
\ ( ulBitsToClearOnExit ),
\ ( pulNotificationValue ),
\ ( xTicksToWait ) )

形参: uxIndexToWaitOn 任务的指定通知(任务通知相关数组成员)
ulBitesToClearOnEntry 等待前清零指定任务通知值的比特位(旧值对应bit清0)
ulBitsToClearOnExit 成功等待后清零指定的任务通知值比特位(新值对应bit清0)
pulNotificationValue 用来取出通知值(如果不需要取出,可设为NULL)
xTicksToWait 阻塞等待任务通知值的最大时间

返回值:0 接收失败
其他 接收成功,返回任务通知的通知值

总结:
1)当任务通知用作于信号量时,使用函数获取信号量:ulTaskNotifyTake()
2)当任务通知用作于事件标志组或队列时,使用此函数来获取: xTaskNotifyWait()

6.任务通知的几种方式

typedef enum
{
eNoAction = 0, /* 无操作 /
eSetBits /
更新指定bit /
eIncrement /
通知值加一 /
eSetValueWithOverwrite /
覆写的方式更新通知值 /
eSetValueWithoutOverwrite /
不覆写通知值 */
} eNotifyAction;

7.任务通知模拟信号量实验

在这里插入图片描述
代码:

#include "freertos_demo.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
/*FreeRTOS*********************************************************************************************/
#include "FreeRTOS.h"
#include "task.h"/*1.FreeRTOS配置*//* 1.1 START_TASK 任务 配置* 包括: 任务句柄 任务优先级 堆栈大小 创建任务*/
#define START_TASK_PRIO 1                   /* 任务优先级 */
#define START_STK_SIZE  128                 /* 任务堆栈大小 */
TaskHandle_t            StartTask_Handler;  /* 任务句柄 */
void start_task(void *pvParameters);        /* 任务函数 *//* 1.2 TASK1 任务 配置* 包括: 任务句柄 任务优先级 堆栈大小 创建任务*/
#define TASK1_PRIO      2                   /* 任务优先级 */
#define TASK1_STK_SIZE  128                 /* 任务堆栈大小 */
TaskHandle_t            Task1Task_Handler;  /* 任务句柄 */
void task1(void *pvParameters);             /* 任务函数 *//* 1.3 TASK2 任务 配置* 包括: 任务句柄 任务优先级 堆栈大小 创建任务*/
#define TASK2_PRIO      3                   /* 任务优先级 */
#define TASK2_STK_SIZE  128                 /* 任务堆栈大小 */
TaskHandle_t            Task2Task_Handler;  /* 任务句柄 */
void task2(void *pvParameters);             /* 任务函数 *//*** 2 FreeRTOS例程入口函数* @param       无* @retval      无*/
void freertos_demo(void)
{xTaskCreate((TaskFunction_t )start_task,            /* 任务函数 */(const char*    )"start_task",          /* 任务名称 */(uint16_t       )START_STK_SIZE,        /* 任务堆栈大小 */(void*          )NULL,                  /* 传入给任务函数的参数 */(UBaseType_t    )START_TASK_PRIO,       /* 任务优先级 */(TaskHandle_t*  )&StartTask_Handler);   /* 任务句柄 */vTaskStartScheduler();
}/*** 3 start_task* @param       pvParameters : 传入参数(未用到)* @retval      无*/
void start_task(void *pvParameters)
{taskENTER_CRITICAL();           /* 进入临界区 *//* 创建任务1 */xTaskCreate((TaskFunction_t )task1,(const char*    )"task1",(uint16_t       )TASK1_STK_SIZE,(void*          )NULL,(UBaseType_t    )TASK1_PRIO,(TaskHandle_t*  )&Task1Task_Handler);/* 创建任务2 */xTaskCreate((TaskFunction_t )task2,(const char*    )"task2",(uint16_t       )TASK2_STK_SIZE,(void*          )NULL,(UBaseType_t    )TASK2_PRIO,(TaskHandle_t*  )&Task2Task_Handler);vTaskDelete(StartTask_Handler); /* 删除开始任务 */taskEXIT_CRITICAL();            /* 退出临界区 */
}/*** 3 task1发送任务通知值* @param       pvParameters : 传入参数(未用到)* @retval      无*/
void task1(void *pvParameters)
{uint8_t key = 0;while (1){key = key_scan(0);switch (key){case KEY0_PRES:                                         /* 发送任务通知 */{xTaskNotifyGive(Task2Task_Handler);printf("任务通知发送,模拟二值信号量释放!\r\n");break;}default:{break;}}vTaskDelay(10);}
}/*** 3 task2 接收任务通知值* @param       pvParameters : 传入参数(未用到)* @retval      无*/
void task2(void *pvParameters)
{uint32_t rev = 0;while (1){rev = ulTaskNotifyTake(pdTRUE,portMAX_DELAY);if(rev != 0){printf("接收任务通知成功,模拟获取二值信号量!\r\n");}}
}

8.任务通知模拟计数型信号量实验

void task2(void *pvParameters)
{uint32_t rev = 0;while (1){rev = ulTaskNotifyTake(pdTRUE,portMAX_DELAY);if(rev != 0){printf("rev:%d\r\n",rev);}vTaskDelay(1000);}
}

9.任务通知模拟事件标志组实验

在这里插入图片描述

#include "freertos_demo.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
/*FreeRTOS*********************************************************************************************/
#include "FreeRTOS.h"
#include "task.h"/******************************************************************************************************/
/*1.FreeRTOS配置*//* 1.1 START_TASK 任务 配置* 包括: 任务句柄 任务优先级 堆栈大小 创建任务*/
#define START_TASK_PRIO 1                   /* 任务优先级 */
#define START_STK_SIZE  128                 /* 任务堆栈大小 */
TaskHandle_t            StartTask_Handler;  /* 任务句柄 */
void start_task(void *pvParameters);        /* 任务函数 *//* 1.2 TASK1 任务 配置* 包括: 任务句柄 任务优先级 堆栈大小 创建任务*/
#define TASK1_PRIO      2                   /* 任务优先级 */
#define TASK1_STK_SIZE  128                 /* 任务堆栈大小 */
TaskHandle_t            Task1Task_Handler;  /* 任务句柄 */
void task1(void *pvParameters);             /* 任务函数 *//* 1.3 TASK2 任务 配置* 包括: 任务句柄 任务优先级 堆栈大小 创建任务*/
#define TASK2_PRIO      3                   /* 任务优先级 */
#define TASK2_STK_SIZE  128                 /* 任务堆栈大小 */
TaskHandle_t            Task2Task_Handler;  /* 任务句柄 */
void task2(void *pvParameters);             /* 任务函数 *///1.4 位0、位1宏定义
#define EVENTBIT_0 (1 << 0)
#define EVENTBIT_1 (1 << 1)/*** 2 FreeRTOS例程入口函数* @param       无* @retval      无*/
void freertos_demo(void)
{xTaskCreate((TaskFunction_t )start_task,            /* 任务函数 */(const char*    )"start_task",          /* 任务名称 */(uint16_t       )START_STK_SIZE,        /* 任务堆栈大小 */(void*          )NULL,                  /* 传入给任务函数的参数 */(UBaseType_t    )START_TASK_PRIO,       /* 任务优先级 */(TaskHandle_t*  )&StartTask_Handler);   /* 任务句柄 */vTaskStartScheduler();
}/*** 3 start_task* @param       pvParameters : 传入参数(未用到)* @retval      无*/
void start_task(void *pvParameters)
{taskENTER_CRITICAL();           /* 进入临界区 *//* 创建任务1 */xTaskCreate((TaskFunction_t )task1,(const char*    )"task1",(uint16_t       )TASK1_STK_SIZE,(void*          )NULL,(UBaseType_t    )TASK1_PRIO,(TaskHandle_t*  )&Task1Task_Handler);/* 创建任务2 */xTaskCreate((TaskFunction_t )task2,(const char*    )"task2",(uint16_t       )TASK2_STK_SIZE,(void*          )NULL,(UBaseType_t    )TASK2_PRIO,(TaskHandle_t*  )&Task2Task_Handler);vTaskDelete(StartTask_Handler); /* 删除开始任务 */taskEXIT_CRITICAL();            /* 退出临界区 */
}/*** 3 task1发送任务通知值* @param       pvParameters : 传入参数(未用到)* @retval      无*/
void task1(void *pvParameters)
{uint8_t key = 0;while (1){key = key_scan(0);switch (key){case KEY0_PRES:                                         /* 发送任务通知 */{printf("将bit0位置置1\r\n");xTaskNotify( Task2Task_Handler,EVENTBIT_0, eSetBits);break;}case KEY1_PRES:                                         /* 发送任务通知 */{printf("将bit1位置置1\r\n");xTaskNotify( Task2Task_Handler,EVENTBIT_1, eSetBits);break;}default:{break;}}vTaskDelay(10);}
}/*** 3 task2 接收任务通知值* @param       pvParameters : 传入参数(未用到)* @retval      无*/
void task2(void *pvParameters)
{uint32_t notify_val = 0,event_bit=0;while (1){xTaskNotifyWait( 0, 0xFFFFFFFF,&notify_val,portMAX_DELAY);if(notify_val & EVENTBIT_0){event_bit |= EVENTBIT_0;} if(notify_val & EVENTBIT_1){event_bit |= EVENTBIT_1;} if(event_bit ==( EVENTBIT_0 | EVENTBIT_1)){printf("任务通知模拟事件标志组接收成功\r\n");event_bit = 0;} }
}

10.任务通知模拟消息邮箱实验

在这里插入图片描述


#include "freertos_demo.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"#include "./BSP/LED/led.h"
/*FreeRTOS*********************************************************************************************/
#include "FreeRTOS.h"
#include "task.h"/******************************************************************************************************/
/*1.FreeRTOS配置*//* 1.1 START_TASK 任务 配置* 包括: 任务句柄 任务优先级 堆栈大小 创建任务*/
#define START_TASK_PRIO 1                   /* 任务优先级 */
#define START_STK_SIZE  128                 /* 任务堆栈大小 */
TaskHandle_t            StartTask_Handler;  /* 任务句柄 */
void start_task(void *pvParameters);        /* 任务函数 *//* 1.2 TASK1 任务 配置* 包括: 任务句柄 任务优先级 堆栈大小 创建任务*/
#define TASK1_PRIO      2                   /* 任务优先级 */
#define TASK1_STK_SIZE  128                 /* 任务堆栈大小 */
TaskHandle_t            Task1Task_Handler;  /* 任务句柄 */
void task1(void *pvParameters);             /* 任务函数 *//* 1.3 TASK2 任务 配置* 包括: 任务句柄 任务优先级 堆栈大小 创建任务*/
#define TASK2_PRIO      3                   /* 任务优先级 */
#define TASK2_STK_SIZE  128                 /* 任务堆栈大小 */
TaskHandle_t            Task2Task_Handler;  /* 任务句柄 */
void task2(void *pvParameters);             /* 任务函数 *//******************************************************************************************************//*** 2 FreeRTOS例程入口函数* @param       无* @retval      无*/
void freertos_demo(void)
{xTaskCreate((TaskFunction_t )start_task,            /* 任务函数 */(const char*    )"start_task",          /* 任务名称 */(uint16_t       )START_STK_SIZE,        /* 任务堆栈大小 */(void*          )NULL,                  /* 传入给任务函数的参数 */(UBaseType_t    )START_TASK_PRIO,       /* 任务优先级 */(TaskHandle_t*  )&StartTask_Handler);   /* 任务句柄 */vTaskStartScheduler();
}/*** 3 start_task* @param       pvParameters : 传入参数(未用到)* @retval      无*/
void start_task(void *pvParameters)
{taskENTER_CRITICAL();           /* 进入临界区 *//* 创建任务1 */xTaskCreate((TaskFunction_t )task1,(const char*    )"task1",(uint16_t       )TASK1_STK_SIZE,(void*          )NULL,(UBaseType_t    )TASK1_PRIO,(TaskHandle_t*  )&Task1Task_Handler);/* 创建任务2 */xTaskCreate((TaskFunction_t )task2,(const char*    )"task2",(uint16_t       )TASK2_STK_SIZE,(void*          )NULL,(UBaseType_t    )TASK2_PRIO,(TaskHandle_t*  )&Task2Task_Handler);vTaskDelete(StartTask_Handler); /* 删除开始任务 */taskEXIT_CRITICAL();            /* 退出临界区 */
}/*** 3 task1发送任务通知值* @param       pvParameters : 传入参数(未用到)* @retval      无*/
void task1(void *pvParameters)
{uint8_t key = 0;while (1){key = key_scan(0);if((key != 0) && (Task2Task_Handler != NULL)){printf("任务通知模拟消息邮箱发送,发送的键值:%d\r\n",key);xTaskNotify(Task2Task_Handler,key,eSetValueWithOverwrite);}vTaskDelay(10);}
}/*** 3 task2 接收任务通知值* @param       pvParameters : 传入参数(未用到)* @retval      无*/
void task2(void *pvParameters)
{uint32_t notify_val = 0;while (1){xTaskNotifyWait(0,0xFFFFFFFF,&notify_val,portMAX_DELAY);switch(notify_val){case KEY0_PRES:printf("接收到的通知为:%d\r\n",notify_val);LED0_TOGGLE();break;case KEY1_PRES:printf("接收到的通知为:%d\r\n",notify_val);LED1_TOGGLE();break;default : break;}}
}

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

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

相关文章

Hive基础知识(四):Hive 元数据配置到 MySQL

1. 拷贝驱动 将 MySQL 的 JDBC 驱动拷贝到 Hive 的 lib 目录下 [zzdqhadoop100 software]$ cp /home/atguigu/mysql-connector-java-5.1.37.jar $HIVE_HOME/lib 2. 配置 Metastore 到 MySQL 1&#xff09;在$HIVE_HOME/conf 目录下新建 hive-site.xml 文件 [zzdqhadoop100 s…

Altium Designer实用系列(六)----AD问题整理,持续更新......

本篇博客会对粉丝提出的问题进行整理汇总&#xff0c;博客会持续更新… 一、 问题描述 问题1&#xff1a; 为什么我的ad点击设计之后没有update pcb document 原因&#xff1a;由于在工程中只有schDoc文件&#xff0c;没有PcbDoc&#xff0c;而导致没有“设计”–>update …

TypeScript 和 jsdom 库创建爬虫程序示例

TypeScript 简介 TypeScript 是一种由微软开发的自由和开源的编程语言。它是 JavaScript 的一个超集&#xff0c;可以编译生成纯 JavaScript 代码。TypeScript 增加了可选的静态类型和针对对象的编程功能&#xff0c;使得开发更加大规模的应用容易。 jsdom 简介 jsdom 是一个…

oracle 19c容器数据库数据加载和传输-----SQL*Loader(一)

目录 数据加载 &#xff08;一&#xff09;控制文件加载 1.创建用户执行sqlldr 2.创建文本文件和控制文件 3.查看表数据 4.查看log文件 &#xff08;二&#xff09;快捷方式加载 1.system用户执行 2.查看表数据 3.查看log文件 外部表 数据加载和传输的工具&#xff1…

【docker】centos7安装harbor

目录 零、前提一、下载离线包二、安装三、访问四、开机自启 零、前提 1.前提是已经安装了docker和docker-compose 一、下载离线包 1. csdn资源&#xff1a;harbor-offline-installer-v2.10.0.tgz 2. 百度云盘&#xff08;提取码&#xff1a;ap3t&#xff09;&#xff1a;harbo…

2023三星齐发,博客之星、华为OD、Java学习星球

大家好&#xff0c;我是哪吒。 一、回顾2023 2023年&#xff0c;华为OD成了我的主旋律&#xff0c;一共发布了561篇文章&#xff0c;其中包含 368篇华为OD机试的文章&#xff1b;100篇Java基础的文章40多篇MongoDB、Redis的文章&#xff1b;30多篇数据库的文章&#xff1b;2…

Java多线程并发篇----第二篇

系列文章目录 文章目录 系列文章目录前言一、ExecutorService、 Callable、 Future 有返回值线程二、基于线程池的方式三、4 种线程池前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,看懂了就去…

VS2022 | 调整适配虚幻5的设置

VS2022 | 调整适配虚幻5的设置

系统存储架构升级分享 | 京东云技术团队

一、业务背景 系统业务功能&#xff1a;系统内部进行数据处理及整合, 对外部系统提供结果数据的初始化(写)及查询数据结果服务。 系统网络架构: 部署架构对切量上线的影响 - 内部管理系统上线对其他系统的读业务无影响分布式缓存可进行单独扩容, 与存储及查询功能升级无关通过…

1.2 Hadoop概述

小肥柴的Hadoop之旅 1.2 Hadoop概述 目录1.2 Hadoop概述1.2.1 回归问题1.2.2 Google的三篇论文1.2.3 Hadoop的诞生过程1.2.4 Hadoop特点简介 参考文献和资料 ) 目录 1.2 Hadoop概述 1.2.1 回归问题 通过前一篇帖子的介绍&#xff0c;特别是问题思考部分的说明&#xff0c;我…

GCN的使用和包的安装(超详细)

文章目录 工具包安装方法首先进入官网&#xff0c;找到安装包的地址进入后&#xff0c;找到自己的torch版本进入后&#xff0c;将每种对应的包都下载到本地&#xff0c;用本地命令安装然后就是本地安装了最后就是pip install pytorch_geometric 工具包安装方法 一定参考其GITH…

【ASP.NET Core 基础知识】--项目结构

一、ASP.NET Core项目的基本结构 ASP.NET Core项目的基本结构通常遵循一种标准的组织方式&#xff0c;这有助于提高项目的可维护性和可扩展性。以下是一个典型的ASP.NET Core项目的基本结构&#xff1a; 项目文件 (.csproj): 项目的主要配置文件&#xff0c;定义了项目的依…

idea创建javaweb项目步骤超详细(2022最新版本)

目录 前言必读 一、新建文件 1.在idea里面点击文件-新建-项目 2.新建项目-更改名称为自己想要的项目名称-创建 3.右键自己建立的项目-添加框架支持&#xff08;英文版是Add Framework Support...&#xff09; 4.勾选Web应用程序-确定 5.建立成功界面 二、配置tomcat 6.…

Java游戏开发 —— 坦克大战

引言&#xff1a; 坦克大战也是小时一个比较经典的游戏了&#xff0c;我在网上也是参考了韩顺平老师写的坦克大战&#xff0c;并做了一下完善&#xff0c;编写出来作为儿时的回忆吧&#xff01; 思路&#xff1a; 创建主窗口&#xff0c;加载菜单及游戏面板。 在游戏面板中初始…

聊聊 Java 集合框架中的 ArrayList

其实 Java 集合框架也叫做容器&#xff0c;主要由两大接口派生而来&#xff0c;一个是 collection,主要存放对象的集合。另外一个是Map, 存储着键值对&#xff08;两个对象&#xff09;的映射表。 下面就来说说 List接口&#xff0c;List存储的元素是有序、可重复的。其下有三个…

HarmonOS 日期选择组件(DatePicker)

本文 我们一起来看基础组件中的 DatePicker 这就是 日程开发中的日期组件 他可以创建一个日期的范围 并创建一个日期的滑动选择器 这里 我们先写一个组件的骨架 Entry Component struct Index {build() {Row() {Column() {}.width(100%)}.height(100%)} }然后 我们先在Column组…

打造成功的SRE团队

一个成功的SRE团队可以为组织带来巨大价值&#xff0c;帮助组织高效完成价值交付。本文介绍了Mission Lane公司打造SRE团队的经验和实践。原文: Building a Successful SRE Team 简介 当我加入Mission Lane时&#xff0c;是公司仅有的两名站点可靠性工程师(SRE)之一&#xff0c…

时序预测 | Matlab实现GJO-VMD-LSTM金豺-变分模态分解-长短期记忆网络时间序列预测

时序预测 | Matlab实现GJO-VMD-LSTM金豺-变分模态分解-长短期记忆网络时间序列预测 目录 时序预测 | Matlab实现GJO-VMD-LSTM金豺-变分模态分解-长短期记忆网络时间序列预测预测效果基本介绍模型设计程序设计参考资料 预测效果 基本介绍 Matlab实现GJO-VMD-LSTM金豺-变分模态分…

PyQT5实现图像处理应用(含Windows7下完整打包方案)

目录 1、任务概述2、环境安装2.1 创建虚拟环境2.2 安装依赖库 3、程序开发3.1 框架搭建3.2 读取图像3.3 图像处理 4、打包部署5、小结 1、任务概述 本篇博文将通过PyQT5来实现一个简单的图像处理应用&#xff0c;并完成打包部署。 本文开发平台&#xff1a;Windows10 64位系统…

如何找回删除的Word文档?多方法供您选择

在日常生活和工作中&#xff0c;我们经常使用Microsoft Word来创建、编辑和保存文档。然而&#xff0c;有时候我们会不小心删除了重要的Word文档&#xff0c;导致无法挽回的损失。幸运的是&#xff0c;有一些方法可以帮助我们找回已删除的Word文档。本文将介绍一些常用的方法供…