51/AVR单片机开发系统
·设为首页
·联系站长
·加入收藏
 位置: 雨飞电子科技 >> 文章资讯 >> 单片机 >> 单片机入门 >> 正文 本站推出51/AVR单片机专业开发系统  [2006-10-02 17:24:49]      雨飞电子科技综合资讯网开通  [2006-01-15 23:09:58]
  子程序设计    3星级
子程序设计
[ 作者:未知     来源:网上收集     点击数:     更新时间:2006-10-9     文章录入:飞奔
【字体: 字体颜色

在用汇编语言编程时,应考虑到恰当地使用子程序,使整个程序的结构清楚,而且阅读和理解方便。使用子程序还可以减少源程序和目标程序的长度。在多次调用同样的程序段时,采用子程序就不必每次重复书写同样的指令,而只需书写一次。当然从程序的执行来看,每调用一次子程序都要附加保护断点、进栈和出栈等操作,增加程序的执行时间。但一般来说,付出这些代价总是值得的。

在汇编语言源程序中使用子程序时,一般要注意两个问题:参数传递和现场保护。参数传递一般可采用以下方法:

·传递数据。将数据通过工作寄存器R0~R7或累加器来传送。即主程序和子程序在交接处,上述寄存器和累加器存储的是同一参数。

·传送地址。数据存放在数据寄存器中,参数传递时只通过R0、R1、DPTR传递数据所存放的地址。

·通过堆栈传递参数。在调用之前,先把要传送的参数压入堆栈,进入子程序之后,再将压入堆栈的参数弹出到工作寄存器或者其他内存单元。

·通过位地址传送参数。在进入汇编子程序时,特别是进入中断服务子程序时还应注意现场保护问题,即对于那些不需要进行传递的参数,包括内存单元的内容、工作寄存器的内容,以及各标志的状态等都不应因凋用子程序而改变。方法就是在进入子程序时,将需要保护的数据推入堆栈,而空出这些数据所占用的工作单元,供在子程序中使用。在返回调用程序之前,则将推入堆栈的数据弹出到原有的工作单元,恢复其原来的状态,使调用程序可以继续往下执行。由于堆栈操作是“先入后出”,因此,先压入堆栈的参数应该后弹出,才能保证恢复原来的状态。例如:

SUBROU:      PUSH     ACC

              PUSH     B

              PUSH     R0

              POP       R0

              POP       B

              POP       PSW

              POP       ACC

              RET

至于每个具体的子程序是否需要现场保护,以及哪些参数应该保护,则应视具体情况而定。

调用子程序过程由调用指令完成,MCS-51单片机有两条调用指令:ACALL  addr11和ACAL  addrl6。指令中的地址为子程序的入口地址,在汇编语言中通常用标号来代表。在执行这二条指令时,单片机将当前的PC值压入堆栈。子程序的最后是返回指令RET,这条指令将堆栈的内容传入PC中,保证程序返回调用的地方继续运行。

在子程序执行过程中调用其他子程序,这种现象称为子程序嵌套。MCS-51单片机允许多重嵌套。

【例4-15】单字节二进制数据转换为BCD码子程序SBTOD。

功能:将单字节二进制数转换为三位BCD码。

入口:R2中存放要转换的二进制数。

出口:(R0)给出百位BCD码的存放地址。(R0)+1给出十位和个位BCD码的存放地址,高半字节放十位,低半字节放个位。

占用寄存器:A,B,R0,R2。

程序如下:

SBTOD:
 MOV
 SP,#60H
  
 
 
 PUSH
 ACC
  
 
 
 MOV
 A,R2
 ;取数
 
 
 MOV
 B,#64H
  
 
 
 DIV
 AB
 ;除以100,(A)为百位数
 
 
 MOV
 @R0,A
 ;存人(R0)单元
 
 
 MOV
 A,#0AH
  
 
 
 XCH
 A,B
 ;余数(B)送A
 
 
 DIV
 A,B
 ;除以10,得十位和个位
 
 
 SWAP
 A
 ;十位数放于高半字节
 
 
 ADD
 A,B
 ;个位数放于低半字节
 
 
 INC
 R0
  
 
 
 MOV
 @R0,A
 ;个位存入(R0)+1单元
 
 
 POP
 ACC
  
 
 
 RET
   
   
 

【例4-16】将内部数据存储器某一单元中的一个字节的十六进制数转换成两位ASCII码,结果存放在内部数据存储器的两个连续单元中。

假设一个字节的十六进制数在内部数据存储器40H单元,结果存于41H、42H单元中,用堆栈进行参数传递。

程序如下:

MAIN:
 MOV
 SP,#55H
  
 
 
 MOV
 R1,#41H
 ;R1为存结果指针
 
 
 MOV
 A,40H
 ;取要转换的数据
 
 
 SWAP
 A
 ;先转换高位字节
 
 
 PUSH
 ACC
 ;压栈
 
 
 LCALL
 HEASC
 ;调用低半字节转换成 
 

ASCII码程序


 POP
 ACC
 ; 要转换的数据出栈
 
 
 MOV
 @ R1 , A 
 ;存高半字节转换结果
 
 
 INC
 R1
  
 
 
 PUSH
 40H
  
 
 
 LCALL
 HEASC
  
 
 
 POP
 ACC
  
 
 
 MOV
 @ R1, A
 ;存低半字节转换结果
 
 
 END
  
  
 
HEASC:
 MOV
 R0, SP
  
 
 
 DEC
 R0
  
 
 
 DEC
 R0
  
 
 
 XCH
 A, @R0
 ;取被转换数据
 
 
 AND
 A, # 0FH
 ;保留低半字节
 
 
 ADD
 A, #2
 ;修改A
 
 
 MOVC
 A, @A+PC
 ;查表
 
 
 XCH
 A, @R0
 ;结果送回堆栈
 
 
 RET
  
  
 
TAB:
 DB
 30H,31H,32H,…
 

【例4-17】求两个无符号数据块中的最大值。数据块的首地址分别为60H和70H,每个数据块的第一个字节都存放数据块的长度,结果存人5FH单元。

解  本例可采用分别求出两个数据块的最大值,然后比较其大小的方法,求最大值的过程可采用子程序。

子程序名称:QMAX。

子程序入口条件:R1中存有数据块首地址。出口条件:最大值在A中,

下面分别编写主程序和子程序。

主程序:

ORG
 2000H
  
 
MOV
 SP,#2FH
 ;设堆栈指针
 
MOV
 R1,#60H
 ;取第一数据块首地址送R1中
 
ACALL
 QMAX
 ;第一次调用求最大值子程序
 
MOV
 40H,A
 ;第一个数据块的最大值暂存40H
 
MOV
 R1,#70H
 ;取第二数据块首地址送R1中
 
ACALL
 QMAX
 ;第二次调用求最大值子程序
 
CJNE
 A,40H,NEXT
 ;两个最大值进行比较 
 

NEXT:
 JNC
 LP
 ;A大,则转LP 
 

MOV
 A,40H
 ;A小,则把40H中内容送人A 
 

LP:
 MOV
 5FH,A
  
 
 
 SJMP
 $ 
   
 

子程序:


 ORG
 2200H
  
 
QMAX:
 MOV
 A,@R1
 ;取数据块长度
 
 
 MOV
 R2,A
 ;R2做计数器
 
 
 CLR
 A
 ;A清零,准备做比较
 
LP1:
 INC
 R1
 ;指向下一个数据地址
 
        
 CLR
 C
 ;0+cY,准备做减法
 
        
 SUBB
 A,@R1
 ;用减法做比较
 
 
 JNC
 LP3
 ;若A大,则转LP3   
 
 
 MOV
 A,@R1
 ;A小,则将大数送A中
 
        
 SJMP
 LP4
 ;五条件转LP4
 
LP3:
 ADD
 A,@R1
 ;恢复A中值
 
LP4:
 DJNZ
 R2,LP1
 ;计数器减1,不为零,转继续比较
 
 
 RET
  
 ;比较完,子程序返回

  • 上一篇文章: 单片机的应用

  • 下一篇文章: 常用波特率与其它参数选取关系
  • 发表评论   告诉好友   打印此文  收藏此页  关闭窗口  返回顶部
     最新5篇热点文章
     本站推出51/AVR单片机开发系统
     锁相环频率合成控制器MB1501/MB1504置...
     4900种场效应管参数资料(五)
     4900种场效应管参数资料(四)
     4900种场效应管参数资料(三)
     
     最新5篇推荐文章
     本站推出51/AVR单片机开发系统
     锁相环频率合成控制器MB1501/MB1504置...
     4900种场效应管参数资料(一)
     ATMEL89系列单片机特点
     2004-2005中国本土嵌入式十佳企业揭晓...
     
     相 关 文 章

      网友评论:(只显示最新5条。评论内容只代表网友观点,与本站立场无关!)
     设为首页  加入收藏  关于本站  版权申明  联系站长  友情链接  在线留言  与我同在 
    Copyright© 2005-2006 Www.Yufik.Com All Rights Reserved
    广州雨飞电子科技 E-mail: yufik@163.com 中国·广东·广州

    粤ICP备05026189号