640 likes | 891 Views
第 4 章 汇编语言程序设计. 4. 1 概 述. 4. 2 简单程序. 4. 3 分支程序. 4. 4 循环程序. 4. 5 查表程序. 4. 6 子程序的设计及调用. 4. 7 程序设计举例. 下页. ① 占用的内存单元和 CPU 资源少. ② 执行速度快. ③ 有效的利用计算机的专有特性。. ④ 适合实时控制 ⑤可计算程序运行时间. 4.1 概 述. 一、汇编语言和高级语言相比具有下列优点:. 如: 输出操作. 专有特性. MOV P1 , A. 上页. 下页. 回目录.
E N D
第4章 汇编语言程序设计 4. 1 概 述 4. 2 简单程序 4. 3 分支程序 4. 4 循环程序 4. 5 查表程序 4. 6 子程序的设计及调用 4. 7 程序设计举例 下页
①占用的内存单元和CPU资源少 ②执行速度快 ③有效的利用计算机的专有特性。 ④适合实时控制 ⑤可计算程序运行时间 4.1 概 述 一、汇编语言和高级语言相比具有下列优点: 如: 输出操作 专有特性 MOV P1, A 上页 下页 回目录
①建立数学模型 ②确定算法 ③制定流程图 ④确定数据结构 ⑤写出源程序 ⑥上机调试 ①定义有关字符名 ②定义程序的起始地址 ③程序主体 ④汇编结束标志 二、汇编语言程序设计的步骤: 三、汇编语言程序的结构 上页 下页 回目录
ORG 2000H START:MOV R0,#DATA1 ; 首址送R0 MOV R1, DATA1 ;长度送R1 ;检查长度是否为零 CJNE R1, #0 , NEXT HERE:SJMP $ ;为零则结束 NEXT: CLR A ;不为零则开始运算 LOOP:INC R0 ;加一个数 ADD A,@R0 DJNZ R1, LOOP ;长度减1不为零则转移 MOV SUM , A ;存和 SJMP HERE DATA1 DATA 20H SUM DATA 1FH END 例1:内部RAM从DATA1单元有一数据块,存放若干无符号数, 第一单元为数据块长度,求这些无符号数之和。 起始地址 标号 注释 程序主体 汇编结束标志 上页 下页 回目录
概念 四、评价程序质量的标准: ① 程序的执行时间 时 间 空 间 ② 程序所占用的内存字节数目 ③ 程序的逻辑性、可读性 ④ 程序的兼容性、可扩展性 ⑤ 程序的可靠性 上页 下页 回目录
RAM 20H ASCII码 21H 22H 4.2 简单程序 简单程序的特点: 既无分支,又无循环,按照顺序执行 可完成一定的基本功能,是编写复杂程序的基础 例4-2:将一个字节内的两个BCD码拆开并变成ASCII码, 存入两个RAM单元。BCD码放在内RAM的20H, 转换后高半字节放到21H,低字节放22H。 方法1: BCD码0~9对应的ASCII码为30H~39H 转换时,将20H中的BCD码拆开, 高四位置为“0011”即可。 BCDH BCDL 0011 BCDH 0011 BCDL 上页 下页 回目录
程序: ORG 1000H ;R0 22H A MOV R0, #22H ; 22H 0 MOV @R0,#0 MOV A, 20H XCHD A, @R0 BCDH BCDL ORL 22H, #30H SWAP A RAM @R0 ORL A, #30H 20H MOV 21H, A 21H SJMP $ 22H END 0011 BCDH 0000 BCDH BCDL 0000 ;两个BCD数送A ;BCDL数送22H ;完成转换 ;BCDH数送A的低4位 0011 BCDH BCDL 0011 0000 0000 ;完成转换 ;存数 ;原地踏步,相当与停机 上页 下页 回目录
B A B A A B ORL , #30H 方法1小结: 以上程序用了8条指令,15个内存字节,执行时间为9个 机器周期。 方法2: 采用除10H取余法将两个BCD数拆开 BCDH BCDL 0000 BCDH DIV AB 0001 0000 0000 BCDL 上页 下页 回目录
程序: ORG 1000H MOV A, 20H ;除10H取余,使BCDH A 、BCDL B MOV B,#10H DIV AB ORL B, #30H BCDH BCDL MOV 22H, B B A B A ORL A, #30H RAM MOV 21H, A 20H SJMP $ 21H END 22H ;取BCD码至A ; 完成转换 ;存ASCII码 0011 BCDH ;完成转换 0011 BCDL ;存ASCII码 BCDH BCDL DIV AB 0000 BCDH 0011 0001 0000 0011 0000 BCDL 上页 下页 回目录
00H 00H 原码 R1 R0 R3 R2 方法2小结: 以上程序用了7条指令, 16个内存字节, 执行时间为13个机器周期。 例4-3: 双字节求补 设:两个字节原码数存在R1、R0中 求补后结果,存在R3、R2中。 方法: -) 求补采用“模 -原码”的方法 即用“0”去减“原码” 上页 下页 回目录
程序: ;CY 0 ; A 0 ORG 1000H CLR C CLR A ;低字节求补 SUBB A, R0 MOV R2, A ;送R2 CLR A ;A清零 ;高字节求补 SUBB A, R1 MOV R3 , A ;送R3 SJMP $ END 上页 下页 回目录
例4-4: 将内部RAM的20H单元中的8位无符号二进制数, 转换为3位BCD码,并将结果存放在FIRST(百位)和 SECOND(十位、个位)两个单元中。 解: 可将被转换数除以100,得百位数;余数除以10 得十位数;最后余数即为个位数。 例如:255(十进制)除以100,得 2(百位数) 余数除以10,得5(十位数) 最后余数5即为个位数 编程如下: 上页 下页 回目录
程序(设(20H)=0FFH): B A 0FFH ;取数 ORG 1000H MOV A, 20H ; 除数 B MOV B,#64H DIV AB MOVFIRST,A MOV B,#0AH DIV AB SWAP A RAM ORL A,B 20H MOV SECOND,A 21H FIRST DATA 21H SJMP $ 22H SECOND DATA 22H END FIRST 0 2 H 5 5 H SECOND ; 除100 ;百位BCD MOV A,B 0 2H 5 0H 0FFH 6 4H 0 5H 0 AH 3 7H 0 5H 3 7H 5 5H ;除数10 → B ;除10 ;十位数送高位 ;A为十位、个位BCD ;存十位、个位数 上页 下页 回目录
4.3 分支程序 简单分支: 测试标志位 判断程序设置的条件 被称为复合条件 多重分支: 判断2个以上的条件 根据程序运行情况,可以有N种选择 N路分支: 利用散转指令JMP @A+DPTR可转向任一处理程序 简单分支程序举例: 例4-5设内RAM 30H,31H存放两个无符号数,试比较 两数的大小,较小的数存入30H单元,较大的数 存入31H单元。 解: 这是一个简单分支程序,可以使两数相减,若CY=1, 则被减数小于减数。用JC指令进行判断。 程序的流程图如下: 上页 下页 回目录
程序: 流程图: START ORG 1000H ;CY 0 CLR C (30H)-(31H) MOV A,30H Y CY=1? SUBB A, 31H N JC NEXT 交换两数 MOV A,30H END XCH A,31H MOV 30H,A NEXT :NOP SJMP $ END ;做减法比较两数 ;若(30H)小,则转移 CY=1则转移 若CY≠1则顺序执行 ;交换两数 上页 下页 回目录
内部RAM 故障标志 排出温度值 进入温度值 40H 41H 42H 例4-6:空调机制冷时,若排出的空气温度比吸入的空气 温度低8℃则认为工作正常,否则便认为是故障, 并设置故障标志。 解: 首先定义一些工作单元 为了可靠的监控空调机的工作情况,做两次减法: 第一次(40H)-(41H),若CY=1 ,则肯定有故障; 第二次两个温度的差值减去8 ℃,若CY=1 ,则肯定 有故障 置热? 高 低 置冷能力不足? 程序的流程图如下: 上页 下页 回目录
START A←(40H)-(41H) Y CY=1? N (A)-8℃ Y CY=1? N 42H←0 42H←FFH END 流程图: 入 出 故 障 故 障 正常 上页 下页 回目录
ORG 1000H START:MOV A,40H CLR C ;吸入温度值送A SUBB A,41H ; 0 → CY JC ERROR SUBB A,#8 JC ERROR MOV 42H,#0 SJMP EXIT ERROR:MOV 42H,#0FFH EXIT: SJMP $ END 程序: ; A←(40H)-(41H) ;CY=1,则故障 ;温度小于8℃? 若CY≠1顺序执行 CY=1转移 ;是则故障 ;工作正常标志 ;转出口 若CY≠1顺序执行 CY=1转移 ;设置故障标志 ;停机 上页 下页 回目录
多重分支程序举例 例4-7:设30H单元存放的是一元二次方程ax2+bx+c = 0 根的判别式△= b2 – 4ac的值。 试根据30H单元的值,编写程序, 判断方程根的三种情况。 在31H中存放“0”代表无实根, 存放“1”代表有相同的实根, 存放“2”代表两个不同的实根。 解: △为有符号数,有三种情况,这是一多重分支程序 即小于零,等于零、大于零。 可以用两个条件转移指令来判断, 首先判断符号位,用指令JNB ACC.7, rel判断, 若ACC.7 = 1,则一定为负数;此时0 若ACC.7 = 0,则△≥0。此时再用指令JNZ rel 判断 若△≠0,则△> 0,否则△= 0 上页 下页 回目录
START A←△ N Acc.7=0? Y Y (A)= 0? N 31H←2 31H←1 31H←0 END 流程图: P124 △ 0,则2个实根 △ 0,则无实根 △= 0,则 1个实根 上页 下页 回目录
ORG 1000H START:MOV A,30H ;△值送A JNB ACC.7,YES ; △≥0 转YES MOV 31H,#0 SJMP FILISH YES: JNZ TOW MOV 31H,#1 SJMP FILISH TOW: MOV 31H,#2 FILISH:SJMP $ END 程序: ; △< 0 无实根 ; △> 0转 TOW ; △= 0 有相同实根 ;有两个不同实根 P124 上页 下页 回目录
4.4 循环程序 循环程序:一些有规可循而又反复处理的问题 利用比较转移指令CJNE、减1不为“0”转移指令DJNZ等实现 例4-13:在内部RAM 30H~4FH连续32个单元中存放了 单字节无符号数,求32个无符号数之和, 并存入内部RAM 51H,50H中。 解: 这是重复相加问题,要设置一些工作单元 设: R0 做加数地址指针, R7 做循环次数计数器, R3 做和数的高字节寄存器。 地址指针 循环次数计数器 程序的流程图如下: 上页 下页 回目录
START #31→R7 #0→R3 (30H)→A #31H→R0 (A)+((R0))→A CY=0? (R3)+1→R3 (R0+1)→R0 N (R7)-1=0? Y 51H←(R3) 50H← (A) END 流程图: (A)+((R0))→A N (R3)+1→R3 Y N P130 Y 上页 下页 回目录
程序: ORG 0200H START:MOV R7,#31 MOV R3,#0 ;R7作循环次数计数器 MOV A,30H ;R3作和数高字节寄存器 MOV R0,#31H LOOP:ADD A, @R0 JNC NEXT INC R3 NEXT :INC R0 DJNZ R7,LOOP 循环控制 MOV 51H,R3 MOV 50H,A SJMP $ END 循环程序的结构 初始化部分 ;取被加数 ;R0作加数地址指针 ;作加法 ;CY=0,和<256,则转 循环体部分 ;CY=1,加到高字节 ;修改R0指针 ;未完,重复加 循环 控制 循环执行 直到R7=0 结束部分 ;存和数 P129 上页 下页 回目录
例4-14:从外部RAM BLOCK单元开始有一无符号数数据块, 数据块长度存入LEN单元, 求出其中最大数存入MAX单元。 解:这是一个基本搜索问题,采用两两比较法。 取两者较大的数再与下一个数进行比较, 若数据块长度LEN=n则应比较n-1次, 最后较大的数就是数据块中的最大数。 为了方便进行比较, 我们使用CY标志来判断两数的大小, 使用B寄存器作比较与交换的寄存器, 使用DPTR作外部RAM地址指针。 P130 请阅读!! 阅读 程序的流程图如下: 上页 下页 回目录
START DPTR←#BLOCK LEN←LEN-1 A←(DPTR) CY←0 B←(A) (DPTR)+1 A←(DPTR) A←(A)-(B) Y CY=0? 若(A)>(B) 则A←(B)+(A) N 若(A)<(B)则A←(B) N LEN-1=0? Y MAX←最大数 END 流程图: 初始化 工作单元 较大数 交换至A 恢复 较大数至A A中 的数总是较大 上页 下页 回目录
编程: ORG 0200H BLOCK DATA 0100H MAX DATA 31H LEN DATA 30H ;定义数据块首址 ;数据块首址送DPTR FMAX: MOV DPTR,#BLOCK DEC LEN ;长度减1 ;定义最大数暂存单元 MOVX A,@DPTR LOOP: CLR C MOV B, A INC DPTR MOVX A,@DPTR SUBB A, B JNC NEXT MOV A, B SJMP NEXT1 NEXT: ADD A, B NEXT1: DJNZ LEN, LOOP MOV MAX, A SJMP $ END ;定义长度计数单元 ;取数至A ;0→CY ;暂存于B ;修改指针 ;取下一数 ;作减法比较 ;大者送A ;若(A)>(B)则恢复A ;未完继续比较 ;存最大数 RET ;*若用RET指令结尾则 该程序可作子程序调用 上页 下页 回目录
例4-15:从外部RAM BLOCK单元开始有一数据块, 数据块长度存入LEN单元, 试统计其中正数、负数和零的个数, 分别存入PCOUNT、MCOUNT、ZCOUNT单元。 解:这是一个多重分支的单循环问题。数据块中是带符号数 • 先用JB ACC.7,rel 指令判断符号位。 • 若ACC.7=1,则该数一定是负数,MCOUNT单元加1; • 若ACC.7=0,则该数可能是正数,也可能是零; • 用JNZ rel 判断A是否为零 • 若A≠0,则一定是正数,PCOUNT单元加1; • 若既不为正也不为负,则一定是零,ZCOUNT单元加1; 程序的流程图如下: P132请阅读!! 阅读!! 上页 下页 回目录
流程图: START DPTR←#BLOCK PCOUNT←0 MCOUNT←0 ZCOUNT←0 A←(DPTR) N ACC.7=0? MCOUNT+1 Y N (A)=0? PCOUNT+1 Y ZCOUNT+1 DPTR+1 N LEN-1=0? Y END 负数 正数 零 P132 上页 下页 回目录
;定义数据块首址 ;定义长度计数单元 ORG 0200H BLOCK DATA 2000H LEN DATA 30H ;定义正计数单元 PCOUNT DATA 31H MCOUNT DATA 32H ;定义负计数单元 ZCOUNT DATA 33H ;定义零计数单元 程序: 上页 下页 回目录
START:MOV DPTR,#BLOCK MOV PCOUNT,#0 ;计数单元清零 MOV MCOUNT,#0 ;数据块首址送DPTR MOV ZCOUNT,#0 LOOP: MOVX A,@DPTR ;取数 JB ACC.7,MCON ;若ACC.7=1 转负计数 JNZ PCON ;若(A)≠0,转正计数 INC ZCOUNT ;若(A)=0,则零的个数加1 AJMP NEXT MCON: INC MCOUNT ;负计数单元加1 AJMP NEXT PCON:INC PCOUNT ;正计数单元加1 NEXT: INC DPTR ;修正指针 DJNZ LEN,LOOP ;未完继续 SJMP $ END P132 上页 下页 回目录
作业 P156: 1、4、5、6 !!!
16位数据指针 不能 4.5 查表程序 对于复杂参数的计算如: 非线性参数 用汇编编程十分困难 甚至无法建立数学模型 对数、指数、三角函数 用查表的方法简单便捷 微分、积分等 MCS-51指令系统中有两条指令具有极强的查表功能 寻址64KB 长查表指令 (1) MOVC A,@A+DPTR 作基址寄存器 作变址寄存器 指向表格的第 i 项 指向表格首址 (2) MOVC A,@A + PC 短查表指令 页内查表指令 作基址寄存器 第i项加 变址调整值 作变址 上页 下页 回目录
查表程序: 先用伪指令 DB 或 DW 把表格的数据存入ROM 利用查表指令 MOVC A,@A+DPTR MOVC A,@A+PC 来获得数据 例4-20:一个十六进制数放在HEX单元的低四位, 将其转换成ASCII码 解: 十六进制 0~9 的ASCII码为 30H~39H, A~F 的ASCII码为 41H~46H, ASCII码表格的首址为ASCIITAB 上页 下页 回目录
ORG 0200H HEX EQU 30H HEXASC: MOV A,HEX ANL A,#0FH MOV DPTR,#ASCTAB MOVC A,@A+DPTR MOV HEX,A RET DPTR ASCTAB:DB 30H,31H,32H,33H DB 34H,35H,36H,37H DB 38H,39H,41H,42H DB 43H,44H,45H,46H END 编程1: (A)= 15 (A)= 3 0 1 2 3 4 5 6 7 8 9 33H A B C D E F 46H 上页 下页 回目录
ORG 0200H HEX EQU 30H ;变址调整 HEXASC: MOV A,HEX ANL A,#00001111B ADD A,#3 MOVC A,@A+PC MOV HEX,A RET ASCTAB:DB 30H,31H,32H,33H DB 34H,35H,36H,37H PC PC DB 38H,39H,41H,42H DB 43H,44H,45H,46H END 编程2: ;变址调整 #3 ;2字节 ;1字节 上页 下页 回目录
0200H HEXASC:MOV A,HEX 0202H ANL A,#0FH 0204H ADD A,#3 0206H MOVC A,@A+PC 0207H MOV HEX,A 0209H 020AH A RET 020BH 30H 31H … … PC PC PC PC PC 46H 查十六进制数“01H”的ASCII码(PC做基址) (PC) =0207H 04H 01H 31H + ALU 上页 下页 回目录
DPTR MOV A,HEX 0200H 0202H ANL A,#0FH 0204H MOV DPTR,#ASCTAB 0207H MOVC A,@A+DPTR 0208H MOV HEX,A 020AH RET 30H DPTR 020BH A 31H 020CH … … 46H PC PC PC PC PC 查十六进制数“01H”的ASCII码(DPTR做基址) 01H 31H 020BH + ALU 上页 下页 回目录
4.6 子程序的设计及调用 一、子程序的概念 • 把能完成某种基本操作,并具有相同操作的程序段,单独 编成子程序。 • 如:函数、±、×、 运算、代码转换、数据采集、延时等 • 利用调用子程序指令(ACALL或LCALL)和从子程序返回指令RET 使用子程序的优点 • ⑴ 不必重复书写同样的程序,提高编程效率 • ⑵ 程序的逻辑结构简单,便于阅读 • ⑶ 缩短了源程序和目标程序的长度,节省了存储器空间 • ⑷ 使程序模块化、通用化、便于交流共享资源 • ⑸ 便于按某种功能调试 上页 下页 回目录
RET LCALL addr16 ; PC7~0 ((SP)) ,(SP) (SP)-1 ; PC15~8 ((SP)) ,(SP) (SP)-1 ; PC addr16 转向子程序 ;在调用子程序之前,保护断点地址 ;SP (SP)+1,(SP) PC15~8 ;SP (SP)+1,(SP) PC7~0 ;(PC) (PC)+3 二、调用子程序的要点 1、子程序的结构 ⑴ 子程序开头的标号段必须有一个标志,该标志既是 子程序的名字又是其入口地址,以便主程序调用。 在主程序中利用指令ACALL或LCALL可转入子程序。 该指令具有保护断点的功能 例如:调用延时子程序 LCALL(ACALL) DELY ⑵ 子程序结尾必须使用一条从子程序返回指令RET, 它具有恢复断点的功能 主程序 CALL断点 子程序 RET 上页 下页 回目录
2、参数传递 子程序入口条件: 在调用一个子程序时,主程序应先把有关参数放到 某些约定的位置,子程序运行时,可以从约定的位置得 到有关参数。 子程序出口条件: 子程序结束前,也应把处理结果送到约定位置 参数传递的方法: ⑴ 子程序无须传递参数 这类子程序中所需要的参数是子程序赋予, 不需要主程序给出 上页 下页 回目录
. . . . . . LCALL DELY DELY: MOV R7, #100 DLY0: MOV R6, #98 NOP DLY1: DJNZ R6, DLY1 DJNZ R7, DLY0 RET 例4-23调用延时子程序DELY 设:主频为12MHZ 意味着每个机器周期为1µs 调用子程序 主程序: 子程序开始的标号 1µs 子程序: 1µs 1µs 98×2=196µs 2µs 子程序返回指令 2µs 不需主程序提供入口参数,从子程序开始到子程序返回,大约为20ms =20003µs = 20.003ms (196+2+2)× 100 +3 +3 上页 下页 回目录
⑵ 用累加器和工作寄存器传递参数 入口参数: 放在累加器A和工作寄存器中R0 ~ R7中 出口参数: 放在累加器A和工作寄存器中R0 ~ R7中 例4-24双字节求补子程序CPLD 解:采用“变反加1”的方法,十六位数变反加1, 不仅低字节要加1,高字节要加低字节的进位。 故采用ADD指令,不采用INC指令。 INC指令不影响CY位 上页 下页 回目录
CPLD:MOV A,R6 CPL A ADD A,#1 MOV R6,A MOV A,R7 CPL A ADDC A,#0 MOV R7,A RET 入口参数:(R7R6)=16位数 R7R6 出口参数:(R7R6)=求补后的16位数 R7R6 Cy + Cy 上页 下页 回目录
内部RAM CPLN:MOV A,@R0 CPL A ADD A,#1 @ R0 @ R0 @ R0 @ R0 @ R0 字节1 MOV @R0,A 字节2 字节3 NEXT: INC R0 … MOV A,@R0 … CPL A 字节n ADDC A,#0 MOV @R0,A DJNZ R7, NEXT RET 地址 ⑶ 通过操作数地址传递参数 例4-25 n字节求补子程序CPLN 入口参数:(R0)=求补数低字节指针,(R7)=n-1 出口参数:(R0)=求补后高字节指针 上页 下页 回目录
. . 例4-26在HEX单元存放两个十六进制数,将它们分别 . . . . 转换成ASCII码并存入ASC和ASC+1单元 MAIN: ;压入 被转换数 PUSH HEX ;转子 *PC LCALL HASC ;ASCL→ASC POP ASC ;取被转换数 SP+1 SP SP+3 SP+2 MOV A, HEX ;处理高四位 ;压入 SWAP A PUSH ACC ;转子程序 LCALL HASC ;ASC→ASC+1 POP ASC+1 ⑷ 通过堆栈传递参数 解: 由于要进行两次转换,故可调用查表子程序完成 主程序 *PCH 断点地址 *PCL HEX 栈底 下页 上页 回目录
HASC: DEC SP ; ;修改SP指向HEX DEC SP POP ACC ;弹出 *PCH ANL A,#0FH ;屏蔽高四位 *PCL ADD A,#5 ;变址调整 HEX 栈底 MOVC A,@A+PC ;查表 PUSH ACC ;结果入栈 A ; INC SP ;修改SP指向断点位置 INC SP SP+3 SP+2 SP+1 SP+3 SP+2 SP SP+1 ; RET ASCTAB: DB ‘0 1 2 … 7’ DB ‘8 9 A … F’ 子程序 PC HEX Result Result 上页 下页 回目录
子程序 HASC:DEC SP . . DEC SP . . . . POP ACC PC ANL A,#0FH 64H ADD A,#5 63H MOVC A,@A+PC PUSH ACC 62H PUSH HEX INC SP 61H LCALL HASC INC SP 60H POP ASC RET MOV A, HEX ASCTAB: DB ‘0 1 2 … 7’ SWAP A DB ‘8 9 A … F’ A PUSH ACC LCALL HASC SP SP SP SP SP SP SP SP SP POP ASC+1 0000 HEXL ASC 主程序 断点 *PCH *PCL HEX HEX ASC 上页 下页 回目录
3、现场保护 现场保护:如果子程序使用的寄存器与主程序使用的寄存器 有冲突,在转入子程序前,特别是进行中断服务 子程序时,要进行现场保护。 冲突 保护内容: 主程序使用的内部 RAM 内容,各工作寄存器内容, 累加器 A 和 DPTR 以及 PSW 等寄存器内容。 保护方式: 将要保护的单元压入堆栈。 R0~R7 中断保护时:还可以用 RS1 RS0 来选择其他通用寄存器组, 以便保护主程序现场。 上页 下页 回目录
BCDCB: PUSH ACC ; ; PUSH PSW ; 保护现场 PUSH DPL ; PUSH DPH ; 十翻二 ; POP DPH ; POP DPL ; 恢复现场 . POP PSW . . ; POP ACC RET 例如:十翻二子程序的现场保护 推入与弹出应按照“先进后出”,或“后进先出”的顺序 上页 下页 回目录