第4章第5节 任务创建和任务删除钩…

VxWorks中高精度实时时钟的实现及C语言汇编混合编程  最近一个项目中需要在VxWorks下使用一个高精度实时时钟,要求精度为1ms,溢出时间大于5小时。VxWorks提供系统时钟,该时钟在操作系统启动后开始计数,精度为1个tick,可以通过tickGet()获取当前计数值。因为系统时钟默认工作频率为60Hz,则1个tick相当于16.7ms,不符号我们的精度要求。虽然可以通过sysClkRateSet(1000),把精度提高到1ms,但1kHz 阅读详情


目前更新到5.3节,请在
http://dl.dbank.com/c02ackpwp6下载5.3节的全部文档

本节源代码请在http://dl.dbank.com/c0t7gmgx2q下载

 

第5节 任务创建和任务删除钩子函数

上节增加了任务切换钩子功能,打印出任务切换的信息,本节将增加任务创建钩子函数和任务删除钩子函数,分别打印出任务创建和删除的信息。

 

任务创建和删除钩子函数的原理与任务切换钩子函数的原理是一样的,都是需要定义一个与被挂接函数类型一致的指针型全局变量,使用钩子添加函数将被执行的函数挂接到钩子变量上,不同的是任务创建钩子函数在任务创建后打印,任务删除钩子函数在任务删除后打印。

钩子变量定义如下:

VFHCRT gvfTaskCreateHook;

VFHDLT gvfTaskDeleteHook;

VFHCRT和VFHDLT的定义为:

typedef void    (*VFHCRT)(M_TCB*);

typedef void    (*VFHDLT)(M_TCB*);

被挂接的任务创建函数如下,与任务创建全局变量gvfTaskCreateHook类型一致,它会打印被创建函数的名称及创建的时间。

00071  void TEST_TaskCreatePrint(M_TCB* pstrTcb)

00072  {

00073      

00074      if((M_TCB*)NULL != pstrTcb)

00075      {

00076          DEV_PutStrToMem((U8*)"\r\nTask %s is created! Tick is: %d",

00077                          pstrTcb->pucTaskName, MDS_SystemTickGet());

00078      }

00079      else 

00080      {

00081          DEV_PutStrToMem((U8*)"\r\nFail to create task! Tick is: %d",

00082                          MDS_SystemTickGet());

00083      }

00084  }

 

被挂接的任务删除函数如下,与任务删除全局变量gvfTaskDeleteHook类型一致,它会打印被删除函数的名称及删除的时间。

00104  void TEST_TaskDeletePrint(M_TCB* pstrTcb)

00105  {

00106      DEV_PutStrToMem((U8*)"\r\nTask %s is deleted! Tick is: %d",

00107                      pstrTcb->pucTaskName, MDS_SystemTickGet());

00108  }

 

如果需要使用钩子创建函数则需要在创建任务的函数MDS_TaskCreate里增加钩子函数代码,如下:

00023  M_TCB* MDS_TaskCreate(U8* pucTaskName, VFUNC vfFuncPointer, U8* pucTaskStack,

00024                        U32 uiStackSize, U8 ucTaskPrio, M_TASKOPT* pstrTaskOpt)

00025  {

00026  

……       ……

00094  

00095      

00096      if((MDS_RootTask != vfFuncPointer) && (MDS_IdleTask != vfFuncPointer))

00097      {

00098  #ifdef MDS_INCLUDETASKHOOK

00099  

00100          

00101          if((VFHCRT)NULL != gvfTaskCreateHook)

00102          {

00103              gvfTaskCreateHook(pstrTcb);

00104          }

00105  

00106  #endif

00107  

00108          

00109          MDS_TaskSwiSched();

00110      }

00111  

00112      return pstrTcb;

00113  }

00026~00094行,代码与上节完全一样。

00096行,只有非系统任务才执行任务创建钩子函数。

00101~00104行,若挂接了任务创建钩子函数则执行。

 

本节我们需要增加一个删除任务的函数MDS_TaskDelete,用它来删除任务,在删除任务时可以执行挂接的任务删除钩子函数。

任务创建时在任务栈里创建了TCB,TCB中的ready节点和delay节点可能会挂接到ready表和delay表,我们只要将任务从ready表和delay表拆除,操作系统就无法再调度这个任务了,这样就可以删除该任务。删除后任务的任务栈中的数据还是存在的,但由于任务已经无法与ready表和delay表关联,因此这些数据就变成了无效数据。任务删除时,任务所使用的任务栈内存应该也被释放掉,但目前任务栈的内存是由用户申请的而不是由操作系统申请的,因此需要用户自行释放任务栈内存,操作系统不进行管理。以后任务栈由操作系统申请时,MDS_TaskDelete函数才负责释放这部分内存。

00121  U32 MDS_TaskDelete(M_TCB* pstrTcb)

00122  {

00123      M_CHAIN* pstrChain;

00124      M_CHAIN* pstrNode;

00125      M_PRIOFLAG* pstrPrioFlag;

00126      U8 ucTaskPrio;

00127      U8 ucTaskSta;

00128  

00129      

00130      if(NULL == pstrTcb)

00131      {

00132          return RTN_FAIL;

00133      }

00134  

00135      

00136      if(pstrTcb == gpstrIdleTaskTcb)

00137      {

00138          return RTN_FAIL;

00139      }

00140  

00141      (void)MDS_IntLock();

00142  

00143      

00144      ucTaskSta = pstrTcb->strTaskOpt.ucTaskSta;

00145  

00146      

00147      if(TASKREADY == (TASKREADY & ucTaskSta))

00148      {

00149          

00150          ucTaskPrio = pstrTcb->ucTaskPrio;

00151          pstrChain = &gstrReadyTab.astrChain[ucTaskPrio];

00152          pstrPrioFlag = &gstrReadyTab.strFlag;

00153  

00154          

00155          (void)MDS_TaskDelFromSchedTab(pstrChain, pstrPrioFlag, ucTaskPrio);

00156      }

00157  

00158      

00159      if(DELAYQUEFLAG == (pstrTcb->uiTaskFlag & DELAYQUEFLAG))

00160      {

00161          

00162          pstrNode = &pstrTcb->strDelayQue.strQueHead;

00163  

00164          

00165          (void)MDS_ChainCurNodeDelete(&gstrDelayTab, pstrNode);

00166      }

00167  

00168      (void)MDS_IntUnlock();

00169  

00170  #ifdef MDS_INCLUDETASKHOOK

00171  

00172      

00173      if((VFHDLT)NULL != gvfTaskDeleteHook)

00174      {

00175          gvfTaskDeleteHook(pstrTcb);

00176      }

00177  

00178  #endif

00179  

00180      

00181      MDS_TaskSwiSched();

00182  

00183      return RTN_SUCD;

00184  }

00121行,函数有2种返回值,RTN_SUCD代表任务删除成功,RTN_FAIL代表任务删除失败。入口参数pstrTcb是需要被删除的任务的TCB指针。

00130~00133行,入口参数检查,入口参数为空则返回失败。

00136~00139行,入口参数检查,若删除idle任务则返回失败。

00141行,锁中断。下面将操作ready表和delay表,为防止多个任务同时操作这两个表,需要锁中断。

00144行,获取被删除任务的当前任务状态。

00147~00156行,若该任务在ready表中则从ready表删除。

00159~00166行,若该任务在delay表中则从delay表删除。

00168行,调度表操作完成,解锁中断。

00170~00178行,若挂接了任务删除钩子函数则执行该函数。

00181行,任务已经被删除,需要重新调度一次任务。

 

本节内容较少,主要内容已经介绍完毕。本节仍使用上节的3个功能验证函数,与上节不同的是在8000 ticks的时候TEST_TestTask3任务会被root任务删除,在10000 ticks时root任务也会被自己删除。

00014  void MDS_RootTask(void)

00015  {

00016      M_TCB* pstrTcb;

00017      M_TASKOPT strOption;

00018  

00019      

00020      DEV_SoftwareInit();

00021  

00022      

00023      DEV_HardwareInit();

00024  

00025      

00026      (void)MDS_TaskCreate((U8*)"Test1", (VFUNC)TEST_TestTask1, gaucTask1Stack,

00027                           TASKSTACK, 2, (M_TASKOPT*)NULL);

00028  

00029      

00030      strOption.ucTaskSta = TASKREADY;

00031      (void)MDS_TaskCreate((U8*)"Test2", (VFUNC)TEST_TestTask2, gaucTask2Stack,

00032                           TASKSTACK, 3, &strOption);

00033  

00034      

00035      strOption.ucTaskSta = TASKDELAY;

00036      strOption.uiDelayTick = 2000;

00037      pstrTcb = MDS_TaskCreate((U8*)"Test3", (VFUNC)TEST_TestTask3, gaucTask3Stack,

00038                               TASKSTACK, 1, &strOption);

00039  

00040      (void)MDS_TaskDelay(8000);

00041  

00042      

00043      (void)MDS_TaskDelete(pstrTcb);

00044  

00045      (void)MDS_TaskDelay(2000);

00046  

00047      

00048      (void)MDS_TaskDelete(MDS_CurrentTcbGet());

00049  }

root任务起来后创建了3个任务,我们会看到这3个任务创建过程的打印,随后任务运行的过程与上节一致。当系统运行到8000 ticks时,TEST_TestTask3任务会被删除,我们可以看到TEST_TestTask3任务被删除的打印信息,此后就只有TEST_TestTask1和TEST_TestTask2任务在运行了。到10000 ticks时,root任务调用MDS_TaskDelete函数将自己删除,无需再调用MDS_TaskDelay(DELAYWAITFEV)函数进入永久delay状态。

本节运行结果截图如下:

第4章第5节 <wbr>任务创建和任务删除钩子函数

图 48  带有任务创建、切换和删除过程的打印

读者可以访问http://blog.sina.com.cn/ifreecoding网站下载视频,观看全部数据的打印过程,可以看到实际运行的结果与我们上面推断的结果是一致的。

使用工具软件将任务切换过程的数据解析为图形,结果如下图所示:

 第4章第5节 <wbr>任务创建和任务删除钩子函数

图 49  4.5节任务切换过程图

从图中可以清晰的看到2000 ticks时TEST_TestTask3任务结束delay状态,开始运行,在8000 ticks时,root任务delay时间耗尽,操作系统切换到root任务,删除了TEST_TestTask3任务,在10000 ticks时,root任务delay时间再次耗尽,操作系统切换到root任务,删除了自己。此后只剩下TEST_TestTask1和TEST_TestTask2任务切换运行。

音频测试专题 麦克风与扬声器单体测试指标及整机性能测试概述 麦克风测试指标包括频率响应、灵敏度、指向性等10项关键参数,用于评估声音捕捉和信号转换性能。扬声器测试包含频率响应、灵敏度等12项指标,涉及声学特性和物理参数。整机性能测试覆盖安静、嘈杂和正常三种环境,重点检测麦克风底噪、清晰度、扬声器音量及通话质量等12项功能指标。两类单体测试与整机测试共同构成完整的音频设备质量评估体系,确保产品在不同场景下的性能表现。 阅读详情

相关推荐

ADS中HB仿真自动优化报错问题解决心得

在ADS HB仿真中自动优化出现报错被强制暂停,解决方法如下

yyyyyyyyyyjy的博客 6539

vxworks点滴记录

 MPC852---大端模式 vxworks压缩   deflate &lt;vxWorks_rom.bin&gt; vxworks.gz      ---- D:\Tornado2.2\host\x86-win32\bin  inflate(vxworksImage, upgrade_package, UPGRADE_PACKAGE_SIZE)   ---代码函数调用 VxWorks中库...

学海无涯,回头是岸........ 1万+

S32K144 ADC硬件触发+DMA传输实战:从寄存器配置到数据采集全流程

本文详细解析了S32K144微控制器中ADC硬件触发与DMA传输的协同工作机制,提供了从寄存器配置到数据采集的全流程实战指南。通过PDB定时触发ADC转换,并利用DMA实现数据自动搬运,构建了高效、实时的汽车级数据采集系统,有效释放CPU资源,满足汽车电子应用的严苛要求。

weixin_29194693的博客 475

2016年7月问题记录与总结

1.norflash的读写 Norflash中的程序可以直接运行在norflash,而不需要拷贝到内存里面再去运行,这一点区别于nand flash。Nor的读和ram相似,提供数据的地址和给出正确的数据。但是写操作之前需要先进行擦的操作。 2.文件系统是干嘛的 文件系统是操作系统用于明确存储设备或者分区上的文件的方法和数据结构,就是组织文件的方法,各个文件系统我的理解是对存储空间的管理和抽

Deep_l_zh的博客 2156

Windows打印体系结构之Windows内置打印驱动程序

时间是一种很残酷的东西,它只会冲淡能够冲淡的,但也会洗尽铅华帮你留下该留下的。1.3.4、Windows内置打印驱动程序现在的Windows下的打印机驱动程序通常分为V4打印机驱动程序(V4 Printer Driver)、XPS打印机驱动程序(XPSDrv)、微软通用打印机驱动程序(Microsoft UniversalPrinter Driver)、微软PostScri...

weixin_34309435的博客 2254

【Zephyr 系列 29】低功耗调试指南:电流测量、系统睡眠与功耗分析

Zephyr低功耗调试指南(150字摘要) 针对物联网设备续航需求,本文解析Zephyr低功耗调试方法:1️⃣ 机制:启用PM子系统和tickless idle,配置睡眠策略;2️⃣ 测量:推荐功耗分析仪捕捉μA级电流波动;3️⃣ 优化:管理唤醒源(如GPIO/RTC)、调整BLE广播/连接参数,挂起闲置外设;4️⃣ 分析:建立功耗文档,对比不同模式电流(如待机0.6mA vs广播3.2mA)。强调低功耗需系统性设计,初期即需纳入测试流程。下期将探讨Zephyr OTA升级实现。

hemoparrot的专栏 1180

linux tick异常变化,linux tickGet()

tickGet()返回的是从系统启动开始tick计数后的总的tick数目。tick是啥,是“滴答”,它是一个数值量,本身不能代表时间。如果说要知道tick增加一个代表多少时间的话,那就要看系统的时钟率了。在Shell下,sysClkRateGet()可以返回这个始终率的值。比如60。啥意思呢,就是1秒钟产生60个tick。操作系统调度是基于这个tick的,这在硬件上是个优先级很高(除了NMI以外都...

weixin_42174176的博客 924

【NIPS 2022】时序精选论文07|Non-stationary Transformers: 引入非平稳性信息的平稳化序列预测模型(代码解读附源码)

整体代码框架基本上与传统 Transformer 类似,基本上只有在内嵌的注意力机制模块有区别,因此这里只对关键部分进行讲解,代码整体框架可参考 Transformer。非平稳时序很难预测,尤其对模型泛化性影响很大,试想下推理阶段的数据分布变了,模型很难适应这种变化。,比如很早以前的差分就是一种平稳化操作。序列平稳化能增强数据的可预测性,但这时也会带来一个问题,叫。,通过MLP层进行定义,使得参数可学习,以便于更好的融合到注意力网络中。代码中整体注意力的计算方式与原生Transformer类似,

ViolenceTemper的博客 1493

第4章第6节&nbsp;任务自结束

目前更新到5.3节,请在http://dl.dbank.com/c02ackpwp6下载5.3节的全部文档 本节源代码请在http://dl.dbank.com/c0ss54iddw下载     第6节 任务自结束 上节增加了删除任务的函数MDS_TaskDelete,任务可以调用该函数结束其它任务或自身任务的运行。在前面章节我们说过,目前任务还不具备自结束功能,需要使用类似while的结

ifreecoding的博客 466

Power EM与Signal EM解决办法与原理分析

1.面对power EM,首先检查missing via,补全via,还可以加宽,加密局部power mesh,一些power IO出pin有power EM问题,可以叠加多层线和垂直方向补power形成网络降低并联电阻和提供更多电流通路解决,这种方法还可以降低ir drop。3.先进工艺有一个via ladder的方法可以解决power/signal em问题,clock cell出pin绕线或者power rail连接power stripe通过搭梯子的方式连接,原理还是分流。

m0_61544122的博客 4746

Vue2 - 详细实现解析Markdown内容生成侧边栏Toc目录索引,识别文章内容根据大标题/小标题自动生成多级文章目录,点击目录导航时跳转到文章内容对应的锚点位置带过渡动画,滑过锚点时高亮对应标题

vue2,nuxt2,Markdown,目录,文章目录锚点,滚动高亮导航文字,根据页面滚动高亮显示目录的侧边栏,自动提取标题生成右侧目录,vuemarkdown解析并生成目录,滚动页面的时候文章目录跟着选中效果,侧边栏滚动跟随页面,右边目录固定,左边内容可以滚动并且与左边目录联动,实现监听滚动,锚点定位,文章目录滚动跟随高亮,右边菜单点击目录滚动到对应标题,报错,渲染失败,文章内容,读取#标题符号,自动生成一个目录树,自动生成Toc目录,博客内容生成目录索引,资讯文章,生成锚点目录树TOC,详细示例代码教

🏆 前端领域优质创作者 3669

第4章第4节&nbsp;任务切换钩子函数

目前更新到5.3节,请在http://dl.dbank.com/c02ackpwp6下载5.3节的全部文档 本节源代码请在http://dl.dbank.com/c0ddwgf0k5下载   第4节 任务切换钩子函数 上节,我们引入了任务的delay态,通过最后例子的打印可以看到任务在交替运行,但这个打印只发生在每个任务每次循环的开始,看不到中间运行过程中任务的切换过程。 本小节将引入任

ifreecoding的博客 1142

【YOLOv11工业级实战】15. YOLOv11海洋监测实战:珊瑚礁健康评估(水下图像增强|机器人搭载)

摘要:本文针对珊瑚礁健康评估的海洋监测需求,基于YOLOv11提出解决方案,聚焦水下色偏、悬浮物干扰、珊瑚形态复杂三大难题。引用全球珊瑚礁监测网络(GCRMN)标准,采用CoralNet数据集,通过Jaffe-McGlamery物理模型引导增强与悬浮物去除算法,在浑浊水域(能见度<5m)实现87.3%的健康珊瑚识别率,藻类误判率低至7.2%。介绍了以BlueROV2水下机器人和Jetson AGX Orin为核心的部署方案,结合水下SLAM定位技术,实现珊瑚健康的实时评估与三维覆盖率计算。

专注于人工智能、软件开发、工控自动化、工厂数字化及智能化等领域,希望和大家共同进步! 1644

第3章第5节&nbsp;发布Wanlix操作系统

​源代码请在https://github.com/ifreecoding/MbedRtos.git下载 第5节发布Wanlix操作系统 经过前面3.1~3.3节循序渐进的开发,我们已经使Wanlix操作系统具备了最基本的任务切换功能,并在3.4节使用Wanlix开发了一个交通红绿灯控制系统,到此为

ifreecoding的博客 813

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

第4章第7节&nbsp;二进制信号量(三)

目前更新到5.3节,请在http://dl.dbank.com/c02ackpwp6下载5.3节的全部文档 本节源代码请在http://dl.dbank.com/c0fp2g5z9s下载   图53列出了多个不同状态的任务与这些调度表之间的关系,任务1被信号量sem1阻塞,处于非永久pend态,strDelayQue结构中的strQueHead节点被挂接到delay表,strTcbQue结构中的

ifreecoding的博客 647

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

1&nbsp;任务管理&nbsp;&nbsp;--转载于电子工程世界

uC/OS-II 中最多可以支持64 个任务,分别对应优先级0~63,其中0 为最高优先级。63为最低级,系统保留了4个最高优先级的任务和4个最低优先级的任务,所有用户可以使用的任务数有56个。    uC/OS-II提供了任务管理的各种函数调用,包括创建任务,删除任务,改变任务的优先级,任务挂起和恢复等。    系统初始化时会自动产生两个任务:一个是空闲任务,它的优先级最低,该任务仅给一个

不积跬步无以至千里,千里之行始于足下! 898

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

了解VS2008&nbsp;和.NET&nbsp;Framework3.5最…

关键词: XAML:扩展的应用标记语言. XBAP: XAML的应用浏览器. JSON:(JavaScript Object Notation) 是一种轻量级的数据交换格式。易于人阅读和编写,同时也易于机器解析和生成。它基于, 的一个子集。 JSON采用完全独立于语言的文本格式,但是也使用了类似于C语言家族的习惯(包括C, C++, C#, Java, JavaScript, Perl, P

200

我的linux学习10&nbsp;例行命令

cron:例行任务,工作持续干下去。 at:工作执行一次就从linux系统任务分配中取消。 首先开启atd服务(使用root权限):/etc/init.d/atd restart 设置开机启动:chkconfig --level 35 atd on 先找/etc/at.allow,写作这个文件中的用户才能使用at,如果没有这个文件则找/etc/at.deny,写在里面的用户不能使用at,如

zhexiao 476

oracle&nbsp;存储过程procedure&nbsp;初始&nbsp;--…

如何开发ORACLE存储过程(引自:http://tech.it168.com/a2009/0305/267/000000267674.shtml)   在我的上一个银行项目中,我接到编写ORACLE存储过程的任务,我是程序员,脑袋里只有一些如何使用CALLABLE接口调用存储过程的经验,一时不知如何下手,我查阅了一些资料,通过实践发现编写ORACLE存储过程是非常不容易的工作,即使上路以后,

小江湖 761

linux系统主分区&nbsp;扩展分区&nbsp;和&nbsp;逻辑…

一、分割区概述    在MicroSoft Windows中同一颗硬盘的各个槽其实就代表了不同的分割区。一般人通常都喜欢把硬盘分割成C区和D区,若需要重新安装系统的时候,就会把所有数据和文件都放在D区,只要把系统碟C区格式化删除,再重装系统,如此数据就不用备份出来,可以很容易完成重装且保存数据。同样地,在GNU/Linux也是一样,我们喜欢把重要的目录分别放在不同的分割区,这样子系统出了问题也

li10080115的专栏 583

win&nbsp;7&nbsp;快捷键

一、常见用法:  F1 显示当前程序或者windows的帮助内容。  F2 当你选中一个文件的话,这意味着“重命名”  F3 当你在桌面上的时候是打开“查找:所有文件” 对话框  F10或ALT 激活当前程序的菜单栏  windows键或CTRL+ESC 打开开始菜单  CTRL+ALT+DELETE 在win9x中打开关闭程序对话框  DELETE 删除

Android攻城狮 519

数据挖掘——总结&nbsp;【未完待续】

一、            数据挖掘 有这么一个说法:在数据挖掘中,至少60%的费用可能要花在步骤(1)信息收集阶段,而其中至少60%以上的精力和时间花在了数据预处理过程中。   数据挖掘通常需要有8个步骤: l  信息收集 l  数据集成 l  数据规约 l  数据清理 l  数据变换 l  数据挖掘实施过程 l  模式评估 l  知识表示

micklf的博客 976

[转]深入Django(1):&nbsp;通用视图&nbsp;(generic&nbsp;views)

http://blog.youkuaiyun.com/thinkinside/article/details/7251130   如果对Django的基础部分尚不熟悉,请参考《Django实战》系列。 欢迎访问Django专栏:http://blog.youkuaiyun.com/column/details/django.html   内容提要 1. 回顾Django的视图函数(view functio...

iteye_19700的博客 172

access&nbsp;转&nbsp;SQL&nbsp;要注意的问题

1,由于SQL2000里面没有“自动编号“,所以你的以“自动编号“设置的字段都会变成非空的字段,这就必须手工修改这些字段,先设为主键,然后要把数据类型改为"bigint",并把他的“标示“选择“是“,种子为“1“,增量为“1“, 2,另外,ACCESS2000转换成SQL2000后,原来属性为“是/否“的字段将被转换成非空的“bit“,这时候你必须修改成自己想要的属性了; 3,另外,大家要注意

php菜鸟技术天地 561
上一篇: 第4章第4节&nbsp;任务切换钩子函数
下一篇: 第4章第6节&nbsp;任务自结束
ifreecoding
博客等级 码龄15年 148粉丝 33原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值