FreeRTOS的中断管理、临界资源保护、任务调度

news2024/11/25 0:55:09

什么是中断?

简介:让CPU打断正常运行的程序,转而去处理紧急的事件(程序),就叫中断。

中断优先级分组设置 

        ARM Cortex-M 使用了 8 位宽的寄存器来配置中断的优先等级,这个寄存器就是中断优先级来配置寄存器。

        但STM32,只用了中断优先级配置寄存器的高4位 [7 : 4],所以STM32提供了最大16级的中断优先等级。

STM32 的中断优先级可以分为抢占优先级和子优先级。

抢占优先级: 抢占优先级高的中断可以打断正在执行但抢占优先级低的中断。 

子优先级:当同时发生具有相同抢占优先级的两个中断时,子优先级数值小的优先执行。

注意:中断优先级数值越小越优先。

一共有 5 种分配方式,对应着中断优先级分组的 5 个组。

特点: 

1、低于configMAX_SYSCALL_INTERRUPT_PRIORITY优先级的中断里才允许调用FreeRTOS 的API函数。

2、建议将所有优先级位指定为抢占优先级位,方便FreeRTOS管理。

3、中断优先级数值越小越优先,任务优先级数值越大越优先。

中断相关寄存器 

三个系统中断优先级配置寄存器,分别为 SHPR1、 SHPR2、 SHPR3 。

SHPR1寄存器地址:0xE000ED18。

SHPR2寄存器地址:0xE000ED1C。

SHPR3寄存器地址:0xE000ED20。

FreeRTOS如何配置PendSV和Systick中断优先级? 

中断相关寄存器

三个中断屏蔽寄存器,分别为 PRIMASK、 FAULTMASK 和BASEPRI  。

FreeRTOS所使用的中断管理就是利用的BASEPRI这个寄存器。         

BASEPRI:屏蔽优先级低于某一个阈值的中断。

比如: BASEPRI设置为0x50,代表中断优先级在5~15内的均被屏蔽,0~4的中断优先级正常执行。

BASEPRI:屏蔽优先级低于某一个阈值的中断,当设置为0时,则不关闭任何中断。

关中断程序示例:

中断优先级在5 ~ 15的全部被关闭 。

开中断程序示例:

FreeRTOS中断管理就是利用BASEPRI寄存器实现的 。

中断管理  

        在 RTOS 中,需要应对各类事件。这些事件很多时候是通过硬件中断产生,怎么处理呢?
        假设当前系统正在运行 Task1 时,用户按下了按键,触发了按键中断。这个中断的处理流程如下:
        CPU 跳到固定地址去执行代码,这个固定地址通常被称为中断向量,这个跳转时硬件实现。
        执行代码做什么?
        保存现场:Task1 被打断,需要先保存 Task1 的运行环境,比如各类寄存器的值。
        分辨中断、调用处理函数 ( 这个函数就被称为 ISR interrupt service routine)
        恢复现场:继续运行 Task1 ,或者运行其他优先级更高的任务你要注意到,ISR 是在内核中被调用的, ISR 执行过程中,用户的任务无法执行。 ISR要尽量快,否则:其他低优先级的中断无法被处理:实时性无法保证用户任务无法被执行:系统显得很卡顿。
        
        如果这个硬件中断的处理,就是非常耗费时间呢?对于这类中断的处理就要分为 2 部分:
        ISR:尽快做些清理、记录工作,然后触发某个任务
        任务:更复杂的事情放在任务中处理
        所以:需要 ISR 和任务之间进行通信要在 FreeRTOS 中熟练使用中断,有几个原则要先说明:
        FreeRTOS 把任务认为是硬件无关的,任务的优先级由程序员决定,任务何时运行由调度器决定。
        ISR 虽然也是使用软件实现的,但是它被认为是硬件特性的一部分,因为它跟硬件密切相关。
        何时执行?由硬件决定。
        
        哪个 ISR 被执行?由硬件决定。
        
        ISR 的优先级高于任务:即使是优先级最低的中断,它的优先级也高于任务。任务只有在没有中断的情况下,才能执行。
      

两套 API 函数

        在任务函数中,我们可以调用各类 API 函数,比如队列操作函数:
        
        xQueueSendToBack。但是在 ISR 中使用这个函数会导致问题,应该使用另一个函数:
        
        xQueueSendToBackFromISR,它的函数名含有后缀"FromISR" ,表示 " ISR 中给队列发送
数据 "
        FreeRTOS 中很多 API 函数都有两套:一套在任务中使用,另一套在 ISR 中使用。后者的函数名含有"FromISR" 后缀。
        
        为什么要引入两套 API 函数?
        很多 API 函数会导致任务计入阻塞状态:
        
        运行这个函数的任务进入阻塞状态。
        比如写队列时,如果队列已满,可以进入阻塞状态等待一会。
        ISR 调用 API 函数时,ISR 不是"任务"ISR 不能进入阻塞状态。
        所以,在任务中、在 ISR 中,这些函数的功能是有差别的。

两套 API 函数列表 

 xHigherPriorityTaskWoken 参数

        xHigherPriorityTaskWoken 的含义是:是否有更高优先级的任务被唤醒了。如果为pdTRUE,则意味着后面要进行任务切换。
        还是以写队列为例。
        任务 A 调用 xQueueSendToBack() 写队列,有几种情况发生:
        队列满了,任务 A 阻塞等待,另一个任务 B 运行
        队列没满,任务 A 成功写入队列,但是它导致另一个任务 B 被唤醒,任务
        B 的优先级更高:任务 B 先运行
        队列没满,任务 A 成功写入队列,即刻返回
        可以看到,在任务中调用 API 函数可能导致任务阻塞、任务切换,这叫做 "context switch",上下文切换。这个函数可能很长时间才返回,在函数的内部实现了任务切换。
        xQueueSendToBackFromISR() 函数也可能导致任务切换,但是不会在函数内部进行切
换,而是返回一个参数:表示是否需要切换,函数原型与用法如下:
/* 
* 往队列尾部写入数据,此函数可以在中断函数中使用,不可阻塞
*/
BaseType_t xQueueSendToBackFromISR(
 QueueHandle_t xQueue,
 const void *pvItemToQueue,BaseType_t *pxHigherPriorityTaskWoken
 );
/* 用法示例 */
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xQueueSendToBackFromISR(xQueue, pvItemToQueue, &xHigherPriorityTaskWoken);
if (xHigherPriorityTaskWoken == pdTRUE)
{
 /* 任务切换 */ 
}
        pxHigherPriorityTaskWoken 参数,就是用来保存函数的结果:是否需要切换
        *pxHigherPriorityTaskWoken 等于 pdTRUE :函数的操作导致更高优先级的任务就绪了,ISR 应该进行任务切换。
        *pxHigherPriorityTaskWoken 等于 pdFALSE :没有进行任务切换的必要
        为什么不在"FromISR" 函数内部进行任务切换,而只是标记一下而已呢?为了效率!
示例代码如下:
void XXX_ISR()
{
 int i;
 for (i = 0; i < N; i++)
 {
 xQueueSendToBackFromISR(...); /* 被多次调用 */
 }
}
ISR 中有可能多次调用 "FromISR" 函数,如果在 "FromISR" 内部进行任务切换,会浪费时间。解决方法是:
        在"FromISR" 中标记是否需要切换。
        在 ISR 返回之前再进行任务切换。
        示例代码如下:
void XXX_ISR()
{
 int i;
 BaseType_t xHigherPriorityTaskWoken = pdFALSE;
 
 for (i = 0; i < N; i++)
 {
 xQueueSendToBackFromISR(..., &xHigherPriorityTaskWoken); /* 被多次调用 */
 }
 /* 最后再决定是否进行任务切换 */
 if (xHigherPriorityTaskWoken == pdTRUE)
 {
     /* 任务切换 */ 
 }
}
        上述的例子很常见,比如 UART 中断:在 UART ISR 中读取多个字符,发现收到回车符时才进行任务切换。
        在 ISR 中调用 API 时不进行任务切换,而只是在 "xHigherPriorityTaskWoken" 中标记一下,除了效率,还有多种好处:
        效率高:避免不必要的任务切换。
        让 ISR 更可控:中断随机产生,在 API 中进行任务切换的话,可能导致问题更复杂。
        可移植性。
        在 Tick 中断中,调用 vApplicationTickHook() :它运行与 ISR ,只能使用 "FromISR"的函数
使用 "FromISR" 函数时,如果不想使用 xHigherPriorityTaskWoken 参数,可以设置为NULL。

怎么切换任务 

        FreeRTOS ISR 函数中,使用两个宏进行任务切换:

        portEND_SWITCHING_ISR ( xHigherPriorityTaskWoken );
        portYIELD_FROM_ISR ( xHigherPriorityTaskWoken );
        这两个宏做的事情是完全一样的,在老版本的 FreeRTOS 中,
        portEND_SWITCHING_ISR 使用汇编实现
        portYIELD_FROM_ISR 使用 C 语言实现
        
        新版本都统一使用 portYIELD_FROM_ISR 。使用示例如下:
void XXX_ISR()
{
 int i;
 BaseType_t xHigherPriorityTaskWoken = pdFALSE;
 
 for (i = 0; i < N; i++)
 {
 xQueueSendToBackFromISR(..., &xHigherPriorityTaskWoken); /* 被多次调用 */
 }
 /* 最后再决定是否进行任务切换
 * xHigherPriorityTaskWoken 为 pdTRUE 时才切换
 */
 portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}

中断的延迟处理

        前面讲过,ISR 要尽量快,否则: 其他低优先级的中断无法被处理:实时性无法保证,用户任务无法被执行:系统显得很卡顿。
        如果运行中断嵌套,这会更复杂,ISR 越快执行约有助于中断嵌套。
        如果这个硬件中断的处理,就是非常耗费时间呢?对于这类中断的处理就要分为 2 部分:
        ISR:尽快做些清理、记录工作,然后触发某个任务。
        任务:更复杂的事情放在任务中处理。
        这种处理方式叫" 中断的延迟处理 "(Deferring interrupt processing) ,处理流程如下图所示:
        t1:任务 1 运行,任务 2 阻塞。
        t2:发生中断。
        该中断的 ISR 函数被执行,任务 1 被打断。
        ISR 函数要尽快能快速地运行,它做一些必要的操作 ( 比如清除中断 ) ,然后唤醒任务 2。
        t3:在创建任务时设置任务 2 的优先级比任务 1 ( 这取决于设计者 ) ,所以ISR 返回后,运行的是任务 2 ,它要完成中断的处理。任务 2 就被称为"deferred processing task",中断的延迟处理任务。
        t4:任务 2 处理完中断后,进入阻塞态以等待下一个中断,任务 1 重新运行。

中断与任务间的通信

前面讲解过的队列、信号量、互斥量、事件组、任务通知等等方法,都可使用。要注意的是,在 ISR 中使用的函数要有 "FromISR" 后缀。

资源管理(Resource Management)

        在前面讲解互斥量时,引入过临界资源的概念。在前面课程里,已经实现了临界资源的互斥访问。
        本章节的内容比较少,只是引入两个功能:屏蔽/ 使能中断、暂停 / 恢复调度器。要独占式地访问临界资源,有 3 种方法:
        公平竞争:比如使用互斥量,谁先获得互斥量谁就访问临界资源,这部分内容前面讲过。
        谁要跟我抢,我就灭掉谁:
        
        中断要跟我抢?我屏蔽中断。
        其他任务要跟我抢?我禁止调度器,不运行任务切换。

屏蔽中断

        屏蔽中断有两套宏:任务中使用、ISR 中使用:
        任务中使用: taskENTER_CRITICA()/taskEXIT_CRITICAL()
        ISR 中使用: taskENTER_CRITICAL_FROM_ISR()/taskEXIT_CRITICAL_FROM_ISR()

在任务中屏蔽中断 

在任务中屏蔽中断的示例代码如下:
/* 在任务中,当前时刻中断是使能的
* 执行这句代码后,屏蔽中断
*/
taskENTER_CRITICAL();
/* 访问临界资源 */
/* 重新使能中断 */
taskEXIT_CRITICAL();
taskENTER_CRITICA()/taskEXIT_CRITICAL() 之间:
低优先级的中断被屏蔽了:优先级低于、等于 configMAX_SYSCALL_INTERRUPT_PRIORITY
高优先级的中断可以产生:优先级高于 configMAX_SYSCALL_INTERRUPT_PRIORITY
但是,这些中断 ISR 里,不允许使用 FreeRTOS API 函数
任务调度依赖于中断、依赖于 API 函数,所以:这两段代码之间,不会有任务调度产生
这套 taskENTER_CRITICA()/taskEXIT_CRITICAL() 宏,是可以递归使用的,它的内部会记录嵌套的深度,只有嵌套深度变为 0 时,调用 taskEXIT_CRITICAL() 才会重新使能中断。
使用 taskENTER_CRITICA()/taskEXIT_CRITICAL() 来访问临界资源是很粗鲁的方法:
中断无法正常运行。
任务调度无法进行。
 所以,之间的代码要尽可能快速地执行。

ISR 中屏蔽中断

要使用含有 "FROM_ISR" 后缀的宏,示例代码如下:
void vAnInterruptServiceRoutine( void )
{
 /* 用来记录当前中断是否使能 */
 UBaseType_t uxSavedInterruptStatus;
 
 /* 在 ISR 中,当前时刻中断可能是使能的,也可能是禁止的
 * 所以要记录当前状态, 后面要恢复为原先的状态
 * 执行这句代码后,屏蔽中断
 */
 uxSavedInterruptStatus = taskENTER_CRITICAL_FROM_ISR();
 
 /* 访问临界资源 */
 /* 恢复中断状态 */
 taskEXIT_CRITICAL_FROM_ISR( uxSavedInterruptStatus );
 /* 现在,当前 ISR 可以被更高优先级的中断打断了 */
}
taskENTER_CRITICA_FROM_ISR()/taskEXIT_CRITICAL_FROM_ISR() 之间:
低优先级的中断被屏蔽了:优先级低于、等于 configMAX_SYSCALL_INTERRUPT_PRIORITY。
高优先级的中断可以产生:优先级高于 configMAX_SYSCALL_INTERRUPT_PRIORITY。
但是,这些中断 ISR 里,不允许使用 FreeRTOS API 函数。
任务调度依赖于中断、依赖于 API 函数,所以:这两段代码之间,不会有任务调度产生。

暂停调度器

        如果有别的任务来跟你竞争临界资源,你可以把中断关掉:这当然可以禁止别的任务
运行,但是这代价太大了。它会影响到中断的处理。
        
        如果只是禁止别的任务来跟你竞争,不需要关中断,暂停调度器就可以了:在这期间,中断还是可以发生、处理。使用这 2 个函数来暂停、恢复调度器:
/* 暂停调度器 */
void vTaskSuspendAll( void );
/* 恢复调度器
* 返回值: pdTRUE 表示在暂定期间有更高优先级的任务就绪了
* 可以不理会这个返回值
*/
BaseType_t xTaskResumeAll( void );
示例代码如下:
vTaskSuspendScheduler();
/* 访问临界资源 */
xTaskResumeScheduler();
        这套 vTaskSuspendScheduler()/xTaskResumeScheduler() 宏,是可以递归使用的,它的内部会记录嵌套的深度,只有嵌套深度变为 0 时,调用 taskEXIT_CRITICAL() 才会重新使能中断。

FreeRTOS临界段代码保护

临界段代码保护简介

什么是临界段:临界段代码也叫做临界区,是指那些必须完整运行,不能被打断的代码段。

适用场合如:

临界段代码保护函数介绍 

临界区是直接屏蔽了中断,系统任务调度靠中断,ISR也靠中断。

任务调度 

开启任务调度器

vTaskStartScheduler() :

作用:用于启动任务调度器,任务调度器启动后, FreeRTOS 便会开始进行任务调度

该函数内部实现,如下:

1、创建空闲任务。

2、如果使能软件定时器,则创建定时器任务。

3、关闭中断,防止调度器开启之前或过程中,受中断干扰,会在运行第一个任务时打开中断。

4、初始化全局变量,并将任务调度器的运行标志设置为已运行。

5、初始化任务运行时间统计功能的时基定时器。

6、调用函数 xPortStartScheduler() 。

xPortStartScheduler()

作用:该函数用于完成启动任务调度器中与硬件架构相关的配置部分,以及启动第一个任务。

该函数内部实现,如下:

1、检测用户在 FreeRTOSConfig.h 文件中对中断的相关配置是否有误。

2、配置 PendSV 和 SysTick 的中断优先级为最低优先级。

3、调用函数 vPortSetupTimerInterrupt()配置 SysTick。

4、初始化临界区嵌套计数器为 0。

5、调用函数 prvEnableVFP()使能 FPU。

6、调用函数 prvStartFirstTask()启动第一个任务。 

启动第一个任务

prvStartFirstTask ()     /* 开启第一个任务

vPortSVCHandler () 

注意:SVC中断只在启动第一次任务时会调用一次,以后均不调用。

出栈/压栈汇编指令详解 

任务切换 

注意:任务切换的过程在PendSV中断服务函数里边完成 。

PendSV中断是如何触发的? 

1、滴答定时器中断调用。

2、执行FreeRTOS提供的相关API函数:portYIELD() 。

本质:通过向中断控制和状态寄存器 ICSR 的bit28 写入 1 挂起 PendSV 来启动 PendSV 中断

查找最高优先级任务 

vTaskSwitchContext( )                    /* 查找最高优先级任务 */

taskSELECT_HIGHEST_PRIORITY_TASK( )    /* 通过这个函数完成 */ 

前导置零指令 

获取最高优先级任务的任务控制块 

总结

以上就是FreeRTOS的中断管理、资源管理、任务调度的核心内容。我讲的是关键点,不过也很片面,内部实现过程更为精妙,读者如果水平较高,可以自己去研究一下,我就不去研究了,因为确实有点难,会到这一步就够了。        

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

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

相关文章

硅纪元视角 | 微软开发全新AI模型,革新电子表格处理效率!

在数字化浪潮的推动下&#xff0c;人工智能&#xff08;AI&#xff09;正成为塑造未来的关键力量。硅纪元视角栏目紧跟AI科技的最新发展&#xff0c;捕捉行业动态&#xff1b;提供深入的新闻解读&#xff0c;助您洞悉技术背后的逻辑&#xff1b;汇聚行业专家的见解&#xff0c;…

在ArcGIS Pro中新建空图层的最快方法

01常规方法 一般情况下&#xff0c;如果我们想新建一个要素图层&#xff0c;常规方法是&#xff1a; 在目录框中&#xff0c;找一个gdb数据库&#xff0c;右键——新建——要素类&#xff1a; 设置好各种属性&#xff1a; 创建结果如下&#xff1a; 最后将要素类拖入地图中即…

openeuler 终端中文显示乱码、linux vim中文乱码

1、解决终端乱码 网上很多教程试了都不生效&#xff0c;以下方法有效&#xff1a; 确认终端支持中文显示&#xff1a; echo $LANG 输出应该包含 UTF-8&#xff0c;例如 en_US.UTF-8。如果不是&#xff0c;您可以通过以下命令设置为 UTF-8&#xff1a; export LANGzh_CN.UTF-8…

Rust RefCell<T> 和内部可变性模式

内部可变性&#xff08;Interior mutability&#xff09;是 Rust 中的一个设计模式&#xff0c;它允许你即使在有不可变引用时也可以改变数据&#xff0c;这通常是借用规则所不允许的。为了改变数据&#xff0c;该模式在数据结构中使用 unsafe 代码来模糊 Rust 通常的可变性和借…

阿里云CDN- https(设计支付宝春节开奖业务)

HTTP相关概念 1. HTTP概述 http是最广泛的网络协议&#xff0c;是客户端与服务器之间的请求与应答的标准&#xff08;TCP&#xff09;&#xff0c;用于www服务器传输超文本到本地浏览器的传输协议&#xff0c;使浏览器更加高效&#xff0c;网络传输减少。 2.HTTPS概述 http…

【总结】实际业务场景中锁、事务、异常如何考虑使用?

文章目录 锁处理目的&#xff1a;考虑锁控制思路&#xff1a;生命周期接口并发控制解决方案&#xff1a;测试锁是否生效&#xff1a;模拟多线程并发场景的2种方式&#xff1a; 事务处理目的&#xff1a;考虑事务控制思路&#xff1a;解决方案&#xff1a; 总结 锁处理 目的&am…

集群架构-web服务器(接入负载均衡+数据库+会话保持redis)--15454核心配置详解

紧接着前面的集群架构深化—中小型公司&#xff08;拓展到大型公司业务&#xff09;–下面图简单回顾一下之前做的及故障核心知识总结&#xff08;等后期完全整理后&#xff0c;上传资源希望能帮大家&#xff09; web集群架构-接入负载均衡部署web02服务器等 web集群-搭建web0…

[C++]一些list,stack和queue选择题和编程题

这时我们学完后的应用 一、选择题 1.下面有关vector和list的区别&#xff0c;描述错误的是( ) A.vector拥有一段连续的内存空间&#xff0c;因此支持随机存取&#xff0c;如果需要高效的随机存取,应该使用vector B.list拥有一段不连续的内存空间&#xff0c;如果需要大量的插入…

JavaScript基础(十四)

函数 很多人一看到这两个字就头大&#xff0c;可能由于多年被数学摧残有不小阴影&#xff0c;放心&#xff0c;我们这里的函数不是那些东西&#xff0c;在编程中我们的函数指的是: 程序的基本单元&#xff0c;是完成特定任务的代码语句块。 我们在写程序时&#xff0c;可能会…

【RAG探索第4讲】KG+RAG丨基于知识图谱优化大型语言模型方法

原文链接&#xff1a;【RAG探索第4讲】KGRAG丨基于生物医学知识图谱优化的大型语言模型提示生成方法 一、现有问题&#xff1a; LLMs在处理特定领域或高度专业化查询时缺乏专业知识&#xff0c;导致回答不够准确和可靠。 LLMs可能会产生事实错误&#xff08;即幻觉&#xff0…

【整洁单元测试】测试气味Test Smells

背景 "Code smell" 是软件开发中的一个术语&#xff0c;指的是代码中可能表明存在问题的某些迹象或模式。这些迹象本身并不表示代码一定有错误&#xff0c;但它们通常表明代码可能难以理解、维护或扩展。Code smells 可以视为一种警告&#xff0c;提示开发者需要进一…

0基础学python-14:python进阶之面向对象

前言 Python是一门解释型、面向对象以及动态数据类型的高级程序设计语言&#xff0c;今天所要说的就是极为重要的概念&#xff0c;面向对象。 一、面向对象的核心概念&#xff1a; 1.类&#xff08;Class&#xff09;&#xff1a; 类是对象的抽象描述&#xff0c;是面向对象编…

HarmonyOS开发中几个常见问题

前言 最近开始HarmonyOS应用开发&#xff0c;遇到一些小问题&#xff0c;也算是自己看官网文档没记住的东西&#xff0c;过程中再记录一下。 一、更改应用的名字和图标 对比看下Android工程中是如何更改的&#xff0c;只需要在清单文件AndroidManifest.xml中&#xff0c;更改…

机器学习 | 深入理解激活函数

什么是激活函数&#xff1f; 在人工神经网络中&#xff0c;节点的激活函数定义了该节点或神经元对于给定输入或一组输入的输出。然后&#xff0c;将此输出用作下一个节点的输入&#xff0c;依此类推&#xff0c;直到找到原始问题的所需解决方案。 它将结果值映射到所需的范围…

CSS综合案例(快报模块头部制作)

&#xff08;大家好&#xff0c;今天我们将继续来学习CSS的相关知识&#xff0c;大家可以在评论区进行互动答疑哦~加油&#xff01;&#x1f495;&#xff09; 目录 一、前述 二、案例分析 1.样例参看 2.拆分分析 三、案例实施 一、前述 案例&#xff1a;快报模块头部制…

微信小程序基本语法

官网 https://developers.weixin.qq.com/miniprogram/dev/framework/ 视频教程&#xff1a;尚硅谷微信小程序开发教程&#xff0c;2024最新微信小程序项目实战&#xff01; 仿慕尚花坊项目源码&#xff1a;https://gitee.com/abcdfdewrw/flower-workshop 目录 一&#xff0c;初…

热门软件缺陷管理工具2024:专业评测与建议

国内外主流的10款软件缺陷管理工具软件对比&#xff1a;PingCode、Worktile、禅道、Tapd、Teambition、Tower、JIRA、Bugzilla、MantisBT、Trac。 在软件开发过程中&#xff0c;管理缺陷和漏洞常常成为一项挑战&#xff0c;尤其是在项目规模庞大时。选择一个高效的软件缺陷管理…

C#实现自定义标签的设计和打印

背景:最近在进行资产盘点的时候,需要对固定资产设计标签并进行打印。 设计标签:选用的是Fastreport自带的,可拆包忌用的标签设计器;进行标签的模型设计。 软件解压后可直接进行使用。模板的设计基本都是无脑操作,拖拽控件按,放置到固定未知即可;我设计的模板如下: 说…

Vision Pro的增强视觉:企业级Unity插件包实现主摄像头访问

在AR和VR技术的快速发展中,Unity作为跨平台游戏和应用开发的首选引擎,其插件生态的丰富性一直是开发者们关注的焦点。最近,一个专为Vision Pro设计的Unity插件包——EnterpriseCameraAccessPlugin,因其能够通过企业API访问主摄像头的功能,引起了广泛关注。 一、插件背景与…

springboot+vue+mybatis鲜花管理系统+PPT+论文+讲解+售后

随着科学技术的飞速发展&#xff0c;社会的方方面面、各行各业都在努力与现代的先进技术接轨&#xff0c;通过科技手段来提高自身的优势&#xff0c;鲜花管理系统当然也不能排除在外。鲜花管理系统是以实际运用为开发背景&#xff0c;运用软件工程开发方法&#xff0c;采用SSM技…