code

;首先对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;每行由28位二进制数控制。
;先将初始化,因为电路的原因,本来应该是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




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值