μC/OS-II---互斥信号量管理1(os_mutex.c)

目录

  • 背景:优先级反转问题
  • 互斥信号量管理
    • 互斥信号量创建
    • 互斥信号量删除
    • 互斥信号量获取/等待

在这里插入图片描述

背景:优先级反转问题

  • 在高优先级任务等待低优先级任务释放资源时,第三个中等优先级任务抢占了低优先级任务。阻塞时间是无法预测的,可能导致高优先级任务无法满足deadline。这是需要解决的问题。μC/OS-II采用的办法:优先级继承协议。【实际采用的方法是由互斥信号量先预占一个优先级】

互斥信号量管理

互斥信号量创建

OS_EVENT  *OSMutexCreate (INT8U   prio,
													INT8U  *perr)
{
	OS_EVENT  *pevent;
#if OS_CRITICAL_METHOD == 3u                               /* Allocate storage for CPU status register */
	OS_CPU_SR  cpu_sr = 0u;
#endif
#ifdef OS_SAFETY_CRITICAL
	
	if (perr == (INT8U *)0)
	{
		OS_SAFETY_CRITICAL_EXCEPTION();
		return ((OS_EVENT *)0);
	}
	
#endif
#ifdef OS_SAFETY_CRITICAL_IEC61508
	
	if (OSSafetyCriticalStartFlag == OS_TRUE)
	{
		OS_SAFETY_CRITICAL_EXCEPTION();
		return ((OS_EVENT *)0);
	}
	
#endif
#if OS_ARG_CHK_EN > 0u
	
	if (prio != OS_PRIO_MUTEX_CEIL_DIS)
	{
		if (prio >= OS_LOWEST_PRIO)                        /* Validate PCP                             */
		{
			*perr = OS_ERR_PRIO_INVALID;
			return ((OS_EVENT *)0);
		}
	}
	
#endif
	
	if (OSIntNesting > 0u)                                 /* See if called from ISR ...               */
	{
		*perr = OS_ERR_CREATE_ISR;                         /* ... can't CREATE mutex from an ISR       */
		return ((OS_EVENT *)0);
	}
	
	OS_ENTER_CRITICAL();
	
	if (prio != OS_PRIO_MUTEX_CEIL_DIS)
	{
		if (OSTCBPrioTbl[prio] != (OS_TCB *)0)             /* Mutex priority must not already exist    */
		{
			OS_EXIT_CRITICAL();                            /* Task already exist at priority ...       */
			*perr = OS_ERR_PRIO_EXIST;                      /* ... ceiling priority                     */
			return ((OS_EVENT *)0);
		}
		
		OSTCBPrioTbl[prio] = OS_TCB_RESERVED;              /* Reserve the table entry                  */
	}
	
	pevent = OSEventFreeList;                              /* Get next free event control block        */
	
	if (pevent == (OS_EVENT *)0)                           /* See if an ECB was available              */
	{
		if (prio != OS_PRIO_MUTEX_CEIL_DIS)
		{
			OSTCBPrioTbl[prio] = (OS_TCB *)0;              /* No, Release the table entry              */
		}
		
		OS_EXIT_CRITICAL();
		*perr = OS_ERR_PEVENT_NULL;                         /* No more event control blocks             */
		return (pevent);
	}
	
	OSEventFreeList     = (OS_EVENT *)OSEventFreeList->OSEventPtr; /* Adjust the free list             */
	OS_EXIT_CRITICAL();
	pevent->OSEventType = OS_EVENT_TYPE_MUTEX;
	pevent->OSEventCnt  = (INT16U) ((INT16U)prio << 8u) | OS_MUTEX_AVAILABLE; /* Resource is avail.     */
	pevent->OSEventPtr  = (void *)0;                       /* No task owning the mutex                 */
#if OS_EVENT_NAME_EN > 0u
	pevent->OSEventName = (INT8U *) (void *)"?";
#endif
	OS_EventWaitListInit (pevent);
	*perr = OS_ERR_NONE;
	return (pevent);
}

互斥信号量删除

#if OS_MUTEX_DEL_EN > 0u
OS_EVENT  *OSMutexDel (OS_EVENT  *pevent,
											 INT8U      opt,
											 INT8U     *perr)
{
	BOOLEAN    tasks_waiting;
	OS_EVENT  *pevent_return;
	INT8U      pcp;                                        /* Priority ceiling priority                */
	INT8U      prio;
	OS_TCB    *ptcb;
#if OS_CRITICAL_METHOD == 3u                               /* Allocate storage for CPU status register */
	OS_CPU_SR  cpu_sr = 0u;
#endif
#ifdef OS_SAFETY_CRITICAL
	
	if (perr == (INT8U *)0)
	{
		OS_SAFETY_CRITICAL_EXCEPTION();
		return ((OS_EVENT *)0);
	}
	
#endif
#if OS_ARG_CHK_EN > 0u
	
	if (pevent == (OS_EVENT *)0)                           /* Validate 'pevent'                        */
	{
		*perr = OS_ERR_PEVENT_NULL;
		return (pevent);
	}
	
#endif
	
	if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX)        /* Validate event block type                */
	{
		*perr = OS_ERR_EVENT_TYPE;
		return (pevent);
	}
	
	if (OSIntNesting > 0u)                                 /* See if called from ISR ...               */
	{
		*perr = OS_ERR_DEL_ISR;                             /* ... can't DELETE from an ISR             */
		return (pevent);
	}
	
	OS_ENTER_CRITICAL();
	
	if (pevent->OSEventGrp != 0u)                          /* See if any tasks waiting on mutex        */
	{
		tasks_waiting = OS_TRUE;                           /* Yes                                      */
	}
	
	else
	{
		tasks_waiting = OS_FALSE;                          /* No                                       */
	}
	
	switch (opt)
	{
		case OS_DEL_NO_PEND:                               /* DELETE MUTEX ONLY IF NO TASK WAITING --- */
			if (tasks_waiting == OS_FALSE)
			{
#if OS_EVENT_NAME_EN > 0u
				pevent->OSEventName   = (INT8U *) (void *)"?";
#endif
				pcp                   = (INT8U) (pevent->OSEventCnt >> 8u);
				
				if (pcp != OS_PRIO_MUTEX_CEIL_DIS)
				{
					OSTCBPrioTbl[pcp] = (OS_TCB *)0;      /* Free up the PCP                          */
				}
				
				pevent->OSEventType   = OS_EVENT_TYPE_UNUSED;
				pevent->OSEventPtr    = OSEventFreeList;  /* Return Event Control Block to free list  */
				pevent->OSEventCnt    = 0u;
				OSEventFreeList       = pevent;
				OS_EXIT_CRITICAL();
				*perr                 = OS_ERR_NONE;
				pevent_return         = (OS_EVENT *)0;    /* Mutex has been deleted                   */
			}
			
			else
			{
				OS_EXIT_CRITICAL();
				*perr                 = OS_ERR_TASK_WAITING;
				pevent_return         = pevent;
			}
			
			break;
			
		case OS_DEL_ALWAYS:                                /* ALWAYS DELETE THE MUTEX ---------------- */
			pcp  = (INT8U) (pevent->OSEventCnt >> 8u);                      /* Get PCP of mutex       */
			
			if (pcp != OS_PRIO_MUTEX_CEIL_DIS)
			{
				prio = (INT8U) (pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8); /* Get owner's orig prio  */
				ptcb = (OS_TCB *)pevent->OSEventPtr;
				
				if (ptcb != (OS_TCB *)0)                  /* See if any task owns the mutex           */
				{
					if (ptcb->OSTCBPrio == pcp)           /* See if original prio was changed         */
					{
						OSMutex_RdyAtPrio (ptcb, prio);   /* Yes, Restore the task's original prio    */
					}
				}
			}
			
			while (pevent->OSEventGrp != 0u)              /* Ready ALL tasks waiting for mutex        */
			{
				(void)OS_EventTaskRdy (pevent, (void *)0, OS_STAT_MUTEX, OS_STAT_PEND_ABORT);
			}
			
#if OS_EVENT_NAME_EN > 0u
			pevent->OSEventName   = (INT8U *) (void *)"?";
#endif
			pcp                   = (INT8U) (pevent->OSEventCnt >> 8u);
			
			if (pcp != OS_PRIO_MUTEX_CEIL_DIS)
			{
				OSTCBPrioTbl[pcp] = (OS_TCB *)0;          /* Free up the PCP                          */
			}
			
			pevent->OSEventType   = OS_EVENT_TYPE_UNUSED;
			pevent->OSEventPtr    = OSEventFreeList;      /* Return Event Control Block to free list  */
			pevent->OSEventCnt    = 0u;
			OSEventFreeList       = pevent;               /* Get next free event control block        */
			OS_EXIT_CRITICAL();
			
			if (tasks_waiting == OS_TRUE)                 /* Reschedule only if task(s) were waiting  */
			{
				OS_Sched();                               /* Find highest priority task ready to run  */
			}
			
			*perr         = OS_ERR_NONE;
			pevent_return = (OS_EVENT *)0;                /* Mutex has been deleted                   */
			break;
			
		default:
			OS_EXIT_CRITICAL();
			*perr         = OS_ERR_INVALID_OPT;
			pevent_return = pevent;
			break;
	}
	
	return (pevent_return);
}
#endif

互斥信号量获取/等待

void  OSMutexPend (OS_EVENT  *pevent,
									 INT32U     timeout,
									 INT8U     *perr)
{
	INT8U      pcp;                                        /* Priority Ceiling Priority (PCP)          */
	INT8U      mprio;                                      /* Mutex owner priority                     */
	BOOLEAN    rdy;                                        /* Flag indicating task was ready           */
	OS_TCB    *ptcb;
	OS_EVENT  *pevent2;
	INT8U      y;
#if OS_CRITICAL_METHOD == 3u                               /* Allocate storage for CPU status register */
	OS_CPU_SR  cpu_sr = 0u;
#endif
#ifdef OS_SAFETY_CRITICAL
	
	if (perr == (INT8U *)0)
	{
		OS_SAFETY_CRITICAL_EXCEPTION();
		return;
	}
	
#endif
#if OS_ARG_CHK_EN > 0u
	
	if (pevent == (OS_EVENT *)0)                           /* Validate 'pevent'                        */
	{
		*perr = OS_ERR_PEVENT_NULL;
		return;
	}
	
#endif
	
	if (pevent->OSEventType != OS_EVENT_TYPE_MUTEX)        /* Validate event block type                */
	{
		*perr = OS_ERR_EVENT_TYPE;
		return;
	}
	
	if (OSIntNesting > 0u)                                 /* See if called from ISR ...               */
	{
		*perr = OS_ERR_PEND_ISR;                           /* ... can't PEND from an ISR               */
		return;
	}
	
	if (OSLockNesting > 0u)                                /* See if called with scheduler locked ...  */
	{
		*perr = OS_ERR_PEND_LOCKED;                        /* ... can't PEND when locked               */
		return;
	}
	
	/*$PAGE*/
	OS_ENTER_CRITICAL();
	pcp = (INT8U) (pevent->OSEventCnt >> 8u);              /* Get PCP from mutex                       */
	
	/* Is Mutex available?                      */
	if ((INT8U) (pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8) == OS_MUTEX_AVAILABLE)
	{
		pevent->OSEventCnt &= OS_MUTEX_KEEP_UPPER_8;       /* Yes, Acquire the resource                */
		pevent->OSEventCnt |= OSTCBCur->OSTCBPrio;         /*      Save priority of owning task        */
		pevent->OSEventPtr  = (void *)OSTCBCur;            /*      Point to owning task's OS_TCB       */
		
		if ((pcp != OS_PRIO_MUTEX_CEIL_DIS) &&
				(OSTCBCur->OSTCBPrio <= pcp))                  /*      PCP 'must' have a SMALLER prio ...  */
		{
			OS_EXIT_CRITICAL();                           /*      ... than current task!              */
			*perr = OS_ERR_PCP_LOWER;
		}
		
		else
		{
			OS_EXIT_CRITICAL();
			*perr = OS_ERR_NONE;
		}
		
		return;
	}
	
	if (pcp != OS_PRIO_MUTEX_CEIL_DIS)
	{
		mprio = (INT8U) (pevent->OSEventCnt & OS_MUTEX_KEEP_LOWER_8); /*  Get priority of mutex owner   */
		ptcb  = (OS_TCB *) (pevent->OSEventPtr);                  /*     Point to TCB of mutex owner   */
		
		if (ptcb->OSTCBPrio > pcp)                                /*     Need to promote prio of owner?*/
		{
			if (mprio > OSTCBCur->OSTCBPrio)
			{
				y = ptcb->OSTCBY;
				
				if ((OSRdyTbl[y] & ptcb->OSTCBBitX) != 0u)        /*     See if mutex owner is ready   */
				{
					OSRdyTbl[y] &= (OS_PRIO)~ptcb->OSTCBBitX;     /*     Yes, Remove owner from Rdy ...*/
					
					if (OSRdyTbl[y] == 0u)                        /*          ... list at current prio */
					{
						OSRdyGrp &= (OS_PRIO)~ptcb->OSTCBBitY;
					}
					
					rdy = OS_TRUE;
				}
				
				else
				{
					pevent2 = ptcb->OSTCBEventPtr;
					
					if (pevent2 != (OS_EVENT *)0)                 /* Remove from event wait list       */
					{
						y = ptcb->OSTCBY;
						pevent2->OSEventTbl[y] &= (OS_PRIO)~ptcb->OSTCBBitX;
						
						if (pevent2->OSEventTbl[y] == 0u)
						{
							pevent2->OSEventGrp &= (OS_PRIO)~ptcb->OSTCBBitY;
						}
					}
					
					rdy = OS_FALSE;                        /* No                                       */
				}
				
				ptcb->OSTCBPrio = pcp;                     /* Change owner task prio to PCP            */
#if OS_LOWEST_PRIO <= 63u
				ptcb->OSTCBY    = (INT8U) ( ptcb->OSTCBPrio >> 3u);
				ptcb->OSTCBX    = (INT8U) ( ptcb->OSTCBPrio & 0x07u);
#else
				ptcb->OSTCBY    = (INT8U) ((INT8U) (ptcb->OSTCBPrio >> 4u) & 0xFFu);
				ptcb->OSTCBX    = (INT8U) ( ptcb->OSTCBPrio & 0x0Fu);
#endif
				ptcb->OSTCBBitY = (OS_PRIO) (1uL << ptcb->OSTCBY);
				ptcb->OSTCBBitX = (OS_PRIO) (1uL << ptcb->OSTCBX);
				
				if (rdy == OS_TRUE)                        /* If task was ready at owner's priority ...*/
				{
					OSRdyGrp               |= ptcb->OSTCBBitY; /* ... make it ready at new priority.   */
					OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
				}
				
				else
				{
					pevent2 = ptcb->OSTCBEventPtr;
					
					if (pevent2 != (OS_EVENT *)0)          /* Add to event wait list                   */
					{
						pevent2->OSEventGrp               |= ptcb->OSTCBBitY;
						pevent2->OSEventTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX;
					}
				}
				
				OSTCBPrioTbl[pcp] = ptcb;
			}
		}
	}
	
	OSTCBCur->OSTCBStat     |= OS_STAT_MUTEX;         /* Mutex not available, pend current task        */
	OSTCBCur->OSTCBStatPend  = OS_STAT_PEND_OK;
	OSTCBCur->OSTCBDly       = timeout;               /* Store timeout in current task's TCB           */
	OS_EventTaskWait (pevent);                        /* Suspend task until event or timeout occurs    */
	OS_EXIT_CRITICAL();
	OS_Sched();                                       /* Find next highest priority task ready         */
	OS_ENTER_CRITICAL();
	
	switch (OSTCBCur->OSTCBStatPend)                  /* See if we timed-out or aborted                */
	{
		case OS_STAT_PEND_OK:
			*perr = OS_ERR_NONE;
			break;
			
		case OS_STAT_PEND_ABORT:
			*perr = OS_ERR_PEND_ABORT;               /* Indicate that we aborted getting mutex        */
			break;
			
		case OS_STAT_PEND_TO:
		default:
			OS_EventTaskRemove (OSTCBCur, pevent);
			*perr = OS_ERR_TIMEOUT;                  /* Indicate that we didn't get mutex within TO   */
			break;
	}
	
	OSTCBCur->OSTCBStat          =  OS_STAT_RDY;      /* Set   task  status to ready                   */
	OSTCBCur->OSTCBStatPend      =  OS_STAT_PEND_OK;  /* Clear pend  status                            */
	OSTCBCur->OSTCBEventPtr      = (OS_EVENT  *)0;    /* Clear event pointers                          */
#if (OS_EVENT_MULTI_EN > 0u)
	OSTCBCur->OSTCBEventMultiPtr = (OS_EVENT **)0;
#endif
	OS_EXIT_CRITICAL();
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【ROS导航Navigation】二 | 坐标系 | 定位 | 导航约束

目录 致谢&#xff1a;ROS赵虚左老师 一、通过里程计定位 二、通过传感器定位 三、坐标系变换 四、导航约束条件 1.硬件 2.软件 致谢&#xff1a;ROS赵虚左老师 Introduction Autolabor-ROS机器人入门课程《ROS理论与实践》零基础教程 参考赵虚左老师的实战教程 一、…

聚观早报 |英伟达发布H200;夸克发布自研大模型

【聚观365】11月15日消息 英伟达发布H200 夸克发布自研大模型 iQOO 12系列开启销售 红魔9 Pro配置细节 禾赛科技第三季度营收4.5亿元 英伟达发布H200 全球市值最高的芯片制造商英伟达公司&#xff0c;正在升级其H100人工智能处理器&#xff0c;为这款产品增加更多功能&am…

《网络协议》07. 其他协议

title: 《网络协议》07. 其他协议 date: 2022-10-07 18:24:02 updated: 2023-11-15 08:00:52 categories: 学习记录&#xff1a;网络协议 excerpt: IPv6、WebSocket、WebService&#xff08;SOAP&#xff0c;WSDL&#xff09;、HTTPDNS、FTP、邮件&#xff08;SMTP&#xff0c;…

PostgreSQL基本操作

目录 1.源码安装PostgreSQL 1.1.前置条件&#xff08;root下操作&#xff09; 1.1.1.卸载yum安装的postgresql 1.1.2.创建postgres用户 1.1.3.安装部分依赖 1.1.4.源码安装uuid 1.2.安装PostgreSQL 1.2.1.使用postgres用户管理PostgreSQL 1.2.2.下载解压postgres12源码…

SUMO道路封闭车辆绕行仿真实验【TraCI】

本文将介绍如何在 SUMO 交通模拟中动态选择车辆绕行指定道路。 绕道是城市驾驶中的常见现象&#xff0c;造成原因有很多&#xff0c;包括建筑和交通事故等。 无论出于何种原因&#xff0c;并非所有车辆都会选择避开这些道路&#xff1b; 有些人可能会毫不犹豫地直接开车过去&a…

Linux信号量以及基于环形队列的生产者消费者模型

文章目录 信号量信号量的接口初始化销毁等待信号量发布信号量 环形队列结合信号量设计模型 实现基于环形队列的生产者消费者模型Task.hppRingQueue.hppmain.cc效果对于多生产多消费的情况 信号量 信号量的本质是一个计数器 首先一份公共资源在实际情况中可能存在不同的线程可…

spring 整合 JUnit

大家好&#xff0c;本篇博客我们通过spring来整合JUnitt单元测试框架。 在之前篇章的测试方法中&#xff0c;几乎都能看到以下的两行代码&#xff1a; ApplicationContext context new ClassPathXmlApplicationContext("xxx.xml"); Xxxx xxx context.getBean(Xxx…

ctyunos 与 openeuler

ctyunos-2.0.1-220311-aarch64-dvd ctyunos-2.0.1-220329-everything-aarch64-dvd glibc python3 对应openEuler 20.03 LTS SP1

μC/OS-II---互斥信号量管理2(os_mutex.c)

目录 背景&#xff1a;优先级反转问题互斥信号量管理互斥信号量发出&#xff08;释放&#xff09;互斥信号量获取/无等待互斥信号量状态查询 背景&#xff1a;优先级反转问题 在高优先级任务等待低优先级任务释放资源时&#xff0c;第三个中等优先级任务抢占了低优先级任务。阻…

【京东API】商品详情+搜索商品列表接口

利用电商API获取数据的步骤 1.申请API接口&#xff1a;首先要在相应电商平台上注册账号并申请API接口。 2.获取授权&#xff1a;在账号注册成功后&#xff0c;需要获取相应的授权才能访问电商API。 3.调用API&#xff1a;根据电商API提供的请求格式&#xff0c;通过编程实现…

8.GC基本原理

目录 概述垃圾回收引用计数法 (Reference Counting)根可达分析算法 (GCRooting Tracing)对象引用类型强引用软引用弱引用 清除垃圾1.标记-清除算法 (Mark-Sweep)2.复制算法 (Copying)3.标记-整理算法 (Mark-Compact)分代回收 (Generational Collection) 垃圾回收器GC-串行收集器…

力扣每日一题-K个元素的最大和-2023.11.15

力扣每日一题&#xff1a;K个元素的最大和 题目链接:2656.K个元素的最大和 题目描述 代码思路 题目看完直接笑嘻了&#xff0c;还有这么容易的题。由题可知&#xff0c;第一次要找出最大值m&#xff0c;那由于把m1放回去&#xff0c;那第二次找的就是m1&#xff0c;以此类推…

DGL如何表征一张图

有关于DGL中图的构建 DGL 将有向图表示为一个 DGL 图对象。图中的节点编号连续&#xff0c;从0开始。我们一般通过指定图中的节点数&#xff0c;以及源节点和目标节点的列表&#xff0c;来构建这么一个图。 下面的代码构造了一个图&#xff0c;这个图有五个叶子节点。中心节点…

python 多线程池 CPU拉满

前言&#xff1a; 关于多线程的博客先前的博客如下&#xff1a; python线程join方法_python 线程join-CSDN博客 【精选】Python GIL锁_python gil 锁-CSDN博客 python函数运行加速_python os.listdir速度慢_两只蜡笔的小新的博客-CSDN博客 只需下面的模版即可: from multi…

CNCC 2023收官,Milvus Cloud与行业大咖共话向量数据库系统

近期,CNCC 2023 在沈阳圆满结束,紧凑、前沿的 129 场技术论坛让人印象深刻。据悉,这 129 场技术论坛涵盖人工智能、安全、计算+、软件工程、教育、网络、芯片、云计算等 30 余个方向。Zilliz 受邀参与【智能时代的大数据系统】技术论坛。 智能时代的到来,无疑给社会经济和日…

前端 vue 面试题 (一)

文章目录 v-if,v-show差别v-for和v-if虚拟dom解决什么问题vue的data为什么返回函数不返回对象比较vue&#xff0c;reactvue双向绑定原理vue虚拟dom 的diff算法vue 虚拟dom的diff算法的时间复杂度vue2与vue3的区别vue数据缓存&#xff0c;避免重复计算单页应用怎么跨页面传参vue…

基于springboot实现学生选课平台管理系统项目【项目源码】

系统开发平台 在该地方废物回收机构管理系统中&#xff0c;Eclipse能给用户提供更多的方便&#xff0c;其特点一是方便学习&#xff0c;方便快捷&#xff1b;二是有非常大的信息储存量&#xff0c;主要功能是用在对数据库中查询和编程。其功能有比较灵活的数据应用&#xff0c…

队列与堆栈:原理、区别、算法效率和应用场景的探究

队列与堆栈&#xff1a;原理、区别、算法效率和应用场景的探究 前言原理与应用场景队列原理应用场景&#xff1a; 堆栈原理应用场景递归原理和堆栈在其中的作用递归原理堆栈作用 队列与堆栈区别队列堆栈算法效率 前言 本文主要讲解数据结构中队列和堆栈的原理、区别以及相关的…

解析数据洁净之道:BI中数据清理对见解的深远影响

本文由葡萄城技术团队发布。转载请注明出处&#xff1a;葡萄城官网&#xff0c;葡萄城为开发者提供专业的开发工具、解决方案和服务&#xff0c;赋能开发者。 前言 随着数字化和信息化进程的不断发展&#xff0c;数据已经成为企业的一项不可或缺的重要资源。然而&#xff0c;这…

0基础学习VR全景平台篇第121篇:认识视频剪辑软件Premiere

上课&#xff01;全体起立~ 大家好&#xff0c;欢迎观看蛙色官方系列全景摄影课程&#xff01; 大家好&#xff0c;这节课是带领大家认识认识我们的剪辑软件Premiere&#xff0c;一般简称是PR。 &#xff08;PR界面&#xff09; 我们首先打开PR&#xff0c;第一步就是要创建…
最新文章