1、;*根据查看端口资源修改下列符号值 *IOY0 EQU 0d800H;*MY8254_COUNT0 EQU 0C060H ;8254 计数器 0 端口地址MY8254_COUNT1 EQU 0C061H ;8254 计数器 1 端口地址MY8254_COUNT2 EQU 0C062H ;8254 计数器 2 端口地址MY8254_MODE EQU 0C063H ;8254 控制寄存器端口地址STACK1 SEGMENT STACK ;设置堆栈段DW 256 DUP(?)STACK1 ENDSDATA SEGMENT;*同一首歌 *FREQ_LIST DW 392,523,578,659,698
2、,659,523,578,523,440,523,392,523,578,659,659,698,784,523 ;频率表 同一首歌DW 698,659,784,578,659,659,578,578,659,784,988,988,880,880,784,784,880,988,880,784,659DW 698,698,784,880,784,698,659,578,494,494,440,392,440,523,1046,880,698,784,880TIME_LIST DB 16, 8, 8, 12, 4, 8, 8, 16, 8, 8, 32, 16, 8, 4,4,8,8 ;时间表
3、DB 12, 4, 8,4, 4, 4,4,32,16,8,8,12,4,16,8,4,4,8,4,4,32DB 12,4,8,8,8,4,4,16,8,4,4,8,8,32,16,16,12,4,16DATA ENDSCODE SEGMENTASSUME CS:CODE,DS:DATASTART:MOV AX,DATA ;这两条语句MOV DS,AX ;设置用户数据段MOV DX,MY8254_MODE ;初始化 8254 工作方式MOV AL,36H ;0011 0110 端口 0、方式 3OUT DX,ALBEGIN:MOV SI,OFFSET FREQ_LIST ;装入频率表起始地址M
4、OV DI,OFFSET TIME_LIST ;装入时间表起始地址PLAY: MOV DX,0FH ;输入时钟为 1.0416667MHz,1.0416667M = 0FE502HMOV AX,0E502HDIV WORD PTR SI ;取出频率值计算计数初值,0F4240H / 输出频率,WORD PTR SI这是强制定义为字大小 (两字节);DX:AX 表示的 32 位数除以 DS:SI 指向内存数据的 16 位数,结果商放在 AX,余数放在 DX 内 AX=1.0416667M/频率MOV DX,MY8254_COUNT0OUT DX,AL ;装入计数初值MOV AL,AHOUT DX
5、,ALMOV DL,DI ;取出演奏相对时间,调用延时子程序 , 8 位CALL DALLYADD SI,2INC DICMP WORD PTR SI,0 ;判断是否到曲末?JE BEGIN ;如果结束,重唱MOV AH,1 ;判断是否有按键按下?INT 16HJZ PLAYQUIT: MOV DX,MY8254_MODE ;退出时设置 8254 为方式 2,OUT0 置 0MOV AL,10H ;0001 0000 端口 0 方式 0,只读/ 写计数器低字节OUT DX,ALMOV AX,4C00H ;结束程序退出,返回操作系统INT 21HDALLY PROC ;延时子程序D0: MOV CX,0A00H ;循环 2560 次D1: MOV AX,0FFFFH ;65535D2: DEC AX ;AX-1JNZ D2 ;如果结果不为 0,跳至 D2LOOP D1DEC DL ;DL=DL-1JNZ D0 ;如果结果不为 0,跳至 D0RET ;过程返回DALLY ENDP ;子程序结束CODE ENDSEND START