资源描述
实践课程 计算机综合实践9002
校外学习中心 重庆黔江奥鹏学习中心[20]VIP
实验内容:
一、熟悉、使用DEBUG调试工具
[摘要] 借助DEBUG调试工具来发现汇编语言程序的错误所在并加以改正。通过实验,掌握DEBUG的常用基本命令,学会如何在windows的命令模式下启动DEBUG,进而学会如何使用DEBUG查看CPU和内存,以及进行程序的跟踪调试等。
1 实验目的
1.1学习如何在Windows的命令模式下启动DEBUG。
1.2掌握DEBUG的常用基本命令。
1.3学习如何使用DEBUG查看CPU和内存以及进行跟踪调试。
2 实验设备及软件环境
装有DOS系统及MASM6.X的微机一台。
3 预备知识
3.1 什么是DEBUG?
Debug是DOS、Windows都提供的实模式(8086方式)程序的调试工具。使用它,可以查看CPU各种寄存器的内容、内存的情况和在机器码级跟踪程序的运行。
3.2 常用的Debug命令及其含义
表1.1 Debug命令及其含义
命令格式 功能说明
R [寄存器名] 查看、改变CPU寄存器的内容
D [范围] 查看指定范围内的内存中的内容
E 起始地址 字节值表 用值表中的值替换从“起始地址”开始的内存单元中的内容
U [范围] 反汇编,将内存中的机器指令翻译成汇编指令
T [=地址][指令数] 执行一条机器指令
A [地址] 以汇编指令的格式在内存中写入一条机器指令
Q 退出Debug,回到DOS状态
4 启动DEBUG
4.1打开Windows命令窗口
选择“开始”→“运行”→输入“cmd”命令
4.2启动DEBUG
在命令窗口中启动DEBUG,将显示连接符“-”,这时可输入各种DEBUG命令。
4.3关于使用命令的几点说明:
l 在提示符“-”下才能输入命令,在按“回车”键后,该命令才开始执行;
l 命令是单个字母,命令和参数的大小写可混合输入;
l 可用F1、F2、F3、Ins、Del、→等编辑键来编辑本行命令;
l 当命令出现语法错误时,将在出错位置显示“^Error”;
l 在DEBUG中使用的数都是以十六进制来表示的。
5 实验内容
5.1 R命令
作用:查看、改变CPU寄存器的内容
(1)显示所有寄存器之中的内容:输入R
我们重点关注AX、BX、CX、DX、CS及IP寄存器的内容,其他寄存器SP、BP、SI、DI、ES、SS及标志寄存器先不予理会。此外,并列出了CS:IP所指向的内存单元处所存放的机器码,并将它翻译为汇编指令。
(2)改变寄存器中的内容:输入R AX
在提示符“:”后输入1111,即可将AX的值设置为1111。在输入R命令,查看修改后的寄存器值。
5.2 D命令
作用:查看指定范围内的内存中的内容
(1)直接输入D命令
DEBUG将输出3部分内容,查看执行结果。
说明:
l 左边是每行的起始地址,用“XXXX:YYYY”表示,其中XXXX表示内存单元的段地址,YYYY表示内存单元的偏移量;
l 中间以十六进制的形式显示从指定地址开始的128个内存单元的内容,每行显示16个字节的内容;
l 右边显示每个内存单元中的数据对应的可显示的ASCII码字符,若没有对应可显示的ASCII码字符,DEBUG用“.”来代替。
(2)执行带参数的D命令
若执行带参数的命令D,DEBUG将显示指定地址范围的内容。带参数的方式有三种。
l 方式一:D 起始位置
n DEBUG从起始位置开始显示128个字节的内容。
n 输入命令:D 1AF5:100
l 方式二:D 起始位置 结束位置
n DEBUG从起始位置开始一直显示到结束位置。
n 输入命令:D DS:100 11F
l 方式三:D 起始位置 L长度
n DEBUG命令从起始位置开始显示指定长度内容。
n 输入命令:D DS:100 L10
使用带参数的D命令后,接着使用D命令,可列出后续的128个内存单元的内容。
5.3 E命令
格式:E 起始地址 字节值表
或 E 起始地址
作用:用值表中的值替换从“起始地址”开始的内存单元中的内容
例1:将内存1000:0~1000:9单元中的内容分别写为0、1、2、3、4、5、6、7、8、9,可用“E 起始地址 数据 数据 数据 数据 数据……”的格式来进行。
步骤:
① 用D命令查看1000:0~1000:f单元的内容:D 1000:0 f
② 用E命令修改从1000:0开始的10个单元中的内容:E 1000:0 0 1 2 3 4 5 6 7 8 9
③ 用D命令查看1000:0~1000:f单元中内容的变化:D 1000:0 f
例2:用E命令向内存中写入字符。从内存1000:0开始写入:数值1,字符“a”,数值2,字符“b”,数值3,字符“c”。
步骤:
① 用D命令查看1000:0处的内容:D 1000:0
② 用E命令输入:E 1000:0 1 ‘a’ 2 ‘b’ 3 ‘c’
③ 用D命令查看1000:0~1000:f单元中内容的变化:D 1000:0 f
例3:用E命令向内存中写入字符串。从内存1000:0开始写入:数值1,字符串“a+b”,数值2,字符串“c++”,数值3,字符“IBM”。
步骤:
① 用D命令查看1000:0处的内容:D 1000:0
② 用E命令输入:E 1000:0 1 ‘a+b’ 2 ‘c++’ 3 ‘IBM’
③ 用D命令查看1000:0~1000:f单元中内容的变化:D 1000:0
例4 用E命令以提问的方式来逐个地修改从某一地址开始的内存单元中的内容。
以从1000:10单元开始为例。
步骤:
① 用D命令查看1000:10处的内容:D 1000:10
② 用E命令输入:E 1000:10,按Enter键
③ DEBUG将显示起始地址1000:0010以及第一个单元(即1000:0010单元)的原始内容:00.,然后光标停在“.”的后面,提示输入想要写入的数据,此时有两种选择:其一输入数据,完后按空格键,即用输入的数据改写当前的内存单元;其二不输入数据,直接按空格键,则表示不对当前内存单元进行改写
④ 当前单元处理完成后(不论是改写或者没有改写,只要按了空格键,就表示处理完成),DEBUG将显示下一个内存单元的原始内容,并提示进行修改,可以用同样的方法进行处理
⑤ 所有希望改写的内存单元改写完毕后,按ENTER键,E命令结束
⑥ 用D命令查看1000:10单元中内容的变化:D 1000:10
6实验任务
C:\>debug
-F 100 17F 00
-A 100
0B3E:0100 MOV DL,01
0B3E:0102 MOV AH,02
0B3E:0104 INT 21
0B3E:0106 INT 20
0B3E:0108
-N C:\1ST.COM
-R BX
BX 0000
:
-R CX
CX 0000
:8
-W 100
Writing 00008 bytes
-Q
C:\>
在dos下执行程序
C:\>dir 1st*.*
Volume in drive C is NTFSCCCC
Volume Serial Number is FC03-2958
Directory of C:\
2010-8-18 18:51 8 1ST.COM
1 File(s) 8 bytes
0 Dir(s) 1,080,619,008 bytes free
C:\>1st
☺
C:\>
方法一:
C:\>DEBUG 1ST.COM
-G=100
☺
Program terminated normally
方法二:
C:\>DEBUG
-N C:\1ST.COM
-L 100
-G=100
☺
Program terminated normally
借助DEBUG调试工具来发现汇编语言程序的错误所在并加以改正。
7体会
这次实验,因为要自己去设计整个过程,所以就去了解学习自己原来并没有真正弄懂的东西。比如一些程序的代码的意思,汇编语言的逻辑。使我对前面所做的实验有了原理性的了解,回头看一些实验,也知其然其所以然了。同时对课本上讲的一些内容,不再像以前那样觉得抽象,通过这次设计,有了具体的理解。
二、设计汇编语言程序
1实验目的
进行程序设计实验,掌握汇编语言程序。实验包括对字符串统计程序进行设计;设计双字乘法程序设计;设计字符串统计程序设计双字乘法程序设计。掌握宏汇编中的标号的使用
学会使用msam编写简单的程序
2预备知识
汇编语言程序设计是一门实践性很强的课程。编写程序、上机调试、运行程序是进一步学习和掌握汇编语言程序设计的必要手段。在编译汇编程序后,需要进行调试,DEBUG.EXE是DOS提供的用于调试可执行程序的工具软件,是汇编语程序设计中常用的调试工具。在DEBUG环境下,不但可以调试经汇编、连接生成的可执行程序,也可以编写简单的程序。调试汇编语言程序,能使用户接触到计算机内部,允许用户直接观察和修改CPU的寄存器;能观察、修改内存单元;允许直接输入机器指令并单步执行;能反汇编程序。可以说,debug是观察和了解计算机内部运行情况的有利助手。
3汇编语言源程序上机操作过程
3.1源程序上机过程流程图
开始
建立源文件
Y
有人工检查吗?
修改源程序
N
ASM文件存盘
调MASM程序
汇编源文件
Y
有语法错误?
N
调LINK程序,连接目标文件?
连接有错?
EXE文件存盘
用DELBUG查错
执行EXE文件
Y
结果有错?
N
结束
3.2 实验步骤
1)编写一段代码(m.asm)功能是:显示字符串
data segment mov ax,num
num dw 8072h or ax,ax
data ends jns done
code segment neg ax
assume cs:code,ds:data mov num,a x
start proc far done: r t e
push ds start endp
xor ax,ax code end s
push ax end start
mov ax,data
mov ds,ax
2) 在DOS提示符下键入:对名为m.asmd的文件进行编译,连接生产.obj和.exe文件:-cd..
-cd..
-cd\masm
-msam
-m
-link t
-debug m.exe得到可执行文件后就可以直接调用可执行文件名,从盘上调到内存中运行。
程序及运行结果(或实验数据记录及分析)
3)编写一段代码(m.asm)功能是:显示字符串
data segment lp3:cmp ax,64h mov dl,[bx+si]
s db 4 dup(?) mov ds,ax add dl,30h
x db ? jb lp4 int 21h
data ends inc dl inc si
code segment sub ax,64h loop lp7
assume cs:code,ds:data jmp lp3 mov ah,1
start:mov ax,data lp4:mov s+1,dl int 21h
mov ds,ax mov dl,0 mov ah,4ch
mov bx,1 lp5: cmp ax,0ah int 21h
mov ax,0 jb lp6 code ends
mov cx,100 inc dl end start
lop:add ax,bx sub ax,0ah
inc bx jmp lp5
loop lop lp6:mov s+2,dl
mov dl,0 mov s+3,al
lp1:cmp ax,3e8h mov bx,offset s
jb lp2 mov si,0
inc dl mov ah,2
sub ax,3e8h mov cl,4
jmp lp1 lp7:mov di,[bx+si]
lp2:mov s,dl or di,30h
mov dl,0
4) 在DOS提示符下键入:对名为m.asmd的文件进行编译,连接生产.obj和.exe文件:-cd..
-cd.. -msam -link t
-cd\masm –m -debug m.exe
程序及运行结果(或实验数据记录及分析)
4体会
编写好一个程序后,要想在计算机中调试、运行,必须要有一个程序来支持程序的编辑、修改等操作。这种支援程序叫编辑程序。编辑程序有很多种,但按功能划分,主要有两大类。一类是行编辑程序,如EDIT编辑程序;另一类是全屏幕编辑程序如Quick Edit(QE)。行编辑程序功能较弱,不如全屏幕编辑程序方便、灵活。在编辑汇编语言的源程序时,可以使用已熟悉的。
三、8253定时器/计数器接口与数字电子琴
[摘要] 选择利用实验仪扬声器/PC机内8253驱动内扬声器改变定时器2的计数值来改变声音频率,通过编程来获得声调(频率)和节奏(延时长短),利用键盘1、2、3、4、5、6、7、8设计一个电子琴,通过按数字键响相应的乐符1、2、3、4、5、6、7、i,使能演奏简单的乐曲。使计算机演奏出乐曲来。
1实验目的
检验和提高我在原理与接口综合应用方面分析问题与解决问题的能力,同时也给我提供更多、更好的训练机会。根据设计要求,尽可能完成设计要求的功能,选择最合适的器件,构成最有效的硬件电路来完成。
2实验要求
选择利用实验仪扬声器/PC机内8253驱动内扬声器与键盘1、2、3、4、5、6、7、8设计一个电子琴,通过按数字键响相应的乐符1、2、3、4、5、6、7、i,使能演奏简单的乐曲。
3程序流程和程序实现
3.1流程图
开始
键盘读入一个字符
是ESC键吗?
N
N 返回DOS
是数字1~8键吗?
Y
读出音阶值保存
赋相应频率
延时
3.2程序
seg segment
freq dw 262,294,330,349,392,440,494,523
;扬声器发声各频率值
msg db 'Press 1,2,3,4,5,6,7,8,ESC:',0dh,0ah,'$'
tim dw 400
num db ?
dseg ends
sseg segment stack
dw 256 dup(?)
sseg ends
cseg segment
assume cs:cseg,ds:dseg
start: mov ax,dseg
mov ds,ax
mov dx,offset msg
mov ah,9
int 21h ;显示提示信息
sss: mov ah,7
int 21h
;等待从键盘接收字符,不回显al=asc码
cmp al,1bh
je exit;若为ESC键,则转EXIT退出
cmp al,31h
jl sss ;小于31h
cmp al,38h ;大于38h
jg sss ;不在'1'-'8'之间转sss
sub al,31h
mov num,al ;num求出相应的时间常数的序号
jinei: mov al,num
add al,al
mov ah,00h
mov si,ax
again: mov di,freq[si]
mov bx,tim
call gen
jmp sss
exit: mov ah,4ch
int 21h
gen proc near
mov al,0b6h ;设置8253通道2方式3二进制计数
out 43h,al
mov dx,12h
mov ax,12928
; DX AX=896*533h=18*65536+12928=1.19M
div di
out 42h,al ;8253通道2口设置初值
mov al,ah
out 42h,al
in al,61h ;读8255PB口
mov ah,al
or al,3
out 61h,al
wait1: mov cx,0h
delay3: mov ax,10 ;延时子程序
delay2: nop
dec ax
jnz delay2
loop delay3
dec bx
jnz wait1
mov al,ah
out 61h,al
ret
gen endp
cseg ends
end start
3.3试验仪电子琴流程图
3.4实验电路:
3.5程序
data segment
ioport equ 0d400h-0280h
io8253a equ ioport+280h
io8253b equ ioport+283h
io8255a equ ioport+288h
io8255b equ ioport+28bh
io0832a equ ioport+290h
data1 db 80h,96h,0aeh,0c5h,0d8h,0e9h,0f5h,0fdh
db 0ffh,0fdh,0f5h,0e9h,0d8h,0c5h,0aeh,96h
db 80h,66h,4eh,38h,25h,15h,09h,04h
db 00h,04h,09h,15h,25h,38h,4eh,66h ;正弦波数据
time db 120,106,94,89,79,70,63,59 ;发不同音时8253的计数器初值
msg db 'Press 1,2,3,4,5,6,7,8,ESC:',0dh,0ah,'$'
num db ? ;num为8253计数器初值的序号
data ends
code segment
assume cs:code,ds:data
start: mov ax,data
mov ds,ax
mov dx,offset msg
mov ah,9
int 21h ;显示提示信息
sss: mov ah,7
int 21h ;从键盘接收字符,不回显
cmp al,1bh
je exit ;若为ESC键,则转EXIT
cmp al,31h
jl sss
cmp al,38h
jg sss ;若不在'1'-'8'之间转sss
sub al,31h
mov num,al ;求出相应的时间常数的序号
mov cx,60 ;取60次32个正弦波数据
ddd: mov si,0
lll: mov al,data1[si] ;取正弦波数据
mov dx,io0832a
out dx,al ;放音
call delay ;调延时子程序
inc si
cmp si,32 ;是否取完32个数据
jl lll ;若没有,则继续
loop ddd ;总循环次数60是否完,没有,则继续
jmp sss
exit: mov ah,4ch
int 21h
delay proc near ;延时子程序
ccc: mov bx,offset time
mov dx,io8253b ;置8253通道0为方式0工作
mov al,10h
out dx,al
mov dx,io8255b ;设8255A口输入
mov al,9bh
out dx,al
mov al,num ;取相应的时间常数
xlat
mov dx,io8253a
out dx,al ;向8253通道0输出
kkk: mov dx,io8255a
in al,dx ;从8255A口读一字节
test al,01 ;判PA0口是否为1
jz kkk ;若不为1,则转KKK
ret ;子程序返回
delay endp
code ends
end start
4测试方案和测试结果
测试方案
测试结果
启动程序,出现按键提示,按下1~8键
机内/实验仪发出相应的音阶
改变开关状态(可随时任意改变),按1~8键
对应发出相应的音阶
“弹琴”
发出优美旋律
按下ESC键
退出程序
5体会
通过这次微机实验课程设计,使我对微机软硬件结合有了进一步的了解。原来并不太清楚是什么意思,一直都很模糊,听课本也是很迷茫;而之前的那些单元实验,也没有都做好。之前做的实验,由于大部分是验证性的,所以就很被动地去做,甚至并没有想为什么要那样连电路,内部的代码更没有认真看。这次课程设计,要自己去设计整个过程,了解学习自己原来并没有真正弄懂的东西。比如一些程序的代码的意思,汇编语言的逻辑,比如一些芯片的用途。使我对前面所做的实验有了原理性的了解,回头看一些实验,也知其然其所以然了。同时对课本上讲的一些内容,不再像以前那样觉得抽象,通过这次设计,有了具体的理解。
同时,我也知道了设计一个项目,应该如何下手。应该先对项目要求有个全面的了解,知道要做什么,然后根据要求所要涉及到的知识我们要主动去摄取,结合自己已学过的,再对整体框架有个感知,心里有数后,进行设计。设计时用流程图,这很重要,这样整个思路就很清晰,而且是按照软硬件语言的逻辑顺序进行,就很方便。设计过程可以分模块,不要一开始就想把所有的功能都实现了,应该一个模块一个模块地实现,再总的连起来,实现最后的总模块。在每个模块设计时,尽量想到比较简单的设计,简化编程和电路,也可少出错。对微机是这样,对其他的像数字系统设计,也是一样的。
因此,我也觉得微机实验的这种形式的课程设计是很好也很有必要的,对我们对微机实验的理解有很大帮助。
四、实时时钟实验
1实验目的
1.1了解RTC实时时钟特性、功能、结构
1.2了解RTC实时时钟寄存器描述
1.3了解RTC中断
2实验过程
2.1利用RTC的增量功能进行1s的定时,当定时时间到,取反LED控制
#include "config.h"
#define LED1CON 0x00000400 /*P0.10口为LED1控制器*/
/*定义Fpclk值,用于设置串口波特率*/
#define FPCLK 3686250L
2.2初始化实时时钟
void RTCIni(void)
{ PREINT=FPCLK/32768-1; //设置预分频器
PREFRAC=FPCLK-(FPCLK/32768)*32768;
YEAR=2005; //初始化年
MONTH=6; //初始化月
DOM=10; //初始化日
CIIR=0x01; //设置秒值的增量产生一次中断
CCR=0x01; //启动RTC
}
2.3使用RTC的秒增量中断功能控制LED闪动
int main(void)
{ PINSEL0=0x00000000; //引脚连接设置
PINSEL1=0x00000000;
IODIR=LED1CON;
RTCIni(); //初始化RTC
while(1)
{ IOSET=LED1CON; //熄灭LED1
while(0==(ILR&0x01)); //等待RTC增量中断标志
ILR=0x01; //清除中断标志
IOCLR=LED1CON; //点亮LED1
while(0==(ILR&0x01));
ILR=0x01;
}
return(0);
}
2.4运行rtc进行计时,并将所计时间值不断地通过串口向上位机发送
#include "config.h"
#define LED1CON 0x00000400 /*P0.10口为LED1控制端*/
/* 定义Fpclk值,用于设置串口波特率*/
#define FPCLK 2764800L
/*定义串口模式设置数据结构*/
typedef struct UartMode
{ uint8 datab; //字长度,5/6/7/8
uint8 stopb; //停止位,1/2
uint8 parity; //奇偶校验位,0为无校验,1为奇数校验,2为偶数校验
} UARTMODE;
uint8 send_buf[16]; //UART0数据接收缓冲区
2.5初始化串口0,设置其工作模式及波特率
入口参数: baud 波特率
set 模式设置(UARTMODE数据结构)
出口参数: 返回值为1时表示初始化成功,为0时表示参数出错
uint8 UART0_Ini(uint32 baud, UARTMODE set)
{ uint32 bak;
/*参数过滤*/
if ((0==baud)||(baud>115200))return(0);
if ((set.datab<5)||(set.datab>8))return(0);
if ((0==set.stopb)||(set.stopb>2))return(0);
if (set.parity>4)return(0);
/*设置串口波特率*/
U0LCR=0x80; //DLAB位置1
bak=(FPCLK>>4)/baud;
U0DLM=bak>>8;
U0DLL=bak&0xff;
/*设置串口模式*/
bak=set.datab-5; //设置字长度
if(2==set.stopb)bak|=0x04; //判断是否为2位停止位
if(0!=set.parity){set.parity=set.parity-1; bak|=0x08;}
bak|=set.parity<<4; //设置奇偶校验
U0LCR=bak;
return(1);
}
2.6向串口发送字节数据,并等待发送完毕
void SendByte(uint8 data)
{ U0THR=data; //发送数据
while((U0LSR&0x20)==0); //等待数据发送
}
2.7将缓冲区的数据发送回主机
入口参数: buf 数据缓冲区
no 发送数据的个数
出口参数: 无
void ISendBuf(uint8 const *buf,uint8 no)
{ uint8 i;
for(i=0;i<no;i++)SendByte(buf[i]);
}
2.8读取rtc的时间值,并将读出的时分秒值由串口发送到上位机显示
void SendTimeRtc(void)
{ uint8 const MESSAGE[]="RTC Time is:";
uint32 times;
uint8 bak;
times=CTIME0; //读取完整时钟寄存器0
bak=(times>>16)&0x1F; //取得时的值
send_buf[0]=bak/10+'0';
send_buf[1]=bak%10+'0';
send_buf[2]=':';
bak=(times>>8)&0x3F; //取得分的值
send_buf[3]=bak/10+'0';
send_buf[4]=bak%10+'0';
send_buf[5]=':';
bak=times&0x3F; //取得秒的值
send_buf[6]=bak/10+'0';
send_buf[7]=bak%10+'0';
send_buf[8]='\n';
ISendBuf(MESSAGE,14); //发送数据
ISendBuf(send_buf,9);
}
2.9初始化实时时钟
void RTCIni(void)
{ PREINT=FPCLK/32768-1; //设置预分频器
PREFRAC=FPCLK-(FPCLK/32768)*32768;
YEAR=2005; //初始化年
MONTH=6; //初始化月
DOM=10; //初始化日
HOUR=8;
MIN=30;
SEC=0;
CIIR=0x01; //设置秒值的增量产生一次中断
CCR=0x01; //启动RTC
}
2.10读取实时时钟的值,并从串口发送出去
int main(void)
{ UARTMODE uart0_set;
PINSEL0=0x00000005; //设置I/O连接到UART0
PINSEL1=0x00000000;
IODIR=LED1CON; //设置LED1控制口为输出,其它I/O为输入
uart0_set.datab=8; //8位数据位
uart0_set.stopb=1; //1位停止位
uart0_set.parity=0; //无奇偶校验位
UART0_Ini(9600,u
展开阅读全文