之前答应给同学帮忙做毕设,想着应该很简单。结果老师给了他一份汇编程序,由于自己之前做过汇编编程的工作,就胆(no)大(zuo)妄(no)为(dai)的说是给他翻译成C语言的。
当我仔细瞅了那份程序之后。额,好吧,我只能说我尽力而为吧!
东西只有一篇近2000行的汇编程序和一份原理图,程序中无任何变量,需要变量或者是标志位时,直接操作一个RAM地址,子程序起名也是相当佛系。目前我只注释了一小部分的程序,大概三四百行吧,贴出来,作为一个笔记,以供后面学习。
由于不是本人程序,所以会在程序中做删减,但不会影响汇编语言的学习。注释为?的,意思是我也没看懂到底什么意思……同样的内容,在前面注释过的,后面不再注释。最后,向那个年代用汇编写单片机程序的老师们致敬。嘻嘻!_!
ORG 0000H ;程序起始地址
LJMP MAIN
ORG 0003H ;外部中断0
LJMP I0000
ORG 000BH ;定时器0
LJMP T0000
ORG 0023H ;串行中断
LJMP ES000
ORG 0030H ;程序存储区(用户RAM)
MAIN:
MOV R0,#7FH ;将数据7FH存入R0寄存器
MAIN1:
MOV @R0,#00H ;将0存入7FH地址
DJNZ R0,MAIN1 ;给R0-1,若不为0,则跳转到MAIN1,上面这两条语句是一个小循环,意思是将00-7FH地址清0,以便后续使用。
MOV SP,#60H ;将60H存入堆栈指针,即栈顶指针地址为60H
LCALL WR100 ;转到WR100,写数据到外部器件,应该是初始化外部器件
MOV TMOD,#21H ;配置定时器控制寄存器,T1为8位自动加载计数器模式,T2为,16位定时器模式
MOV TH0,#0FAH
MOV TL0,#00H ;T0
MOV TH1,#0FBH
MOV TL1,#0FBH ;T1
ANL PCON,#7FH ;配置电源控制寄存器,默认值
SETB SM0 ;以下6行配置SCON串行通信控制寄存器
SETB SM1 ;配置串行通信波特率为11:由定时器T1或T2的溢出率和SMOD所定:2SMOD ×(T1溢出率)/32
CLR SM2 ;多机通信控制位
CLR RI ;接收中断标志位
CLR TI ;发送终端标志位
CLR REN ;禁止接收
SETB P1.4
SETB TR0 ;允许T0计数
SETB TR1 ;允许T1计数
SETB ET0 ;定时器0中断充许
SETB ES ;打开串行中断
SETB PT0 ;定时器0中断优先
SETB EX0 ;打开外部中断INT0
SETB EA ;打开总中断
CLR P1.0 ;根据原理图,P1.0接在外部看门狗上,应该是喂狗信号,后面同理
SETB P1.0
MOV DPTR,#0E000H ;将0E00H写入DPTR(数据指针寄存器),片外RAM首地址?
MAIN2:
MOV A,#00H
MOVX @DPTR,A
INC DPTR
MOV A,DPH
CJNE A,#0E4H,MAIN2 ;清零0E000H-0E4000H地址区间
CLR P1.0
SETB P1.0
MOV DPTR,#0F000H
MAIN3:
MOV A,#00H
MOVX @DPTR,A
INC DPTR
MOV A,DPH
CJNE A,#0F5H,MAIN3 ;清零0F000H-0F5000H地址区间
CLR P1.0
SETB P1.0
MOV DPTR,#0E000H
MOV A,#00H
MOVX @DPTR,A
INC DPTR
MOVX @DPTR,A
INC DPTR
MOVX @DPTR,A
INC DPTR
MOVX @DPTR,A ;清零0E000H-0E0003H地址区间
INC DPTR
MOV A,#0F1H
MOVX @DPTR,A
INC DPTR
DEC A
MOVX @DPTR,A ;将0F1H写入0E0004H,将0F0H写入0E0005H
INC DPTR
MOV A,#0C0H
MOVX @DPTR,A ;将0C0H写入0E0006H
INC DPTR
MOV A,#05H
MOVX @DPTR,A ;将05H写入0E0007H
MOV DPTR,#7FFFH
CPL A
CJNE A,#03H,MAIN4 ;?
MAIN4:
JNC MAIN5
MOV A,#03H ;以下赋值原理同上,不再解释
MAIN5:
;此处有删减
SETB 00H ;标志位0
MOV 12H,#01H ;R2第2组通用寄存器
MOV 2FH,#00H ;位寻址区
MOV 32H,#03H ;用户RAM区,以上三句,应该是设置了三个变量
MOV C,P1.5
CPL C
MOV 78H,C
MOV C,P1.6
CPL C
MOV 79H,C
MOV C,P1.7
CPL C
MOV 7AH,C ;读取P1.5、P1.6、P1.7的值,并取反后存到78H、79H、7AH
XDY00:
CLR P1.0
SETB P1.0
JNB 01H,M0000 ;若标志位1,为0,跳转到M0000
LJMP M0100 ;否则跳转到M0100
;程序由此转向两个分支,后续。。。
子程序(有删减)
WR100:
MOV A,#06H ;将06H存入累加器A
CLR P1.0 ;清零P1.0
LCALL WR200 ;转到WR200,写8位数据到外部器件
SETB P1.0 ;置位P1.0
MOV A,#01H ;同上,将01H写入外部器件
CLR P1.0
LCALL WR200
MOV A,#20H ;同上,将20H写入外部器件
LCALL WR200
SETB P1.0
LCALL DEL20 ;转到DEL20,延时
RET
WR200:
MOV R3,#08H ;将08H存入R3寄存器
WR201:
RLC A ;将A带进位左移一位
MOV P1.2,C ;上一次左移无进位,因此P1.2为0
CLR P1.3 ;清零P1.3
SETB P1.3 ;置位P1.3
DJNZ R3,WR201 ;将R3-1,若不为0,转到WR201
RET ;返回。综上,此函数是将A通过左移写入外部器件,类似于I2C,SPI通信的写寄存器操作,A是所要写入的内容
DEL20:
MOV R2,#0FH
DEL21:
MOV R3,#0BAH
DEL22:
NOP
NOP
NOP
DJNZ R3,DEL22
CPL P1.0 ;对P1.0每隔(3个指令周期*0BAH)这么长时间取反
DJNZ R2,DEL21 ;取反0FH次
RET ;返回,综上,此函数可以实现将P1.0取反0FH次,每次保持0BAH*3T,T为1指令周期,类似于让LED闪烁的函数