📄 eleorgan.asm
字号:
;----------------------------------------------------------------------
; 完整程序代码
;----------------------------------------------------------------------
DRAW MACRO START_X,START_Y,END_X,END_Y,COLOR ;画实心矩形宏
LOCAL DRAW_NEXT
PUSH AX
PUSH BX
PUSH CX
PUSH DX
MOV AH,0CH ;写像素点
MOV AL,COLOR ;设置颜色
MOV BH,0 ;选用页号0
MOV CX,START_X ;列起始点
MOV DX,START_Y ;行起始点
DRAW_NEXT:
INT 10H ;画点
INC CX ;画横线
CMP CX,END_X ;比较行是否画完
JNE DRAW_NEXT ;画另一行
MOV CX,START_X ;另一行的起始点
INC DX
CMP DX,END_Y ;比较列是否画完
JNE DRAW_NEXT ;未完继续画
POP DX
POP CX
POP BX
POP AX
ENDM
DRAWSQRE MACRO START_X,START_Y,END_X,END_Y,COLOR ;画空心矩形宏
LOCAL ROW_UP,RANK_RIGHT,ROW_DOWN,RANK_LEFT
PUSH AX
PUSH BX
PUSH CX
PUSH DX
PUSH SI
MOV AH,0CH
MOV AL,COLOR
MOV BH,0
MOV CX,START_X ;横坐标
MOV DX,START_Y ;纵坐标
ROW_UP: ;画上边
INT 10H
INC CX
CMP CX,END_X
JNE ROW_UP
RANK_RIGHT: ;画右边
INT 10H
INC DX
CMP DX,END_Y
JNE RANK_RIGHT
MOV CX, START_X ;下边起始点
MOV SI,END_X
INC SI
ROW_DOWN: ;画下边
INT 10H
INC CX
CMP CX,SI
JNE ROW_DOWN
MOV DX,START_Y ;右边起始点
MOV CX,START_X
RANK_LEFT: ;画右边
INT 10H
INC DX
CMP DX, END_Y
JNE RANK_LEFT
POP SI
POP DX
POP CX
POP BX
POP AX
ENDM
DATA SEGMENT
SPACE DW 500 DUP(?) ;存放弹奏录音的音符
TIME DW 500 DUP(300) ;存放弹奏录音的音长
MUS_FREQ DW 392,392,440,294,262,262,220,294 ;预存歌曲《东方红》频率
DW 392,392,440,523,440,392,262,262,220,294
DW 392,294,262,247,220,196,392,294,330,294
DW 262,262,220,294,330,294,262,294,262,247,220,196
DW 392,294,262,247,220,196,392,294,330,294
DW 262,262,220,294,330,294,262,554,523,494,440,392,-1
MUS_TIME DW 3000,1500,1500,6000,3000,1500,1500,6000 ;预存歌曲《东方红》音长
DW 3000,3000,1500,1500,1500,1500,3000,1500,1500,6000
DW 3000,3000,3000,1500,1500,3000,3000,3000,1500,1500
DW 3000,10 DUP(1500),6000
DW 3000,3000,3000,1500,1500,3 DUP(3000),1500,1500
DW 3000,1500 DUP(10),6000
TEXT1 DB ' FUNNY PIANO ',0DH,0AH,0DH,0AH,'$' ;显示文本
TEXT2 DB 'Designed By WANG QI ',0DH,0AH,'$'
TEXT3 DB 'Copyright 2006','$'
TEXT4 DB 'BACH MOZART BEETHOVEN BRAHMS CHOPIN','$'
SPEED DW 1 ;播放乐曲的速度标记
STAND_ST DW 100,122,144,166,188,210,232,254,276,298,320 ;画白键的边框
342,364,386,408,430,452,474,496,518,540
STAND_ED DW 120,142,164,186,208,230,252,274,296,318,340,
362,384,406,428,450,472,494,516,538,560
ST_LX DW 100,122,144,166,188,210,232 ;白色琴键坐标
ST_MX DW 254,276,298,320,342,364,386
ST_HX DW 408,430,452,474,496,518,540
ST_Y DW 160
ED_LX DW 120,142,164,186,208,230,252
ED_MX DW 274,296,318,340,362,384,406
ED_HX DW 428,450,472,494,516,538,560
ED_Y DW 230
BT_X DW 112,134,178,200,222 ;黑色琴键坐标
BT_Z DW 266,288,332,354,376
DW 420,442,486,508,530
BT_Y DW 160
BD_X DW 128,150,194,216,238
BD_Z DW 282,304,348,370,392
DW 436,458,502,524,546
BD_Y DW 205
MES DB ' WELCOME TO ELE_PIANO! ',0DH,0AH
DB ' PRESS 1-8 TO PLAY THE PIANO ',0DH,0AH
DB ' PRESS Z AND NUMBER TO AUTO_PLAY ',0DH,0AH
DB ' PRESS ESC TO RETURN TO DOS ','$'
DATA ENDS
CODE SEGMENT
ASSUME DS:DATA,CS:CODE
START:
MOV AX,DATA
MOV DS,AX
MOV AL,10000000B ;初始化 8255
MOV DX,28BH ;PORT A,模式0
OUT DX,AL
CALL INIT ;初始化屏幕
MOV DH,26
MOV DL,0
MOV AH,2 ;置光标位置
INT 10H
MOV DX,OFFSET MES
MOV AH,9 ;显示提示信息
INT 21H
GET: MOV AH,7 ;读入键盘输入
INT 21H
JUDGE_P: ;判断是否播放录音
CMP AL,'P'
JNZ JUDGE
MOV AX,-1
MOV [BX],AX
CALL MUSIC1
MOV BX,OFFSET SPACE
JMP GET
JUDGE: CMP AL,'Z' ;若输入是'Z',播放乐曲
JNZ COMPARE ;否则判断是哪个音符
MOV AH,7 ;输入播放乐曲速度
INT 21H
SUB AL,'0' ;获得速度
MOV AH,0
MOV SPEED,AX
CALL MUSIC
JMP GET
COMPARE: ;判断是否为do
CMP AL,'1'
JNZ SHARP_DO
MOV AX,261 ;将弹奏音符存入space中
MOV [BX],AX
ADD BX,2
LEA SI,ST_MX
LEA DI,ED_MX
DRAW [SI],230,[DI],238,0FH ;灰色变白色:琴键按下
MOV CX,261 ;计数初值OF 1
CALL BEEP
DRAW [SI],230,[DI],238,07H ;白色变灰色:琴键弹起
JMP GET
SHARP_DO: ;判断是否为升do
CMP AL,'Q'
JNZ RE
MOV AX,261 ;将弹奏音符存入space中
MOV [BX],AX
ADD BX,2
LEA SI,BT_Z
LEA DI,BD_Z
DRAW [SI],199,[DI],205,00H ;灰色变白色:琴键按下
MOV CX,277 ;计数初值 OF #1
CALL BEEP
DRAW [SI],199,[DI],205,07H ;白色变灰色:琴键弹起
JMP GET
RE: CMP AL,'2' ;判断是否为re
JNZ SHARP_RE
MOV AX,261 ;将弹奏音符存入space中
MOV [BX],AX
ADD BX,2
LEA SI,ST_MX
LEA DI,ED_MX
ADD SI,2
ADD DI,2
DRAW [SI],230,[DI],238,0FH ;灰色变白色:琴键按下
MOV CX,294 ;计数初值 OF 2
CALL BEEP
DRAW [SI],230,[DI],238,07H ;白色变灰色:琴键弹起
JMP GET
SHARP_RE: ;判断是否为升re
CMP AL,'W'
JNZ MI
MOV AX,261 ;将弹奏音符存入space中
MOV [BX],AX
ADD BX,2
LEA SI,BT_Z
LEA DI,BD_Z
ADD SI,2
ADD DI,2
DRAW [SI],199,[DI],205,00H ;灰色变白色:琴键按下
MOV CX,311 ;计数初值 OF #2
CALL BEEP
DRAW [SI],199,[DI],205,07H ;白色变灰色:琴键弹起
JMP GET
MI: CMP AL,'3' ;判断是否为mi
JNZ FA
MOV AX,261 ;将弹奏音符存入space中
MOV [BX],AX
ADD BX,2
LEA SI,ST_MX
LEA DI,ED_MX
ADD SI,4
ADD DI,4
DRAW [SI],230,[DI],238,0FH ;灰色变白色:琴键按下
MOV CX,330 ;计数初值 OF 3
CALL BEEP
DRAW [SI],230,[DI],238,07H ;白色变灰色:琴键弹起
JMP GET
FA: CMP AL,'4' ;判断是否为fa
JNZ SHARP_FA
MOV AX,261 ;将弹奏音符存入space中
MOV [BX],AX
ADD BX,2
LEA SI,ST_MX
LEA DI,ED_MX
ADD SI,6
ADD DI,6
DRAW [SI],230,[DI],238,0FH ;灰色变白色:琴键按下
MOV CX,349 ;计数初值 OF 4
CALL BEEP
DRAW [SI],230,[DI],238,07H ;白色变灰色:琴键弹起
JMP GET
SHARP_FA: ;判断是否为升fa
CMP AL,'R'
JNZ SO
MOV AX,261 ;将弹奏音符存入space中
MOV [BX],AX
ADD BX,2
LEA SI,BT_Z
LEA DI,BD_Z
ADD SI,4
ADD DI,4
DRAW [SI],199,[DI],205,00H ;灰色变白色:琴键按下
MOV CX,370 ;计数初值 OF #4
CALL BEEP
DRAW [SI],199,[DI],205,07H ;白色变灰色:琴键弹起
JMP GET
SO: CMP AL,'5' ;判断是否为so
JNZ SHARP_SO
MOV AX,261 ;将弹奏音符存入space中
MOV [BX],AX
ADD BX,2
LEA SI,ST_MX
LEA DI,ED_MX
ADD SI,8
ADD DI,8
DRAW [SI],230,[DI],238,0FH ;灰色变白色:琴键按下
MOV CX,392 ;计数初值 OF 5
CALL BEEP
DRAW [SI],230,[DI],238,07H ;白色变灰色:琴键弹起
JMP GET
SHARP_SO: ;判断是否为升so
CMP AL,'T'
JNZ LA
MOV AX,261 ;将弹奏音符存入space中
MOV [BX],AX
ADD BX,2
LEA SI,BT_Z
LEA DI,BD_Z
ADD SI,6
ADD DI,6
DRAW [SI],199,[DI],205,00H ;灰色变白色:琴键按下
MOV CX,415 ;计数初值 OF #5
CALL BEEP
DRAW [SI],199,[DI],205,07H ;白色变灰色:琴键弹起
JMP GET
LA: CMP AL,'6' ;判断是否为la
JNZ SHARP_LA
MOV AX,261 ;将弹奏音符存入space中
MOV [BX],AX
ADD BX,2
LEA SI,ST_MX
LEA DI,ED_MX
ADD SI,10
ADD DI,10
DRAW [SI],230,[DI],238,0FH ;灰色变白色:琴键按下
MOV CX,440 ;计数初值 OF 6
CALL BEEP
DRAW [SI],230,[DI],238,07H ;白色变灰色:琴键弹起
JMP GET
SHARP_LA: ;判断是否为升la
CMP AL,'Y'
JNZ XI
MOV AX,261 ;将弹奏音符存入space中
MOV [BX],AX
ADD BX,2
LEA SI,BT_Z
LEA DI,BD_Z
ADD SI,8
ADD DI,8
DRAW [SI],199,[DI],205,00H ;灰色变白色:琴键按下
MOV CX,466 ;计数初值 OF #6
CALL BEEP
DRAW [SI],199,[DI],205,07H ;白色变灰色:琴键弹起
JMP GET
XI: CMP AL,'7' ;判断是否为xi
JNZ HIGH_DO
MOV AX,261 ;将弹奏音符存入space中
MOV [BX],AX
ADD BX,2
LEA SI,ST_MX
LEA DI,ED_MX
ADD SI,12
ADD DI,12
DRAW [SI],230,[DI],238,0FH ;灰色变白色:琴键按下
MOV CX,494 ;计数初值 OF 7
CALL BEEP
DRAW [SI],230,[DI],238,07H ;白色变灰色:琴键弹起
JMP GET
HIGH_DO: ;判断是否为高音do
CMP AL,'8'
JNZ IF_ESC
MOV AX,261 ;将弹奏音符存入space中
MOV [BX],AX
ADD BX,2
LEA SI,ST_MX
LEA DI,ED_MX
ADD SI,14
ADD DI,14
DRAW [SI],230,[DI],238,0FH ;灰色变白色:琴键按下
MOV CX,523 ;计数初值 OF 8
CALL BEEP
DRAW [SI],230,[DI],238,07H ;白色变灰色:琴键弹起
JMP GET
IF_ESC:
CMP AL,27 ;是否是'ESC'
JZ GO_BACK
JMP GET ;不是,继续读数
GO_BACK:
MOV AX,0003 ;调回显示模式
INT 10H
MOV AH,4CH ;返回dos
INT 21H
;---------------------------------------------------------------
INIT PROC NEAR ;初始化屏幕:画琴键
MOV AX,DATA
MOV DS,AX
MOV AH,0 ;设置屏幕显示方式
MOV AL,12H ;VGA 640×480 16色
INT 10H
MOV AH,0BH ;置彩色调板
MOV BH,0
MOV BL,00H ;背景色
INT 10H
DRAWSQRE 70,60,590,412,0CH ;框框
DRAWSQRE 74,62,586,410,0EH ;框框
DRAW 260,330,387,358,09H ;TEXT1的框框
MOV DH,21 ;行
MOV DL,34 ;列
MOV AH,2 ;置光标位置
INT 10H
MOV DX,OFFSET TEXT1
MOV AH,9 ;显示字符串
INT 21H
DRAW 220,359,427,385,09H ;TEXT2的框框
MOV DH,23
MOV DL,30
MOV AH,2 ;置光标位置
INT 10H
MOV DX,OFFSET TEXT2
MOV AH,9 ;显示字符串
INT 21H
DRAW 255,386,392,405,09H ;TEXT3的框框
MOV DH,24
MOV DL,33
MOV AH,2 ;置光标位置
INT 10H
MOV DX,OFFSET TEXT3
MOV AH,9 ;显示字符串
INT 21H
DRAW 85,120,575,260,09H ;蓝色
DRAWSQRE 85,120,575,260,0AH ;绿色
DRAW 90,125,570,145,10 ;浅绿色
;DRAWSQRE 90,150,570,250,0EH
MOV DH,8 ;行
MOV DL,22 ;列
MOV AH,2 ;置光标位置
INT 10H
MOV DX,OFFSET TEXT4
MOV AH,9 ;显示字符串
INT 21H
LEA SI,ST_LX ;画21个白色键
LEA DI,ED_LX
MOV CX,21
INIT_DRAW:
DRAW [SI],ST_Y,[DI],ED_Y,0FH ;0FH白色
DRAW [SI],230,[DI],238,07H ;阴影
ADD SI,2
ADD DI,2
LOOP INIT_DRAW
LEA SI,BT_X ;画15个黑色键
LEA DI,BD_X
MOV CX,15
INIT_BLOCK:
DRAW [SI],BT_Y,[DI],BD_Y,00H ;00H黑色
DRAW [SI],199,[DI],205,07H ;阴影
ADD SI,2
ADD DI,2
LOOP INIT_BLOCK
RET
;--------------------------------------------------------------
BEEP PROC NEAR ;扬声器发声子程序
MOV AL,00110110B ;8253计数器0方式3,16位2进制
MOV DX,283H
OUT DX,AL
MOV DX,12H ;1.19MHZ对应初值
MOV AX,348CH ;1.19MHZ
DIV CX ;计数初值放于AX
;8253计数初值
MOV DX,280H ;计数器 0
OUT DX,AL
MOV AL,AH ;先写低位,后写高位
OUT DX,AL
MOV DX,288H ;读8255 PA口
IN AL,DX
MOV AH,AL ;将数据暂存
OR AL,03H
OUT DX,AL ;打开gate2,使out2输出到扬声器
GET1: IN AL,60H ;判断按键是否持续
TEST AL,80H
JNZ STOP
JMP GET1
STOP: MOV AL,AH ;回复8255A的pA口原值,停止发声
MOV DX,288H
OUT DX,AL
RET
BEEP ENDP
;--------------------------------------------------------
MUSIC PROC NEAR ;乐曲播放子程序
LEA BP,DS:MUS_TIME
LEA SI,MUS_FREQ
FREQ: MOV DI,[SI]
CMP DI,-1 ;如果是末尾
JZ END_MUS
MOV BX,DS:[BP] ;BX 储存发声时间
MOV DX,0
MOV AX,BX
DIV SPEED
MOV BX,AX
CALL SOUNDF
ADD SI,2
ADD BP,2
MOV AH,01H ;播放时有按键退出
INT 16H
JNZ END_MUS
JMP FREQ
END_MUS:
RET
MUSIC ENDP
;---------------------------------------------------------
SOUNDF PROC NEAR ;乐曲播放音符长短程序
MOV AL,00110110B
OUT 283H,AL
MOV DX,12H ;1.19MHZ对应的初值
MOV AX,348CH ;1.19MHZ
DIV DI
MOV DX,280H
OUT DX,AL ;通道 0
MOV AL,AH
OUT DX,AL
MOV DX,288H
IN AL,DX ;PORT A
MOV AH,AL
OR AL,3
OUT DX,AL
AA: MOV CX,0
DELAY: LOOP DELAY
DEC BX
JNZ AA
MOV AL,AH
OUT DX,AL
RET
SOUNDF ENDP
;----------------------------------------------------------
INIT ENDP
CODE ENDS
END START
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -