;首先对8254和点阵显示的端口进行定义
IOY3 EQU 06C0H
MY8254_COUNT0 EQU IOY3+00H ;8254计数器0端口地址
MY8254_MODE EQU IOY3+06H ;8254控制寄存器端口地址
ROW1 EQU 0600H ;点阵端口定义
ROW2 EQU 0640H
COL1 EQU 0680H
COL2 EQU 06C0H
DATA SEGMENT
;下面是存放的汉字,利用软件将转换为点阵显示对应的码。
;我 CCED2
WHWDZG DB 020H,002H,070H,00AH,01EH,012H,010H,012H
DB 010H,002H,0FFH,07FH,010H,002H,010H,022H
DB 050H,022H,030H,012H,018H,00CH,016H,044H
DB 010H,04AH,010H,051H,0D4H,060H,008H,040H
;和 CBACD
DB 020H,000H,070H,000H,01EH,000H,010H,03EH
DB 010H,022H,0FFH,022H,010H,022H,018H,022H
DB 038H,022H,054H,022H,054H,022H,012H,022H
DB 011H,03EH,010H,022H,010H,000H,010H,000H
;我 CCED2
DB 020H,002H,070H,00AH,01EH,012H,010H,012H
DB 010H,002H,0FFH,07FH,010H,002H,010H,022H
DB 050H,022H,030H,012H,018H,00CH,016H,044H
DB 010H,04AH,010H,051H,0D4H,060H,008H,040H
;的 CB5C4
DB 008H,002H,008H,002H,004H,002H,07EH,03EH
DB 042H,021H,042H,021H,0C2H,020H,042H,022H
DB 07EH,024H,042H,024H,042H,020H,042H,020H
DB 042H,020H,07EH,020H,042H,014H,000H,008H
;祖 CD7E6
DB 004H,000H,088H,01FH,088H,010H,09FH,010H
DB 090H,010H,088H,01FH,088H,010H,09CH,010H
DB 0AAH,010H,0A9H,01FH,088H,010H,088H,010H
DB 088H,010H,088H,010H,0E8H,07FH,008H,000H
;国 CB9FA
DB 000H,000H,0FEH,03FH,002H,020H,002H,020H
DB 0FAH,02FH,082H,020H,082H,020H,0F2H,027H
DB 082H,020H,082H,022H,082H,024H,0FAH,02FH
DB 002H,020H,002H,020H,0FEH,03FH,002H,020H
HuanLe DB 000H,001H,000H,001H,03FH,001H,020H,03FH
DB 0A0H,020H,092H,010H,054H,002H,028H,002H
DB 008H,002H,014H,005H,024H,005H,0A2H,008H
DB 081H,008H,040H,010H,020H,020H,010H,040H
;/*乐 CC0D6 */
DB 000H,000H,000H,00FH,0F8H,000H,008H,000H
DB 088H,000H,084H,000H,084H,000H,0FCH,03FH
DB 080H,000H,090H,004H,090H,008H,088H,010H
DB 084H,020H,082H,020H,0A0H,000H,040H,000H
;/*颂 CCBCC */
DB 000H,000H,014H,07FH,024H,004H,024H,002H
DB 042H,03FH,04AH,021H,009H,029H,008H,029H
DB 004H,029H,004H,029H,012H,029H,022H,025H
DB 03FH,00CH,022H,012H,000H,021H,0C0H,040H
;教 CBDCC
GodFather DB 010H,004H,010H,004H,07EH,005H,090H,07CH
DB 050H,022H,0FFH,022H,010H,022H,07EH,025H
DB 024H,014H,012H,014H,0F1H,008H,01EH,008H
DB 010H,014H,010H,012H,014H,021H,088H,040H
;父 CB8B8
DB 020H,002H,010H,004H,008H,008H,004H,010H
DB 002H,024H,010H,004H,010H,004H,020H,002H
DB 020H,002H,040H,001H,080H,000H,040H,001H
DB 020H,002H,010H,004H,00CH,018H,003H,060H
;下面是在程序一开始显示的提示信息
sentence1 DB 0DH,0AH,"- - -HB MUSIC BOX- - -"
sentence2 DB 0DH,0AH,"- - -INPUT ERROR- - -",'$'
sentence3 DB 0DH,0AH,"---------------------"
DB 0DH,0AH,"--------MENU---------"
DB 0DH,0AH,"1 WHWDZG"
DB 0DH,0AH,"2 Due To Joy"
DB 0DH,0AH,"3 GodFather"
DB 0DH,0AH,"---------------------"
DB 0DH,0AH,"----------------------------"
DB 0DH,0AH,"PLEASE SELECT MUSIC:",'$'
;MUSIC_ONE是第一首歌对应的频率表,演奏时在这里获取数据为8254计算计数初值
MUSIC_ONE DW 525,589,525,467,441,393,350,262,350,441,770,661,589,441,525
DW 589,661,589,525,467,441,393,294,330,294,262,525,350,363,441
DW 525,589,525,467,441,393,350,262,350,441,770,661,786,700,589
DW 700,661,589,525,589,525,467,441,330,294,262,393,350
DW 700,786,882,786,700,589,661,589,441,525,700,786,882,786,700,589,661,525,441,589
DW 525,467,441,393,330,294,262,441,467,393,350
DW 700,786,882,786,700,589,661,589,441,525,700,786,882,786,700,589,661,525,441,589
DW 525,467,441,393,330,294,262,441,525,786,700,0
;TIME_ONE是第一首歌的节拍表,在控制节拍时,在这里面找到相应的数放入DL中,并调用延时程序
TIME_ONE DW 4,4,4,4,4,4,12,12,4,4,4,4,6,2,24
DW 4,4,4,4,4,4,12,12,4,4,4,4,6,2,24
DW 4,4,4,4,4,4,12,12,4,4,4,4,6,2,24
DW 4,4,4,12,4,4,4,12,8,4,8,4,24
DW 4,4,4,4,4,4,4,6,2,24,4,4,4,4,4,4,6,2,24
DW 4,4,4,12,4,4,4,12,12,8,4,24
DW 4,4,4,4,4,4,4,6,2,12,4,4,4,4,4,4,4,6,2,12
DW 4,4,4,4,12,4,4,4,12,12,8,28,4
MUSIC_TWO DW 624,624,661,742,742,661,624
DW 556,495,495,556,624,624,556,556
DW 624,624,661,742,742,661,624,556
DW 495,495,556,624,556,495,495
DW 556,556,624,495,556,624,661,624,495
DW 556,624,661,624,556,495,556,371
DW 624,624,661,742,742,661,624,556
DW 495,495,556,624,556,495,495,0
TIME_TWO DW 4,4,4,4,4,4,4,4,4,4,4,4,6,4,8
DW 4,4,4,4,4,4,4,4,4,4,4,4,6,4,8
DW 4,4,4,4,4,2,2,4,4,4,2,2,4,4,4,4,8
DW 4,4,4,4,4,4,4,4,4,4,4,4,6,4,8
MUSIC_THREE DW 330,441,525,495,441,525,441,495,441,350,393
DW 330,330,441,525,495,441,525,441,495,441,330,315
DW 294,294,350,410,495,294,350,393,441,221,131,221,131,196
DW 350,330,393,350,350,330,330,205,221,211,221,221
DW 393,495,441,350,330,330,393,330,294,294,350,310
DW 294,350,420,495,294,350,420,441,221,262,393
DW 350,330,393,350,350,330,330,205,441,0
TIME_THREE DW 4,4,4,4,4,4,4,4,4,4,4
DW 16,4,4,4,4,4,4,4,4,4,4,4
DW 16,4,4,4,20,4,4,4,16,4,4,4,4,4
DW 4,4,4,4,4,4,4,4,16,4,4,4
DW 16,8,4,4,16,4,4,4,20,4,4,4
DW 16,4,4,4,4,20,4,4,4,16,4,4,4
DW 4,4,4,4,4,4,4,4,32,4
DATA ENDS
STACK1 SEGMENT STACK
;堆栈段,用于保存数值,通过PUSH和POP对原有的数据进行保存与恢复
DW 256 DUP(?)
STACK1 ENDS
CODE SEGMENT
ASSUME DS:DATA,CS:CODE
START:
;先对8254进行初始化
MOV AX,DATA ;数据段装入段寄存器DS
MOV DS,AX
MOV DX,MY8254_MODE ;初始化8254工作方式
MOV AL,36H ;定时器0、方式3,00零号计数器 11 先低八位后高八位 011方式三 0 二进制。
OUT DX,AL
;通过宏定义,定义一个输出函数,在想要输出提示信息时会很方便
output MACRO a;定义输出的函数
LEA DX,a
MOV AH,09h;使用DOS中的9号调用显示字符串
INT 21H
ENDM
output sentence1
output sentence3
;下面是input输入函数,调用了DOS的1号调用,
;从键盘上输入字符的ASCII码并放入AL寄存器中,并显示
INPUT:
MOV AH,01H ;键盘输入字符并回显
INT 21H
PUSH AX;AX中的数据很重要,所以这里先将AX中的数据保存起来
JMP input_select;跳转到判断输入的程序中
input_select:
POP AX;恢复AX中的数据
CMP AL,'Q'
JZ START ;退出
CMP AL,'q'
JZ START ;跳转到start
CMP AL,'1'
JNZ B0
CALL MUSIC1;如果输入为1则播放歌曲一
B0:
CMP AL,'2';播放歌曲二
JNZ C0
CALL MUSIC2
C0:
CMP AL,'3'
JNZ INPUT_FALSE;输入不是123Qq时跳转到输入错误显示
CALL MUSIC3;播放音乐三
INPUT_FALSE: output sentence2 ;宏调用,输入错误,重新输入
;点阵的延时函数
DELAY PROC
PUSH CX ;延时子程序
MOV CX, 0100H
DL1: PUSH AX
POP AX
LOOP DL1
POP CX
RET
DELAY ENDP
MUSIC1 PROC
;初始化点阵显示
;先保存数据,再初始化端口号
PUSH DX
PUSH AX
PUSH BX
MOV DX, ROW1
MOV AL, 00H
OUT DX, AL
MOV DX, ROW2
OUT DX, AL
MOV AL, 0ffH
MOV DX, COL1
OUT DX, AL
MOV DX, COL2
OUT DX, AL
BG0:MOV AX, 81
MOV SI, OFFSET WHWDZG
BG1:CALL DISP;调用显示函数显示字符,AX为显示次数,调整AX可以调整显示的时间
ADD SI, 2;AX过大可能会乱码,AX过小可能会导致显示不全
DEC AX
JZ MU1;显示完成之后跳转到音乐播放函数
JMP BG1
MU1:POP BX
POP AX
POP DX ;在播放音乐前必须对8254进行初始化,否则会出错
MOV DX,MY8254_MODE ;初始化8254工作方式
MOV AL,36H ;定时器0、方式3
OUT DX,AL
MOV SI,OFFSET MUSIC_ONE ;装入频率表起始地址
MOV DI,OFFSET TIME_ONE ;装入时间表起始地址
JMP PLAY
MUSIC1 ENDP
MUSIC2 PROC
PUSH DX;放入栈中保存,其实没什么必要,但是为了严谨
PUSH AX
PUSH BX
MOV DX, ROW1;初始化点阵显示
MOV AL, 00H
OUT DX, AL
MOV DX, ROW2
OUT DX, AL
MOV AL, 0ffH
MOV DX, COL1
OUT DX, AL
MOV DX, COL2
OUT DX, AL
BG02:MOV AX, 33
MOV SI, OFFSET HuanLe
BG12:CALL DISP;调用显示函数显示字符
ADD SI, 2
DEC AX
JZ MU2
JMP BG12
MU2:POP BX;恢复
POP AX
POP DX
MOV DX,MY8254_MODE ;初始化8254工作方式
MOV AL,36H ;定时器0、方式3
OUT DX,AL
MOV SI,OFFSET MUSIC_TWO ;装入频率表起始地址
MOV DI,OFFSET TIME_TWO ;装入时间表起始地址
JMP PLAY
MUSIC2 ENDP
MUSIC3 PROC
MOV DX, ROW1;初始化点阵显示
MOV AL, 00H
OUT DX, AL
MOV DX, ROW2
OUT DX, AL
MOV AL, 0ffH
MOV DX, COL1
OUT DX, AL
MOV DX, COL2
OUT DX, AL
BG03:MOV AX, 18
MOV SI, OFFSET GodFather
BG13:CALL DISP;调用显示函数
ADD SI, 2
DEC AX
JZ MU3
JMP BG13
MU3:MOV DX,MY8254_MODE ;初始化8254工作方式
MOV AL,36H ;定时器0、方式3
OUT DX,AL
MOV SI,OFFSET MUSIC_THREE ;装入频率表起始地址
MOV DI,OFFSET TIME_THREE ;装入时间表起始地址
JMP PLAY
MUSIC3 ENDP
PLAY:
;调用
MOV AH,1;检测键盘上的输入,输入后ASCII码放在AL中,判断有无输入,无输入将ZF变为1,不会调用中断程序。
INT 16H
JZ SOUND
JMP input
SOUND:MOV DX,0FH ;输入时钟为1MHz,1M=0F4240H
MOV AX,4240H
DIV WORD PTR [SI] ;取出频率值计算计数初值0F4240H / 输出频率
MOV DX,MY8254_COUNT0
OUT DX,AL ;装入计数初值
MOV AL,AH ;将商AX的低八位和高八位分别输出
OUT DX,AL
MOV DL,[DI] ;取出演奏时间,调用延时子程序
CALL DALLY
ADD SI,2 ;定义的值为DW,地址每次+2
ADD DI,2
CMP WORD PTR [SI],0 ;每首歌结尾都为0,用当前频率值与0比较,若相等,则标志位ZF=1
JE END_MUSIC ;若ZF=0,跳转
JMP PLAY
END_MUSIC:
MOV DX,MY8254_MODE ;初始化8254工作方式
MOV AL,36H ;定时器0、方式3
OUT DX,AL
JMP START ;播放完音乐跳转到开始界面
;工作过程:点阵的显示是利用了人的视觉效果,先把一块的显示,之后再将SI加2,相当于向上滚动一行
;每次都加2就相当于连续滚动,就有了滚动的效果。所以每次显示完整个屏幕后都要将SI-=32,因为16行
;每行由2个8位二进制数控制。
;先将初始化,因为电路的原因,本来应该是row = 0,col = 1显示,这里正好相反,所以取SI之后要not一下
;用BL通过循环左移进行加上延时程序将每一行显示,完成所有的显示之后再将SI -= 32,这样就确保了下一步
;添加一行之后能和之前的接上。RET之后将SI += 2这样就能保证下次显示的是上一次之后一行的了。一次类推就
;在眼中形成了滚动显示的效果。通过调整AX的值使显示的时间改变,这里,如果AX过小则不能显示完全,过大就会
;显示定义数据之后的乱码。所以,应该将AX设置为字符中所有 (XXH 数量和 - 32)/ 2。
;======显示汉字子程序======
;入口参数: SI = 存放汉字起始地址
DISP PROC
MOV CX, 000FH
PUSH AX
ML0: PUSH CX
MOV BL, 01H
MOV CX, 0008H
ML1: MOV DX, ROW1 ;控制0--7行
MOV AL, 00H
OUT DX, AL
MOV AL, [SI]
not al
MOV DX, COL1 ;0--7列
OUT DX, AL
INC SI
MOV AL, [SI]
not al
MOV DX, COL2 ;8--15列
OUT DX, AL
INC SI
MOV DX, ROW1 ;控制0--7行
MOV AL, BL
OUT DX, AL
ROL BL, 1
CALL DELAY
LOOP ML1
MOV DX, ROW1
MOV AL, 00H
OUT DX, AL
MOV CX, 0008H
ML2: MOV DX, ROW2 ;控制8--15行
MOV AL, 00H
OUT DX, AL
MOV AL, [SI]
not al
MOV DX, COL1 ;0--7列
OUT DX, AL
INC SI
MOV AL, [SI]
not al
MOV DX, COL2 ;8--15列
OUT DX, AL
INC SI
MOV DX, ROW2 ;控制8--15行
MOV AL, BL
OUT DX, AL
ROL BL, 1
CALL DELAY
LOOP ML2
MOV DX, ROW2
MOV AL, 00H
OUT DX, AL
SUB SI, 32
POP CX
LOOP ML0
POP AX
RET
DISP ENDP
;下面是点阵对应的延时子程序
DALLY PROC ;延时子程序
D0:
MOV CX,0010H
D1:
MOV AX,0F00H
D2:
DEC AX
JNZ D2
LOOP D1 ;循环次数由CX决定
DEC DL
JNZ D0
RET
DALLY ENDP
CODE ENDS
END START
code
最新推荐文章于 2022-11-16 18:39:51 发布