
首先你要有个总体的逻辑框架,然后写出你大致的程序框图,在在每一个环节上进行思考理解,理清头绪,把整个框图都完全理解明白以后,就开始进行写程序了,注意一些语句的用法哦,写完之后烧到开发板上,然后对程序进行调试,有错误就仔细的修改,调试应该说是最麻烦的工作,所以不要着急,慢慢来,等到你成功的时候你就有种说不出来的高兴了,祝你好运。
又是汇编的。。。
计算机是通过执行指令(由 *** 作码字段和 *** 作数字段组成)序列来解决问题的,因而每种计算机都有一组指令集(指令系统)供给用户使用,寻址就是其中之一(如为了找到 *** 作数)。
寻址方式:1)与数据有关的寻址方式 :
a 立即寻址方式: *** 作数(立即数)直接存放在指令中,紧跟在 *** 作码,作为指令的一部分,这中寻址方式用来表示常数,它经常用于给寄存器赋初值,且只能用于源 *** 作数字段,不能用于目的 *** 作字段,且源 *** 作数长度与目的 *** 作数长度一致。
b 寄存器寻址方式: *** 作数在寄存器中,指令用来指定寄存器号,不需要访问存储器来取得 *** 作数,速度较快。
c 直接寻址方式: *** 作数的有效地址(在8086里把 *** 作数的偏移地址叫做有效地址)只包含位移量一种成分,其值就存放在代码段中指令的 *** 作码之后,位移量的指即 *** 作数的有效地址。适用于处理单个变量。
d 寄存器间接寻址方式: *** 作数的有效地址只包含基址寄存器内容或变址寄存器内容一种成分,因此有效地址就在某个寄存器中,而 *** 作数就在存储器中。适用与表格处理,执行完一条指令后,只需修改寄存器的内容就可以取出表格下一项。
e 寄存器相对寻址方式: *** 作数的有效地址即为基址或变址寄存器和指令中指定的位移量之和。
f 基址变址寻址方式: *** 作数的有效地址是一个基址寄存器和一个变址寄存器之和。
g 相对基址变址寻址方式 h 比例变址寻址方式 等等。
2)与转移地址有关的寻址方式。
a 段内直接寻址:转向的有效地址是当前IP寄存器的内容和指令中指定的8位或16位位移量之和。
b 段内间接寻址:转向有效地址是一个寄存器或是一个存储单元的内容 。(常用)
c 段间直接寻址 d 段间间接寻址
此外 还介绍一些寄存器 如通用寄存器 AX BX CX DX 也可叫做数据寄存器,可以以字或字节的形式访问, 另外 SP BP SI DI 四个16位寄存器可以像数据寄存器一样在运算时存放 *** 作数,但他们只能以字(16位)为单位使用,此外它们更经常的用途是在存储器寻址时,提供偏移地址,再者有四个专门提供段地址的寄存器,称为段寄存器 有代码段CS 数据段DS 堆栈段SS 附加段ES。
MODE_RG EQU 40H ;模式选择
MODE2 EQU 60H ;MODE值
MODE3 EQU 61H
MODE4 EQU 62H
MODE5 EQU 63H
MODE6 EQU 64H
MODE1 EQU 65H
HOUR EQU 41H ;小时缓冲区
MIN EQU 42H ;分钟缓冲区
SEC EQU 43H ;秒缓冲区
TEMP EQU 4AH
;闹钟缓冲区
H_ALARM EQU 6AH ;闹钟缓冲区
M_ALARM EQU 6BH
S_ALARM EQU 6CH
F_ALARM EQU 6DH
;秒表缓冲区
M_SEC EQU 76H
S_SEC EQU 77H
;LED送显示临时变量
LED0 EQU 51H
LED1 EQU 52H
LED2 EQU 53H
LED3 EQU 54H
MODE_KEY EQU P34
UP_KEY EQU P33
DOWN_KEY EQU P35
BUF EQU 49H
ORG 0000H
LJMP MAIN
ORG 000BH
LJMP INT_0
ORG 001BH
LJMP INT_1
ORG 0080H
MAIN: MOV SP,#2FH ;堆栈初始化
MOV MODE_RG,#0 ;MODE_RG寄存器值初始化
MOV LED0,#0FEH ;初始化LED
MOV LED1,#0FDH
MOV LED2,#0FBH
MOV LED3,#0F7H
MOV MODE1,#1
MOV MODE2,#2
MOV MODE3,#3
MOV MODE4,#4
MOV MODE5,#5
MOV MODE6,#6
MOV F_ALARM,#0 ;错误2:一开始用 CLR F_ALARM,这导致在后面的时候JZ F_ALARM 运行错误,
MOV BUF,#0 ;在于 JZ 指令是对累加器A全为0或者全为1进行判断,CLR只能对一位 *** 作
MOV TMOD,#11H ;定时器初始化:定时器0,方式1,定时器1,方式1
MOV IP,#00001000B ;定时器1优先级高
MOV TH0,#3CH ;定时50MS
MOV TL0,#0B1H
MOV TH1,#0D8H ;定时10MS
MOV TL1,#0F0H
SETB EA
SETB ET0
SETB ET1
SETB TR0 ;启动定时器
MOV HOUR,#0 ;for test
MOV MIN,#0
MOV SEC,#0 ;定时器计数器,50MS中断一次,200次则刚好1S
MOV M_SEC,#0
MOV S_SEC,#0
MOV H_ALARM,#0
MOV M_ALARM,#0
MAIN1: LCALL DISPLAY12
LCALL DISPLAY34
;CLR P14 TEST
JNB MODE_KEY,KEY_SCAN
MOV A,MODE_RG
CJNE A,MODE6,Y1 ;MODE6 秒表
JNB DOWN_KEY,DEALDOWN ;判断秒表开关
JNB UP_KEY,DEALUP
Y1: MOV A,F_ALARM ;判断闹钟
JNZ ALARM
LJMP MAIN1
;-----------------------------------秒表开关程序---------------------------
DEALDOWN: LCALL DELY10MS
JB DOWN_KEY,MAIN1
H1: JNB DOWN_KEY,H1
CPL TR1
LJMP MAIN1
DEALUP: LCALL DELY10MS
JB UP_KEY,MAIN1
H2: JNB UP_KEY,H2
MOV M_SEC,#0
MOV S_SEC,#0
CLR TR1
LJMP MAIN1
;-----------------------------------闹钟扫描程序---------------------------
ALARM: MOV A,H_ALARM
CPL P12
CJNE A,HOUR,EXIT3
MOV A,M_ALARM
CJNE A,MIN,EXIT3
LJMP STARTALARM
EXIT3: SETB P36
LJMP MAIN1
STARTALARM: CPL P36
JNB DOWN_KEY,OFFALARM
LJMP S1
OFFALARM: LCALL DELY10MS
JB DOWN_KEY,MAIN1
S2: JNB DOWN_KEY,S2
MOV F_ALARM,#0
SETB P36
LJMP MAIN1
S1: LCALL DELAY
LJMP MAIN1
;-----------------------------------键盘扫描程序---------------------------
KEY_SCAN: LCALL DELY10MS
JB MODE_KEY,MAIN1
INC MODE_RG
;SETB P14 测试
K1: JNB MODE_KEY,K1 ;按键直到用户松开按键
K2: MOV A,MODE_RG
CJNE A,#0,DEALMODE ;不是在正常显示模式下则跳转到模式处理程序
LJMP MAIN1 ;返回主程序
;模式处理程序部分
DEALMODE: MOV TEMP,#0 ;凡转入MODE处理,则首先清除TEMP
MOV A,MODE_RG ;有MODE_RG值不为5、0
CJNE A,MODE2,M0 ;判断MODE_RG值,不为1跳转
LJMP H_GLINT ;模式1,小时位闪烁
M0: CJNE A,MODE3,M1 ;不是模式2,跳转
LJMP M_GLINT ;模式2,分钟位闪烁
M1: CJNE A,MODE4,M2 ;不是模式3,跳转
LJMP H_GLINT
M2: CJNE A,MODE5,M3
LJMP M_GLINT
M3: CJNE A,MODE6,M4
MOV M_SEC,#0
MOV S_SEC,#0
LJMP MAIN1
M4: CJNE A,MODE1,M5
;CLR TR1
LJMP MAIN1
M5: MOV MODE_RG,#0
LJMP MAIN1
;MODE为1,3,小时位闪烁
//MOV TEMP,HOUR ;将TEMP赋值,防止在加的时候是在随机值的基础上增加
H_GLINT: ;CPL P10
MOV R0,#28
MOV R1,#28
K4: LCALL DISPLAY12 ;分开显示
LCALL DISPLAY34
E1: JNB MODE_KEY,K21 ;检测是否有按键按下,有按下则跳转到分钟位闪烁
JB UP_KEY,E9 ;判断加位有无按键按下
LJMP UP
E9: DJNZ R0,K4
K6: LCALL DISPLAY34
JNB MODE_KEY,K21 ;检测是否有按键按下,有按下则跳转延时后进行模式判断
LJMP G1
K21: LCALL DELY10MS ;延时后确定有MODE按键按下,将
JB MODE_KEY,H_GLINT
W: JNB MODE_KEY,W
INC MODE_RG
CPL P14
LJMP DEALMODE ;确定有按下,MODE+1后返回MODE处理程序
JNB UP_KEY,UP ;判断加位有无按键按下
G1: DJNZ R1,K6
LJMP H_GLINT ;调用完毕返回,实现闪烁
K3: LJMP MAIN1 ;可省略
;MODE为2,4,分钟位闪烁
M_GLINT: MOV R0,#28
MOV R1,#28
K23: CPL P17
LCALL DISPLAY12
LCALL DISPLAY34
JNB MODE_KEY,KK ;跳转,确定是否有按键按下
JNB UP_KEY,UP ;判断加位有无按键按下
MOV A,MODE_RG
CJNE A,MODE3,E2 ;在MODE5的情况下要判断闹钟确认键有没按下
LJMP E5
E2: JNB DOWN_KEY,F2
LJMP E5
F2: LJMP ONALARM2
E5: DJNZ R0,K23
K24: LCALL DISPLAY12
JNB MODE_KEY,KK ;检测是否有按键按下,有按下则跳转
JNB UP_KEY,UP ;判断加位有无按键按下
MOV A,MODE_RG ;扫描闹钟确认键
CJNE A,MODE3,E7 ;在MODE5的情况下要判断闹钟确认键有没按下
LJMP G2
E7: JB DOWN_KEY,E8
CPL P13
LJMP ONALARM2
E8: LJMP G2
KK: LCALL DELY10MS ;去抖
JB MODE_KEY,M_GLINT
W1: JNB MODE_KEY,W1
INC MODE_RG
CPL P14
LJMP DEALMODE ;确定有按下,MODE+1后返回MODE处理程序
G2: DJNZ R1,K24
LJMP M_GLINT
;位加,处理程序
;小时调整
UP: MOV R1,#20
UP11: INC TEMP
UP12: MOV A,MODE_RG ;判断此时的MODE,根据MODE将临时变量给对应的赋值
CJNE A,MODE2,AA0 ;不是在MODE2的情况下跳转
MOV A,TEMP
CJNE A,#24,A_UP1
MOV TEMP,#0
A_UP1: MOV HOUR,TEMP ;为MODE2,将临时变量赋给小时位
LJMP UP15
AA0: CJNE A,MODE4,UP13 //UP13为分钟调整入口
MOV A,TEMP
CJNE A,#24,A_UP
MOV TEMP,#0
A_UP: MOV H_ALARM,TEMP ;模式3,将临时变量赋给闹钟的小时位
LJMP UP15 ;UP15为显示入口
;分钟调整入口
UP13: MOV A,MODE_RG
CJNE A,MODE3,UP14 ;不是模式2,跳转
MOV A,TEMP
CJNE A,#60,DISOVER2
MOV TEMP,#0
DISOVER2: MOV MIN,TEMP
LJMP UP15
UP14: MOV A,TEMP ;上面判断不是模式2,则必然是模式4
CJNE A,#60,DISOVER3
MOV TEMP,#0
DISOVER3: MOV M_ALARM,TEMP
LJMP UP15
UP15: LCALL DISPLAY12
LCALL DISPLAY34
DJNZ R1,UP01
MOV R1,#1 ;
JNB UP_KEY,UP11
UP01: JNB UP_KEY,UP12
UP16: MOV A,MODE_RG ;松开键以后按照模式判断该返回哪种状态,不能返回DEALMODE函数
CJNE A,MODE2,UP17
LJMP H_GLINT
UP17: CJNE A,MODE3,UP18
MOV SEC,#0 ;每次设置完时间后将秒钟位置零保证时间准确
LJMP M_GLINT
UP18: CJNE A,MODE4,UP19
LJMP H_GLINT
UP19: CJNE A,MODE5,UP20
LJMP M_GLINT
UP20: LJMP MAIN1
ONALARM2: LCALL DELY10MS ;延时10MS,去抖
JB DOWN_KEY,B2 ;抖动所致,返回分钟位闪烁
LJMP K42
B2: LJMP M_GLINT
K42: JNB DOWN_KEY,K42
MOV F_ALARM,#0FFH
MOV MODE_RG,#0
LJMP MAIN1
;---------------------------------------中断程序入口---------------------
;时间中断0
;错误1:中断程序EXIT处用了MAIN1,导致一直处于中断状态
INT_0: PUSH ACC
PUSH PSW
MOV TH0,#3CH
MOV TL0,#0B1H
INC BUF
MOV A,BUF
CJNE A,#20,EXIT
TIME: MOV BUF,#0
INC SEC
MOV A,SEC
CJNE A,#60,EXIT
MOV SEC,#00H
INC MIN
MOV A,MIN
CJNE A,#60,EXIT
MOV MIN,#00H
INC HOUR
MOV A,HOUR
CJNE A,#24,EXIT
MOV HOUR,#0
RETI
EXIT: POP PSW
POP ACC
RETI
;时间中断1
INT_1: MOV TH1,#0D8H ;定时10MS
MOV TL1,#0F0H
INC S_SEC
MOV A,S_SEC
CJNE A,#100,EXIT4
MOV S_SEC,#0
INC M_SEC
MOV A,M_SEC
CJNE A,#100,EXIT4
MOV M_SEC,#0
EXIT4: RETI
;---------------------------------------显示-----------------------------
DISPLAY12: MOV A,MODE_RG ;判断模式,决定是显示闹钟时间还是显示当前时间
CJNE A,MODE4,DIS0 ;模式四,显示闹钟
LJMP DIS01 ;MODE4
DIS0: CJNE A,MODE5,DIS20
DIS01: MOV R7,H_ALARM ;闹钟模式
LJMP DIS2
DIS20: CJNE A,MODE6,DIS21
MOV R7,M_SEC ;秒表模式,显示秒表高位
LJMP DIS2
DIS21: CJNE A,MODE1,DIS1
LJMP DIS22
DIS22: MOV R7,MIN
LJMP DIS2
DIS1: MOV R7,HOUR ;DISPLAY12显示高位
DIS2: LCALL BCTD ;判断完毕,调用显示
;将秒、分 分别转码,放到R4,R3
MOV A,R4
MOV R3,A
LCALL DIVIDE
MOV DPTR,#NUMTAB
MOV P2,#0FH
MOV P2,LED0
MOV A,45H ;从拆字的出口获取值
MOVC A,@A+DPTR
MOV P0,A
LCALL DELY10MS
MOV P2,LED1
MOV A,46H
MOVC A,@A+DPTR
MOV P0,A
LCALL DELY10MS
RET
DISPLAY34: MOV A,MODE_RG ;判断模式,决定是显示闹钟时间还是显示当前时间
CJNE A,MODE4,DIS31
LJMP DIS32
DIS31: CJNE A,MODE5,DIS35
DIS32: MOV R7,M_ALARM
LJMP DIS34
DIS35: CJNE A,MODE6,DIS41
MOV R7,S_SEC ;秒表模式,显示秒表低位
LJMP DIS34
DIS41: CJNE A,MODE1,DIS33
MOV R7,SEC
LJMP DIS34
DIS33: MOV R7,MIN ;DISPLAY34显示低位
DIS34: LCALL BCTD
MOV A,R4
MOV R3,A
LCALL DIVIDE
MOV P2,LED2
MOV A,47H
MOVC A,@A+DPTR
MOV P0,A
LCALL DELY10MS
MOV P2,LED3
MOV A,48H
MOVC A,@A+DPTR
MOV P0,A
LCALL DELY10MS
SETB P23
RET
;--------------------二翻十:入口:R6R7 出口:R2R3R4----------------------
BCTD: MOV R5,#16
CLR A
MOV R2,A
MOV R3,A
MOV R4,A
LOOP: CLR C
MOV A,R7
RLC A
MOV R7,A
MOV A,R6
RLC A
MOV R6,A
MOV A,R4
ADDC A,R4
DA A
MOV R4,A
MOV A,R3
ADDC A,R3
DA A
MOV R3,A
MOV A,R2
ADDC A,R2
DA A
MOV R2,A
DJNZ R5,LOOP
RET
;-----------------------拆字:入口:R3R4 出口:45H46H47H48H------------------
DIVIDE: MOV A,R3
ANL A,#0FH
MOV 46H,A
MOV A,R3
ANL A,#0F0H
SWAP A
MOV 45H,A ;时拆字 45H放时高位,46H放十低位
MOV A,R4
ANL A,#0FH
MOV 48H,A
MOV A,R4
ANL A,#0F0H
SWAP A
MOV 47H,A ;分拆字 47H放分高位,48H放分低位
RET
;------------------------------------延时----------------------------------
DELY10MS: MOV R6,#10
D1: MOV R7,#248
DJNZ R7,$
DJNZ R6,D1
RET
DELAY: MOV 74H,#2 ;延时子程序,12M晶振延时1002秒
L3: MOV 72H ,#10
L1: MOV 73H ,#249
L2: DJNZ 73H ,L2
LCALL DISPLAY12
LCALL DISPLAY34
JNB DOWN_KEY,OFFALARM1
LJMP S3
OFFALARM1: LCALL DELY10MS
JB DOWN_KEY,S3
S4: JNB DOWN_KEY,S4
MOV F_ALARM,#0
SETB P36
LJMP MAIN1
S3: DJNZ 72H ,L1
DJNZ 74H ,L3
RET
NUMTAB: DB 0C0H,0F9H,0A4H,0B0H,99H,92H,82H,0F8H,80H,90H,88H,83H,0C6H,0A1H,86H,8EH ;码表
END
;TowTigerasm
;乐谱是:;1231 1231 345 345 565431 565431 25(低)1 25(低)1
;--------------------------------------------------------------------------------------------------
extrn delay:far
data segment
ftable dw 2 dup(262,294,330,262)
dw 2 dup(330,349,392,19)
dw 2 dup(392,440,392,349,330,262)
dw 2 dup(294,196,262,19),-1
ttable dw 8 dup(8)
dw 8 dup(8)
dw 2 dup(4,4,4,4,8,8)
dw 8 dup(8)
data ends
code segment
assume cs:code,ds:data
begin: mov ax,data
mov ds,ax
lea si,ftable
lea bp,ds:ttable
freq: mov di,[si]
cmp di,-1
je exit
mov bx,DS:[BP]
call sound
add si,2
add bp,2
jmp freq
exit: mov ah,4ch
int 21h
sound proc near
push ax
push bx
push cx
push dx
push di
mov al,0b6h
out 43h,al
mov dx,12h
mov ax,348ch
div di
out 42h,al
mov al,ah
out 42h,al
in al,61h
mov ah,al
or al,3
out 61h,al
call delay
mov al,ah
out 61h,al
pop di
pop dx
pop cx
pop bx
pop ax
ret
sound endp
code ends
end begin
;--------------------------------------------------------------------------------------------------
这中间还用到了一个延迟用的通用子程序: delay
在delayasm里实现:
;--------------------------------------------------------------------------------------------------
public delay
code segment
assume cs:code
delay proc far
push ax
ms250: mov cx,16666
us015: in al,61h
and al,10h
cmp al,ah
je us015
mov ah,al
loop us015
dec bl
jnz ms250
pop ax
ret
delay endp
code ends
end
其实很简单:下载一个masm615的压缩文件(直接在百度主页里搜“masm615下载”),大概432M,下载后,解压缩到D:盘,将文件夹的名字改为masm,这是因为解压后的名字默认为masm 615,中间有个空格不太好(因为再DOS下对于有空格的文件夹的名字要用双引号括起来,比较麻烦)。
1、用记事本或其他文本编辑器(例如Editplus)写好汇编程序,保存为asm格式的文件(直接将后缀名修改为asm),例如文件名为testasm,放到D:盘。
2、在windows下点击“开始”,再点击“运行”,在编辑框中输入cmd,切换到DOS界面下。进入D:盘——d:,再回车。
3、在当前目录(D:盘下)用cd命令,切换到刚才解压到D:盘的masm目录下的BIN目录下——
cd masm\bin
4、 然后生产目标文件,使用命令——masm D:\testasm(后缀名可以省略,默认为asm),生成obj的目标文件,该目标文件在D:\masm\BIN目录下。将生成的obj文件拷贝到D:盘根目录下(其实不用拷贝也行,只要下面能找到该obj文件就行,个人建议将obj文件和asm文件放到一起比较清楚)。
5、再使用命令将obj目标文件链接成exe文件(还在D:\masm\BIN目录下使用命令)——
link D:\testobj(后缀名可以省略,默认为obj),出现选项让你选,第一个选项是让你输入生成的exe文件的名字,例如输入——D:\testexe(后缀名可以省略,默认为exe),其他选项暂时可以不考虑(其实看他们的名字就能看懂)。这样就在D:盘下生成了一个testexe的可执行文件。
6、双击该文件,发现屏幕闪了一下就没了,说明程序是运行了。要想看到程序每一步的执行情况,那么生成的testexe文件要在Debug模式下运行。在DOS界面下(任何目录)输入命令——debug D:\testexe(此时后缀名exe必须要有),回车后就开始运行该可执行文件了。按照王爽那本书上从第91页开始的程序执行过程的跟踪使用的一些命令,例如:r命令、u命令、d命令、g命令、p命令等的使用,就能查看和控制程序的运行了。
求数据块的最小值和最大值
1)实验内容
在以BUFFER为首址的内存中存放了若干个带符号数, 其个数存放在首单元,寻找出它们最大值放到存储单元MAXVAL中, 最小值放到存储单元MINVAL中。汇编语言源程序如下:
DATA SEGMENT
BUFFER DB 10,22,33,-80,127,-76,0,90,-45,60,-1
MINVAL DB ?
MAXVAL DB ?
DATA ENDS
STACK SEGMENT PARA STACK ‘STACK’
STA DB 100 DUP()
STACK ENDS
CODE SEGMENT
ASSUME CS:CODE, DS:DATA, ES:DATA, SS:STACK
START PROC FAR
PUBH DS
MOV AX, 0
PUSH AX
MOV AX, DATA
MOV DS, AX
MOV ES, AX
LEA BX, BUFFER
MOV CH, 0
MOV CL, [BX]
INC BX
MOV AL, [BX]
MOV MINVAL, AL
MOV MAXVAL, AL
INC BX
DEC CX
AGAIN: MOV AL, [BX]
CMP AL, MINVAL
JE NEXT
JG A1
MOV MINVAL, AL
JMP NEXT
A1: CMP AL, MAXVAL
JL NEXT
MOV MAXVAL, AL
NEXT: INC BX
DEC CX
JNE AGAIN
RETF
START ENDP
CODE ENDS
END START
2)实验步骤
(1)用编辑程序建立源程序文件,文件名自定。
(2)用MASM宏汇编程序和LINK连接程序将源程序文件汇编生成以EXE为扩展名的执行文件。
(3)用DEBUG调试程序将由上产生的EXE可执行文件送入内存,先用反汇编命令检查程序内容和首末地址,然后检查以BUFFER为首址的存储单元中数据块和MINVAL、MAXVAL单元的内容。BUFFER 地址单元的段地址和偏移地址是由系统在汇编和连接时指定的。各个不同的系统都不一样,一般来说,偏移地址为零,段地址可在反汇编程序时,根据指令MOV AX, DATA 对应机器码中DATA的值来确定。
(4)在DEBUG下运行程序,检查运行结果。
(5)修改源程序中BUFFER数据区的各数据,重新汇编后再运行,检查结果。
以上就是关于单片机汇编语言设计程序的方法,步骤,思路全部的内容,包括:单片机汇编语言设计程序的方法,步骤,思路、C语言程序设计实验中汇编程序使用的寻址方式有、求单片机课程设计实验 用汇编语言,基于51单片机的定时闹钟等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)