📄 sin.asm
字号:
;******************************************************************************************
;题目:正弦波信号发生器
;要求:要求模拟正弦波信号发生器,将正弦波信号显示在显示器上,信号的周期,峰;值可以键盘输入。
;应用:理解数字信号的发生原理。
;提示:运用分支,循环,子程序等编程形式,运用键盘显示器,文件的中断调用。
;-----------------------------------------------------------------------
;注意:所画图形必须在全屏状态下才能显示。
;******************************************************************************************
mode_11 = 11h ;640*480 2 colors
x_axisy = 240
x_axisx = 20
x_axislen = 600
y_axisx = 320
y_axisy = 10
y_axislen = 460
white = 1
;ax:line bx:colomn
writedot macro ;写像素
mov cx,ax
mov dx,bx
mov ah,0ch
mov al,01
mov bh,0
int 10h
endm
data segment
direction db ?
angle dw ?
savemode db ?
currX dw ?
currY dw ?
t db 6,?,7 dup(?) ;周期
num_t dw ?
a db 5,?,6 dup(?) ;幅度
num_a dw ?
mess_t db 'T:$'
mess_a db 'A:$'
mess1 db 13,10,"Error:Over flow!",13,10,'$'
table db 100,100,100,100,100,100,099,099,099,099
db 098,098,098,097,097,097,096,096,095,095
db 094,093,093,092,091,091,090,089,088,087
db 087,086,085,084,083,082,081,080,079,078
db 077,075,074,073,072,071,069,068,067,066
db 064,063,062,060,059,057,056,054,053,052
db 050,048,047,045,044,042,041,039,037,036
db 034,033,031,029,028,026,024,022,021,019
db 017,016,014,012,010,009,007,005,003,002,000
data ends
code segment
assume cs:code,ds:data
main proc far
mov ax,data
mov ds,ax
call input ;输入周期和峰值
call xy ;画笛卡尔坐标系
mov direction,0 ;画正半轴
call DrawSin
mov direction,1 ;画负半轴
call DrawSin
;Wait for a keystroke
mov ah,10h ;wait for key
int 16h
;Restroe the starting video mode
mov ah,0
mov al,savemode
int 10h
;Return to Dos
mov ax,4c00h
int 21h
main endp
;-------------------------------------------------------------------------
;function: 在指定范围画出正弦波(从零开始画)
;input:direction=0 正向
; =1 负向
;-------------------------------------------------------------------------
DrawSin proc near
mov angle,0
next: mov ax,angle
sub ax,90 ;90-ax
neg ax
call search
mov ax,bx ;bx*num_a/100
mov cx,num_a
imul cx ;(dx,ax)
mov cx,100
idiv cx
mov bx,ax
cmp bx,-240
jl modify
cmp bx,240
jg modify
sub bx,240 ;240-bx
neg bx
mov ax,angle ;ax+320
mov cx,num_t ;ax*num_t/100
imul cx
mov cx,100
idiv cx
cmp ax,-320
jl DrawSin_exit
cmp ax,320
jge DrawSin_exit
add ax,320
writedot
modify: cmp direction,0
jne reverse
inc angle
jmp next
reverse:dec angle
jmp next
DrawSin_exit:
ret
DrawSin endp
;-------------------------------------------------------------------------
;search子程:
;input:ax存放度数
;output:bx:函数值*100
;require:以table为首的余弦函数表(仅有2位小数)
;-------------------------------------------------------------------------
search proc near
push ax
push cx
push dx
mov cl,0 ;初始化整数部分(默认为零)
mov ch,-1
cmp ax,0
jg greater
neg ax
greater:
cmp ax,360 ;0<=ax<=360则转移
jle between_0_and_360
cwd ;将ax转化到[0,360]之间
mov bx,360
idiv bx ;(dx,ax)/bx
mov ax,dx ;ax中为转化好的度数
between_0_and_360:
sub ax,180
cmp ax,0
jg search_plus
neg ax ;负数时求补
search_plus:
cmp ax,90
jle find ;[0,90)之间,直接去查找
sub ax,180 ;[90,180]之间时,函数值为正
neg ax
mov ch,1
find: mov bx,ax ;确定小数部分
mov dl,table[bx]
mov dh,0
mov bx,dx
cmp ch,-1
jne search_exit
neg bx
search_exit:
pop dx
pop cx
pop ax
ret
search endp
;-------------------------------------------------------------------------
;画笛卡尔坐标系
;-------------------------------------------------------------------------
xy proc near
;Save the current video mode
mov ah,0fh ;get video mode
int 10h
mov savemode,al
;Switch to a graphics mode
mov ah,0 ;set video mode
mov al,mode_11
int 10h
;Draw the X-axis
mov cx,x_axisx ;X-coord of start of line
mov dx,x_axisy ;Y-coord of start of line
mov ax,x_axislen ;length of line
mov bl,white ;line color
call DrawHorizLine
;Draw the Y-axis
mov cx,y_axisx ;X-coord of start of line
mov dx,y_axisy ;Y-coord of start of line
mov ax,y_axislen ;length of line
mov bl,white ;line color
call DrawVerticalLine
ret
xy endp
;--------------------------------------------------------------
DrawhorizLine proc
;
;Draw a horizontal line starting at position X,Y with
;Receives: CX=X-coordinate, DX=Y-coordinate
; AX=length,and BL=color
;REturns:nothing
;---------------------------------------------------------------
push cx
mov currX,cx ;save X-coordinate
mov cx,ax ;loop counter
dhl1: push cx ;save loop counter
mov al,bl ;color
mov ah,0ch ;draw pixel
mov bh,0 ;video page
mov cx,currX ;retrieve X-coordinate
int 10h
inc currx ;move 1 pixel to the right
pop cx ;restroe loop counter
loop dhl1
pop cx
ret
DrawHorizLine endp
;--------------------------------------------------------------
DrawVerticalLine proc
;
;Draw a vertical line starting at position X,Y with
;a given length and color
;Receives: CX=X-coordinate,DX=Y-coordinate,
; AX=length,BL=color
;Returns:nothing
;---------------------------------------------------------------
push cx
mov currY,dx ;save Y-coordinate
mov currX,cx ;save X-coordinate
mov cx,ax ;loop counter
dvl1: push cx ;save loop counter
mov al,bl ;color
mov ah,0ch ;function:draw pixel
mov bh,0 ;set video page
mov cx,currX ;set X-coordinate
mov dx,currY ;set Y-coordinate
int 10h ;draw the pixel
inc currY ;move down 1 pixel
pop cx ;restore loop counter
loop dvl1
pop cx
ret
DrawVerticalLine endp
;---------------------------------------------------------------
;将ax中的数转换为10进制数输出。
;---------------------------------------------------------------
binidec proc near
push cx
push dx
push ax
push bx
pushf
;MAIN PART OF THE PROGRAM GOES HERE:
mov ch,0 ;CH为0则AX为正数,CH为1则Ax为负数
cmp ax,0
jge normal
neg ax
mov ch,1
normal: mov cl,0 ;计数器置零
mov bx,10
binidec_next:
mov dx,0
div bx
push dx
inc cl
cmp ax,0
jne binidec_next
cmp ch,1
jne print
mov ah,2
mov dl,'-'
int 21h
print: pop ax
mov dl,al
add dl,30h
mov ah,2
int 21h
dec cl
jne print
popf
pop bx
pop ax
pop dx
pop cx
ret
binidec endp
;--------------------------------------------------------------
;function:输入周期值和峰值
;input:none
;output:将周期值和峰值分别放入num_t和num_a中
;--------------------------------------------------------------
input proc near
mov ah,9
mov dx,offset mess_t
int 21h
mov ah,0ah ;输入t
mov dx,offset t
int 21h
mov ah,2 ;输出回车换行
mov dl,0dh
int 21h
mov dl,0ah
int 21h
mov bl,t+1 ;在表达式末尾加';'
mov bh,0
mov t[bx+2],';'
mov si,offset t+2
call decibin
mov cx,100 ;ax*100/360
mul cx
mov cx,360
div cx
mov num_t,ax
mov ah,9
mov dx,offset mess_a
int 21h
mov ah,0ah ;输入a
mov dx,offset a
int 21h
mov ah,2 ;输出回车换行
mov dl,0dh
int 21h
mov dl,0ah
int 21h
mov bl,a+1 ;在表达式末尾加';'
mov bh,0
mov a[bx+2],';'
mov si,offset a+2
call decibin
mov cx,100 ;ax=整数部分*100
mul cx
jo input_error
mov cx,ax
cmp byte ptr [si+1],'.'
jne input_mov
add si,2
call decibin ;转化小数部分
cmp ax,10
ja input_add
mov bx,10 ;若小数部分只有一位则乘以10
mul bx
input_add:
add ax,cx ;小数部分+整数部分
input_mov:
mov num_a,ax
ret
input_error:
jmp decibin_error1
input endp
;-----------------------------------------------------------
;function:将十进制数转换为二进制数
;input:Si指向表达式
;output:转换后的数放在AX中
;instruction:遇到非数字字符就认为该串数字结束
; 如数字过大导致溢出,则输出提示信息后程序结束
; 出错信息名为mess1,请在数据段中定义
;-----------------------------------------------------------
decibin proc near
push bx
push cx
push dx
mov bx,0
newchar:mov al,byte ptr [si]
sub al,30h
jl exit
cmp al,9d
jg exit
cbw
;digit is now in AX
;Multiply number in BX by 10 decimal
xchg ax,bx
mov cx,10d
imul cx
jno c1
jmp decibin_error1
c1: xchg ax,bx
;Add digit in AX to number in BX
add bx,ax
jno c2
jmp decibin_error1
c2: inc si
jmp newchar
exit: mov ax,bx ;将得数存入AX
dec si ;保证SI指向的是数字的最后一个
pop dx
pop cx
pop bx
ret
decibin_error1: ;出错处理
mov ah,9
mov dx,offset mess1
int 21h
mov ax,4c00h
int 21h
decibin endp
code ends
end main
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -