版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、rtx51小型实时操作系统的应用体会2007年06月27日 星期三 23:53最近在做设计的时候老遇到一些几个任务需要同时进行的情况,刚开始想自己去做一个多任务的程序(因为称不上系统),想用一个脉冲计数的方法来实现多任务切换,但是感觉实现起来比较麻烦。无意中发现了51单片机下个rtx51实时操作系统(本人以前不知道的),后来就去找相关资料。发现这方面的资料在网上很少,也很杂乱。经过一段时间的学习,我有了个大概的了解。下面给大家讲述一下:RTX51是一个用于8051系列处理器多任务实时操作系统。RTX51可以简化那些复杂而且时间要求严格的工程的软件设计工作。有二个不同的RTX51版本可以利用:R
2、TX51 Full 使用四个任务优先权完成同时存在时间片轮转调度和抢先的任务切换 RTX51工作在与中断功能相似的状态下 信号和信息可以通过邮箱系统在任务之间互相传递 你可以从一存池中分配和释放内存 你可以强迫一个任务等待中断 超时或者是从另一个任务或中断发出的信号或信息RTX51 Tiny 是一个 RTX51的子集 它可以很容易地在没有任何外部存储器的单片8051系统上运转。 除了下列例外 RTX51 Tiny支持许多在RTX51中的特征。RTX51 Tiny仅支持时间片轮转任务切换和使用信号进行任务切换 不支持抢先式的任务切换。不包括消息历程。没有存储器池分配程序 。RTX51使用一个80
3、51硬件计时器中断作为定时程序。 产生的周期性中断用于驱动 RTX51时钟。 RTX51不需要在你的程序中拥有一个主函数 它将自动开始执行任务 0 如果你确实有一个主函数 你必须利用 RTX51 Tiny中的 os_create_task函数或 RTX51中的 os_start_system函数手工启动 RTX51。 下列例子显示一个只使用时间片轮转任务调度的简单的 RTX51应用程序 在本程序里的二个任务是简单计数器回路 rtx51开始执行函数名为 job0的任务 0 。 这些功能添加了另一个叫做 job1任务。 在 job0运行一会儿以后 RTX51切换到 job1。 在 job0运行一会
4、儿以后、RTX51转回到job0。 这个过程将不确定地重复下去 #include <rtx51tny.h> int counter0; int counter1; void job0 (void) _task_ 0 os_create (1); /* mark task 1 as ready */ while (1) /* loop forever */ counter0+; /* update the counter */ void job1 (void) _task_ 1 while (1) /* loop forever */ counter1+; /* update the
5、 counter */ 今天夜已很深了,明早还有考试,对不起了,不写了。我介绍几个资料的下载地址,大家自己去看吧!【转】 KEIL RTX51 TINY内核的分析与应用2011年04月18日 星期一 19:28转载自 lan042最终编辑 lan042特性:最大任务数:16最大激活的任务数:16所需的CODE空间:最大900ByteDATA空间:7字节STACK空间:3字节XDATA空间:0字节时钟数:0个系统时钟分频:1000-65535中断嵌套:小于20层任务切换时间:100-700时钟周期工具要求:以下软件应用需要用 RTX51 TinyC51纺编译器A51 Marco Assemble
6、rBL51 Linker or Lx51 LinkerRTX51TNY.LIB 和 RTX51BT.LIB必需存储在库路径上,一般是文件夹KEILC51LIBRTX51TNY.H包含文件必须存储在包含文件路径上,一般是文件夹KEILC51INC目标要求:应用程序可能需要外部分的数据存储空间,但内核并不需要外部存储空间KEIL C51支持各种存储模式:选择存储模式只影响应用程序的存的数据存储,操作系统的变量和堆栈只存在于51的内存中,即DATA和IDATA,一般情况下,RTX51 Tiny的应用只需要小存储模式在RTX51 Tiny中每个应用程序运行的时间是固定的,支持cooperative任务
7、切换和round-robin任务切换,不支持preemptive任务切换和任务优先级。如果应用程序需要preemptive任务切换则必须使用RTX51 FULL-Time Executive版本。中断:RTX51 Tiny的工作与中断函数是并行工作的。中断服务程序可以向RTX51 Tiny的任务发信号(使用函数isr_send_signal),也可以置位作任务的Ready标志(使用函数isr_set _ready)在RTX51 Tiny中必须使能中断,但是在RTX51 Tiny没有中断服务管理RTX51 Tiny使用Timer0和Timer0中断。全局中断禁能和Timer0中断禁能会使RTX5
8、1 Tiny停止工作,所以只能在短时间内禁能中断。可重入函数非可重入的C函数不能被多个任务或中断过程调用。非可重入的函数的参数和变量保存在静态存储空间中,当它们同时被多个任务调用时,这些参数和变量就可能被覆盖了。你可以在多任务系统中调用非可重入函数如果你能保证他们不会同进行。不过,这就意味着必须能 round-robin任务调度,并且非可重入函数不可以调用RTX51 Tiny的功能函数。只使用寄存器就量和自动变量的函数自然地就是可重入函数,可以毫无限制地在RTX51 Tiny中调用。C51编译器支可重入函数。可重入函把参数和局部变量保存在堆栈中。这样就可以保证他们被多个任务同时使用。RTX51
9、 Tiny并不管理可重入函数的堆栈,因些,如果你在应用程序中使用了可重入函数,你必须确保这些功能函数不调用任务RTX51 Tiny的系统函数,并且可重入函数不会被round-robin任务切换所中断。注意:如果你打自在多个任务或中断中调用可重入或非可重入函数必须禁止round-robin任务切换。运行时库:所有的C51可重入运行时库可能毫无限制地在所用任务中使用。非可重入时库的要与可重入函数的要求相同。多个数据指针C51编译器允许使用多个数据指针。RTX51 Tiny对他们不进行管理,所以在应用中你必须小心Essentially,你必须确保在改变数据指针时不会发生round-robin切换。注
10、意:当你打算使用多数据指针时你最好禁止round-robin切换。算术单元(说法与多个数据指针相同)工作寄存器组RTX51 Tiny的所有任务都使用工作组0。 因些,所有的任务都必须使用C51默认的编译选项:REGISTERBANK (0)中断函数可能会使用其他的工作寄存器组。然而RTX51 Tiny在工作寄存器组中永远需要6个字节。RTX51 Tiny在工作寄存器组中使用的这些字节可以参考配置文件单个任务程序嵌入式和标准C程序都mian()函数开始。在入式应用中, main函数一般都是一个死循环,我们也可以把它看作是一个连续执行的任务。如:void main (void)while (1)
11、/* repeat forever */do_something (); /* execute the do_something 'task' */在这个例子中,do_something ()函数可以认为是一个单任务,既然只有一个任务在执行,就不需要具有多任务能力或多任务操作系统。多任务程序许多成熟的C程序使用一种叫做pseudo多任务的策略,把多个作协做为一循环,如:void main (void)int counter = 0;while (1) /* repeat forever */check_serial_io (); /* check for serial inpu
12、t */process_serial_cmds (); /* process serial input */check_kbd_io (); /* check for keyboard input */process_kbd_cmds (); /* process keyboard input */adjust_ctrlr_parms (); /* adjust the controller */counter+; /* increment counter */在这个例子中,每个函数完成一个独立的操作或任务。这些函数是一个一个顺序执行的当添加更多的任务时调度就行了一个问题。比方说,如果函数pr
13、ocess_kbd_cmds执行的时间比较长,主循环就需要很长时间才能再执行到函数check_serial_io ,这时候串口的数据可能会丢失。当然check_serial_io 可以在主循环中多调用几次来解决这个问题,但最终这种方法并不是最有效的。RTX51 Tiny的程序当使用RTX51 Tiny时,你可以为每一个任务生成一个独立的函数,如:void check_serial_io_task (void) _task_ 1/* This task checks for serial I/O */void process_serial_cmds_task (void) _task_ 2/*
14、This task processes serial commands */void check_kbd_io_task (void) _task_ 3/* This task checks for keyboard I/O */void process_kbd_cmds_task (void) _task_ 4/* This task processes keyboard commands */void startup_task (void) _task_ 0os_create_task (1); /* Create serial_io Task */os_create_task (2);
15、/* Create serial_cmds Task */os_create_task (3); /* Create kbd_io Task */os_create_task (4); /* Create kbd_cmds Task */os_delete_task (0); /* Delete the Startup Task */在这个例子中,每个函数定义了一个RTX51 Tiny的任务。RTX51 Tiny程序没有主C函数,RTX51 Tiny首先执行任务0。作为一个典型的应用,任务0只是简单地用来生成其他的所有任务。工作原理RTX51 Tiny使用并管理你的目标资源,这一部分讲述RTX
16、51 Tiny如何使用这些资源。RTX51 Tiny的许多方面都可以根据工程需要进行配置。时间片中断RTX51 Tiny使用标准的8051的定时器0来产生定时中断。这个中断就是RTX51 Tiny的时钟片。RTX51 Tiny运行时库中用的时等待时间都是以这个时间片为单位的RTX51 Tiny的默认的时间片是10000个机器周期。因此,标准的8051运行在12MHz的时钟下的时候,时间片有0.01S或着说是100Hz。这个值可以在CONF_TNY.A51 配置文件中更改。注意:你在以RTX51 Tiny时间片中断中编辑你自己的代码,参考:CONF_TNY.A51任务:RTX51 Tiny可以看
17、作是一个任务切换器。要生成RTX51 Tiny程序,你必须生成一个具有一个或多个任务的应用。以下细节可以帮你更快地理解RTX51任务必须用C语言编写,并且用Keil C51支持的关键词声明RTX51 Tiny使用准确的状态维护任务。同时只有一个任务可以处于运行状态可能会有多个任务处于就绪,等待,删除或超时状态空闲任务总是处于就绪状态,即使使用你的所有任务都处于block状态任务管理RTX51 Tiny的任务总是处于以下状态中一确定的状态RUNNING:任务处于运行状态,os_running_task_id返回正在运行的任务的编号READY:任务处于就绪状态。当一个正在运行的任务运行完毕,RTX
18、51 Tiny就会启动下一个就绪状态的任务。一个任务可以通设置他的READY标志位os_set_ready or isr_set_ready使它立即进入就绪状态(即使它可能正在等待时间到或等一个信号)WAITTING:处于等待一个事件的任务就处于等待状态。当所等待的事件发生后,任务就转换到就绪状态,函数os_wait用来使一个作任务进行等待状态DELETED:没有开始运行的任务或被删除的任务处于DELETED状态。函数os_delete_task使一个已经启动(使用函数os_create_task)的任务进入DELETED状态TIME-OUT:被round-robin Time-Out中断的任
19、务处于TIME-OUT状态。这个状态在round-robin程序中等效于READY状态事件(Events)在实时操作系统中事件可以用来控制任务的执行。一个可能会等待一个事件,也可能给其他任务设置事件标志。函数os_wait允许任务等待一个或多个事件。任务等待的是最普通的事件就是Timeout,一个简单的Timeout就是一定数量的clock ticks,当一个任务等待的时间耗尽时,它就可以继续执行了,当它等待时,其他的任务就可以运行variant of the Timeout is the Interval. An interval is like a timeout except that
20、the specified number of clock ticks is relative to the last time the os_wait function was invoked by the task. The Interval may be used to generate a task which is run on a regular, synchronous schedule (like once every second) regardless of how long the task takes between calls to the os_wait funct
21、ion.(以上内容是说,interval类似于timeout,但与timeout不同的是interval参考的不是上一次任务执行后的时间,而是某个特定的时间点,从而是一个规律性的、周期性的运行的任务:比如说每秒一次)信号是任务间通信的一种简单的形式,一个任务可以等待其他作任务给他发一个信号(使用 os_send_signal and isr_send_signal 函数)。每个任务的READY标志都可能被其他任务置位(使用 os_set_ready and isr_set_ready 函数)。一个等timeout, interval, 或信号的任务都可以通过置位READY标志重新启动。RTX5
22、1 Tiny会为每个事件维护一个标志。以下事件选择项可以被用来表明等待什么:事件选项 描述K_IVL 等待特定数目的IntervalK_SIG 等待一个信号K_TMO 等待Timeout当函数os_wait返回,发生的事件被返回值标志返回值 描述RDY_EVENT 任务的就绪标志被置位SIG_EVENT 信号已收到TMO_EVENT 一个Timeout已经结束或一个interval已经完毕函数os_wait可能会等待以下事件组合K_SIG | K_TMO:os_wait延迟任务直到一个信号已经发给他,或直到设定的clocktick耗尽K_SIG | K_IVL:os_wait延迟任务直到一个信
23、号已经发给他,或直到设定的interval耗尽注意:上面的两个事件也可能不组合。任务调度器任务调度器是RTX51 Tiny的一部分,用来将处理器交给任务。任务调度器根据以下规则决定具体执行哪一个任务。当出现以下情况将中断当前任务任务调用函数os_wait,并且等待的任务还没有发生任务执行的时间超过了设定的round-robin时间片其他的任务在出现以下条件时开始运行没有其他任务正在运行将启动的任务正处于就绪状态或TIME-OUT状态RTX51 tiny(2)Round-robin 任务切换RTX51 Tiny可以配置成使用round-robin多任务。Round-robinp容许quasi-p
24、arallel执行多任务。任务并不是连续执行的,而是分时间片执行的(可用的CPU时间被分成时间片,RTX51 Tiny把时间片分配给各个任务)。时间片的时间很短(以毫秒为单位),所以任务看起来像连续执行一样任务在分配给他的时间片内执行(除非放弃)。然后切换到下一个就绪的任务。RTX51tiny(3)编译连接有两种方法编译和连接RTX51 Tiny应用程序RTX51 Tiny(4)os_set_readySummary:i nclude <rtx51tny.h>char os_set_ready (unsigned char task_id); /* Task to make rea
25、dy */Description:使编号为task_id的任务就入就绪状态,可以任务中调用该函数Return Value: None.原创:RTX51 Tiny操作系统实例应用0推荐/*/*
26、160; */* RCPU.C: C-51 COMPILER
27、 */*
28、160;
29、160; */*/ char code title = "RCPUn" "GLOBAL TECH 2005n" "VERSION 2.0n"i nclude <reg52.h>
30、60; /* special function registers 8052 */i nclude <rtx51tny.h>
31、0; /* RTX-51 tiny functions & defines */i nclude <stdio.h> /* standard I/O .h-file
32、0; */i nclude <mydef.h>i nclude "keyname.h"i nclude "vfd.h"i nclude "tmr2.h"/* constants for os_task function */#define INIT 0 /* task nu
33、mber of task: init */#define PROCKEY 1 /* task number of task: prockey
34、160; */#define PROCPIR 2 /* task number of task: procpir */#define VFDCODE 3 /* task
35、 number of task: vfdcode */#define NECCODE 4 /* task number of task: neccode */#defi
36、ne USARTSEND 5 /* task number of task: usartsend */#define CLOCK 7
37、 /* task number of task: clock */#define TICK 6 /* task number of task: procrst */#define VIEWCON
38、; 8/* constants for UsartSend function */#define UsartSendMotor 1 /* Command for control to MOTO board */#define UsartSendQCB 2
39、; /* Command for control to QCB board */#define UsartSendTime 3 /* System time
40、 */#define UsartSendVFD 4 /* IDE state
41、0; */#define UsartSendPIR 5 /* pir
42、160; */#define UsartSendNEC 6 /* NEC code &
43、#160; */#define UsartSendKey 7 /* key code
44、 */#define UsartSendPIREN 8 /* PIR_EN
45、; */#define IDEFREE 1#define IDEPLAY 2#define IDESETUP 3#define IDERECORD 4#define IDENOSIG
46、; 5#define VIEWIDE 1#define VIEWQUAD1 2#define VIEWQUAD2 3unsigned char QUAD_NOW_BAK;unsigned char CAM_NOW_QUAD1;unsigned char CAM_NOW_QUAD2;unsigned char TickCounter;unsigne
47、d char MotorCmd;unsigned char NECCmd;unsigned char UsartSendData;unsigned char UsartSendCmd;unsigned char IDEStatus;unsigned char rst6s,stopcount;unsigned int rst4h;bit PWFlag;bit viewportbak;bit StopFlagBit;/*/* Task 0 'init': Initialize
48、 */*/void init (void) _task_ INIT
49、60; /* program execution starts here */ serial_init (); /* initialize the serial interface
50、 */ VIEW_SA = 0; VIEW_SB = 0; os_create_task (PROCKEY); /* key sample task
51、0; */ os_create_task (PROCPIR); /* PIR sample task */ os_create_task (VFDCODE)
52、; /* VFDCODE incepted from IDE board */ os_create_task (NECCODE); /* send NECCODE to IDE board
53、160; */ os_create_task (USARTSEND); /* send data to USART port */ os_create_task (CLOCK);
54、/* start clock task */ os_create_task (TICK); /* process tick
55、; */ os_create_task (VIEWCON); os_delete_task (INIT); /* stop init task (no longer needed)
56、 */char code motordata =0x01,0x09,0x0,0x08,0x03,0x0B,0x02,0x0A,0x0D,0x05,0x0C,0x04,0x0F,0x07,0x0E,0x06;/*/* Task 1 'prockey': monitor key incepted
57、160; */*/void prockey (void) _task_ PROCKEY while (1)
58、/* prockey is an endless loop */ KEY_NOW = _getkey (); /* key is incepted
59、0; */ TickCounter = 0; if (KEY_NOW = '')continue;
60、0; if (KEY_NOW = SLEEP)continue; switch (KEY_NOW) /*
61、160; */ case PANUP:
62、0; if (CAM_NOW != 0)&(IDEStatus != IDESETUP)
63、 /* motor control */
64、60; MotorCmd = motordata(CAM_NOW-1)*4; UsartSendCmd = UsartSendMotor;
65、60; os_send_signal (USARTSEND); break;
66、60; case PANDOWN: if (CAM_NOW != 0)&(IDEStatus != IDESETUP)
67、60; /* motor control */ &
68、#160; MotorCmd = motordata(CAM_NOW-1)*4+1;
69、; UsartSendCmd = UsartSendMotor; os_send_signal (USARTSEND);
70、 break; case PANLEFT: if (IDEStatus = IDESETUP) break
71、; if (CAM_NOW = 0)
72、; /* QCB control */
73、; CAM_NOW_QUAD1 = 0; QUAD_NOW = 1; UsartSendCmd = UsartSendQCB;
74、60; os_send_signal (USARTSEND); NECCmd = TOQUAD1;
75、; os_send_signal (NECCODE); else
76、60; /* motor control */ &
77、#160; MotorCmd = motordata(CAM_NOW-1)*4+2;
78、; UsartSendCmd = UsartSendMotor; os_send_signal (USARTSEND);
79、; break; case PANRIGHT: if (IDEStatus = IDESETUP) break;
80、0; if (CAM_NOW = 0) /* QCB co
81、ntrol */ CAM_NOW_QUAD2 = 0;
82、60; QUAD_NOW = 2; UsartSendCmd = UsartSendQCB;
83、160; os_send_signal (USARTSEND); NECCmd = TOQUAD2;
84、0; os_send_signal (NECCODE); else
85、160; /* motor control */
86、 MotorCmd = motordata(CAM_NOW-1)*4+3; UsartSendCmd = UsartS
87、endMotor; os_send_signal (USARTSEND);
88、0; break; case QUAD: /* QCB control &
89、#160; */ if (IDEStatus = IDESETUP) break; if (CAM_NOW
90、!= 0) CAM_NOW = 0;
91、; UsartSendCmd = UsartSendQCB; os_send_signal (USARTSEND);
92、160; if (QUAD_NOW=1)CAM_NOW_QUAD1 = CAM_NOW; if (QUAD_NOW=2)CAM_NOW_QUAD2 = CAM_NOW;
93、 break; case CAMERA1: /* QCB control
94、; */ if (IDEStatus = IDESETUP) break;
95、; if (CAM_NOW = 0) CAM_NOW = 1;
96、0; UsartSendCmd = UsartSendQCB; os_send_signal (USARTSEND); &
97、#160; if (QUAD_NOW=1)CAM_NOW_QUAD1 = CAM_NOW; if (QUAD_NOW=2)CAM_NOW_QUAD2 = CAM_NOW;
98、; break; case CAMERA2: &
99、#160; /* QCB control */ if (IDEStatus = IDESETUP) break;
100、0; if (CAM_NOW = 0)
101、0; CAM_NOW = 2; UsartSendCmd = UsartSendQCB; os_send_signal (USART
102、SEND); if (QUAD_NOW=1)CAM_NOW_QUAD1 = CAM_NOW; if (QUAD_NOW=2)CAM_NOW_QU
103、AD2 = CAM_NOW; break; case CAMERA3:
104、 /* QCB control */
105、 if (IDEStatus = IDESETUP) break; if (CAM_NOW = 0)
106、60; CAM_NOW = 3; UsartSendCmd = UsartSendQCB;
107、60; os_send_signal (USARTSEND); if (QUAD_NOW=1)CAM_NOW_QUAD1 = CAM_NOW; &
108、#160; if (QUAD_NOW=2)CAM_NOW_QUAD2 = CAM_NOW; break; &
109、#160; case CAMERA4: /* QCB control */
110、; if (IDEStatus = IDESETUP) break; if (CAM_NOW = 0)
111、160; CAM_NOW = 4; UsartSendCmd = UsartSendQCB;
112、160; os_send_signal (USARTSEND); if (QUAD_NOW=1)CAM_NOW_QUAD1 = CAM_NOW;
113、 if (QUAD_NOW=2)CAM_NOW_QUAD2 = CAM_NOW; break;
114、 case STOP: if (StopFlagBit = 0)
115、60; NECCmd = KEY_NOW; os_send_signal (NECCODE); /* send NECCom to IDE
116、60; */ break;
117、0; default : NECCmd = KEY_NOW; os_send_signal (NECCODE); /* send NECCom to IDE
118、 */ break; if (KEY_NOW = STOP)
119、; /* stop check */ StopFlagBit = 1; &
120、#160; /* stop counter start */ else StopFlagBit = 0;
121、160; /* stop counter stop */ /*/* Task 2 'procpir': PIR signal manage &
122、#160; */*/void procpir (void) _task_ PROCPIR unsigned char pirport,pirportn; while(1
123、) if (IDEStatus = IDEFREE) pirport = P2; /* PI
124、R Signal Sample */ if (pirport!=0xFF)
125、0; pirportn = pirport; UsartSendData = pirport; &
126、#160; UsartSendCmd = UsartSendPIR; os_send_signal (USARTSEND);
127、0; if (pirportn&0x01)!=0) if (PIR_EN&0x80)!=0
128、) CAM_NOW = CAM_NOW_QUAD1;
129、60; QUAD_NOW = 1; NECCmd = TRIG_Q1;
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2024全新生态农业园区施工队承包施工合同下载3篇
- 2024年度屠宰场工人岗位培训与晋升发展合同3篇
- 2024年汽车制造商与供应商关于汽车零部件采购的合同
- 2024年度上门摄影摄像及后期制作服务合同3篇
- 2024年知识产权合同保护
- 医院设施隐患排查与整改制度
- 手术器械使用与管理制度
- 教育机构知识产权管理制度的必要性
- 农户养鸡与销售合同
- 2025进口设备合同范本
- 2024年天然气管道施工环保劳务合同范本3篇
- 防范非法金融宣传
- 重症监护室抢救制度
- 统编版(2024)七年级上册道德与法治第四单元学情调研测试卷(含答案)
- 小学语文骨干教师专题讲座《自由阅读-开启快乐的读书之门》
- C语言程序设计-001-国开机考复习资料
- 华为经营管理-华为激励机制(6版)
- 2024年社会工作者-社会综合能力考试历年真题
- 人力资源的降本增效操作
- 机场航班信息LED显示屏方案
- 村级财务课件教学课件
评论
0/150
提交评论