一. 实验目的
- 了解8255芯片结构及编程方法。
- 了解8255输入/输出实验方法。
- 掌握8255控制键盘及显示电路的基本功能及编程方法。
- 掌握一般键盘和显示电路的工作原理。
二. 实验内容
实验5-1 8255并行输入/输出实验
将实验的线路连接好后,编程,将8255的C口作为输入。输入信号由8个逻辑电平开关提供,A口作为输出,其内容由发光二极管来显示。编程从8255C口输入数据,再从A口输出。
电路图:
接线:
汇编代码:
P8255A EQU 288H
P8255B EQU 0602H
P8255C EQU 28AH
P8255MODE EQU 28BH
code segment
assume cs:code
start:
mov dx,P8255MODE
mov al,10001001b
out dx,al
next:
mov dx,P8255C
in al,dx
mov dx,P8255A
out dx,al
mov dl,0ffh
mov ah,06h
int 21h
jz next
mov ax, 4ch
int 21h
code ends
end start
运行结果:
运行程序,拨动开关,相应的二极管被点亮。效果如下图所示:
实验5-2 并行接口键盘反转扫描实验
编程,设置8255C口键盘输入、A口为数码管段码输出。使得在4×4小键盘上每按一个键,8位数码管上显示出相应字符。
电路图:
接线:
汇编代码:
a8255 equ 288H ;8255 A口
c8255 equ 28aH ;8255 C口
k8255 equ 28bH ;8255 控制口
;========================数据定义段data开始=======================;
data segment
table1 dw 0770h,0B70h,0D70h,0E70h,07B0h,0BB0h,0DB0h,0EB0h ;键盘行列码表,对应着si寄存器,用于确定按下按键的位置及按键信息
dw 07D0h,0BD0h,0DD0h,0ED0h,07E0h,0BE0h,0DE0h,0EE0h
LED DB 3FH,06H,5BH,4FH,66H,6DH,7DH,07H,7FH,6FH,77H,7CH ;LED段码表,分别代表0~F
DB 39h,5EH,79h,71h,0ffh
char db '0123456789ABCDEF' ;字符表,对应着di寄存器,用于最后在屏幕上输出内容
mes db 0ah,0dh,'PLAY ANY KEY IN THE SMALL KEYBOARD! ',0ah,0dh ;提示信息,用于开始时在屏幕上提示输入
db 'IT WILL BE ON THE SCREEN! END WITH E ',0ah,0dh,'$'
key_in db 0h
data ends
;========================数据定义段data结束=======================;
;=======================堆栈定义段stacks开始======================;
stacks segment stack
db 100 dup (?)
stacks ends
;=======================堆栈定义段stacks结束======================;
code segment
assume cs:code,ds:data,ss:stacks,es:data
start:
cli ;禁止中断发生
mov ax,data ;将data放入通用寄存器ax中,data是伪指令,起到过渡作用
mov ds,ax ;将ax中的data转到ds数据段寄存器中,让数据段指向正确的位置,但内存数不能放入段地址
mov es,ax ;将ax中的data放入通用寄存器es中
mov ax,stacks ;将stack堆栈放入通用寄存器ax中,起到过渡作用
mov ss,ax ;将ax中的stack转到数据段寄存器ss中
mov dx,offset mes ;显示提示信息mes
mov ah,09 ;将功能号09H送入ah
int 21h ;返回DOS,输出需要显示的信息
mov dx,k8255 ;设置8255 (工作方式0;A口输出;C口高四位输出,低四位输入),初始化控制字,将控制字k8255送入端口dx
mov al,81h ;将控制字10000001(81h)送入al中,特征位D7默认置1,A组方式0,D6D5=00,端口A输出,D4=0,PC7~PC4输出,D3=0,B组方式0,D2=0,B端口输出,D1=0,PC3~PC0输入,D0=1
out dx,al ;将al中的控制字送入端口dx中
main_key:
call key ;获取一个输入的字符并显示
call display ;调用显示子程序,显示得到的字符
cmp byte ptr key_in,'E' ;将输入的字符key_in与'E'进行比较,计算key_in-'E'的值,判断是否执行退出操作,按'E'退出程序
jnz main_key ;如果key_in-'E'的值不为0,则跳转至main_key,继续循环
mov ax,4c00h ;如果key_in-'E'的值等于0,则退出
int 21h ;返回DOS,退出
;==========================子程序key开始=========================;
key proc near ;开始定义子程序key的伪指令,NEAR属性为段内近调用,调用程序和子程序在同一代码段中,只能被相同代码段的其他程序调用
key_loop: ;开始定义key_loop循环,等待键盘按键按下
mov ah,1 ;调用DOS的1号功能,没有入口参数,只有出口al
int 16h ;读取键盘缓冲区输入
jnz exit ;若pc键盘有键按下则退出
mov dx,c8255 ;设置端口C,准备读取行3~行0
in al,dx ;进行读行扫描值
and al,0fh ;将al寄存器中的高四位内容清零
cmp al,0fh ;将al中高四位清零后的内容与0fh进行比较,判断是否有键被按下
jz key_loop ;如若未发现有键按下则继续转至key_loop进行循环
call delay ;调用延迟子程序delay
mov ah,al ;设置8255 (工作方式0;A口输出;C口高四位输入,低四位输出),将al内容送入ah暂存
mov dx,k8255 ;初始化控制字,将控制字k8255送入端口dx
mov al,88h ;将控制字10001000(88h)送入al中,特征位D7默认置1,A组方式0,D6D5=00,端口A输出,D4=0,PC7~PC4输出,D3=1,B组方式0,D2=0,B端口输出,D1=0,PC3~PC0输入,D0=0
out dx,al ;将al中的控制字送入端口dx中
mov al,ah ;将ah中的暂存值还给al
mov dx,c8255 ;设置端口C,准备读取列3~列0
in al,dx ;读列扫描值
and al,0f0h ;将al低四位清零
cmp al,0f0h ;将al中低四位清零后的内容与0f0h进行比较,判断是否有键被按下
jz key_loop ;如若未发现有键按下则继续转至key_loop进行循环
mov si,offset table1 ;si为键盘扫描码表table1的首地址
mov di,offset char ;di为字符表char的首地址
mov cx,16 ;cx为待查表的表大小为16,0~F
key_tonext: ;开始定义key_tonext操作,用于查找扫描码,确定按下按键的位置
cmp ax,[si] ;逐个比较键盘扫描码表table1的首地址的值,计算行列差值,进而确定按下的键在键盘上的位置
jz key_findkey ;如果计算结果等于0,则跳转到key_findkey操作
dec cx ;把cx中的值减一
jz key_loop ;未找到对应扫描码,则跳转到key_loop循环中,等待再次按下按键
add si,2 ;源变址寄存器si加2
inc di ;字符表首地址di自增1,di指向字符表char中的下一个字符内容
jmp key_tonext ;跳转至key_tonext操作
key_findkey: ;开始定义key_findkey操作,用于查找键盘码,并在屏幕上显示
mov dl,[di] ;将di中的字符内容送入dl中
mov ah,02 ;调用DOS的2号功能,将功能号02H送入ah
int 21h ;显示查找到的键盘码,进行单字符输出,入口是dl,在屏幕上输出di中的键盘码字符内容
mov byte ptr key_in,dl ;将dl中的键盘码送入key_in中
key_waitup: ;开始定义key_waitup操作,用于进行按键抬起的操作,用于防止抖动
mov dx,k8255 ;初始化控制字,将控制字k8255送入端口dx
mov al,81h ;将控制字10000001(81h)送入al中,特征位D7默认置1,A组方式0,D6D5=00,端口A输出,D4=0,PC7~PC4输出,D3=0,B组方式0,D2=0,B端口输出,D1=0,PC3~PC0输入,D0=1
out dx,al ;将al中的控制字送入端口dx中
mov dx,c8255 ;设置端口C
mov al,0fh ;将00001111(0fh)送入al中,端口C特殊控制方式:特征位D7置0,D6D5D4不使用,位选择为端口C的7位,D3D2D1均为1,置位D0=1
out dx,al ;将al中的控制字送入端口dx中
in al,dx ;进行读行扫描值
and al,0fh ;将al寄存器中的高四位内容清零
cmp al,0fh ;将al中高四位清零后的内容与控制字0fh进行比较,判断是否有键被按下
jnz key_waitup ;若按键未抬起,则继续跳转至key_waitup循环
call delay ;调用延时子程序
ret ;用栈中的数据,修改IP的内容,从而实现近转移
exit: ;子程序key退出
mov byte ptr key_in,'E' ;将'E'字符送入key_in中
ret ;用栈中的数据,修改IP的内容,从而实现近转移
key endp ;结束子程序key伪指令
;==========================子程序key结束=========================;
;=========================子程序delay开始========================;
delay proc near ;开始定义子程序delay的伪指令,NEAR属性为段内近调用,调用程序和子程序在同一代码段中,只能被相同代码段的其他程序调用
push ax ;延迟50ms~100ms
mov ah,0 ;调用DOS0号指令
int 1ah ;返回DOS
mov bx,dx ;将dx中内容送入bx
delay1: ;定义delay1操作
mov ah,0 ;调用DOS0号指令
int 1ah ;返回DOS
cmp bx,dx ;比较bx和dx中值的值是否相等,计算bx-dx的值是否为0
jz delay1 ;若bx-dx的值为0,则继续跳转至delay1
mov bx,dx ;将dx中内容送入bx
delay2: ;定义delay2操作
mov ah,0 ;调用DOS0号指令
int 1ah ;返回DOS
cmp bx,dx ;比较bx和dx中值的值是否相等,计算bx-dx的值是否为0
jz delay2 ;若bx-dx的值为0,则继续跳转至delay2
pop ax ;从栈顶取出数据送入ax
ret ;用栈中的数据,修改IP的内容,从而实现近转移
delay endp ;结束子程序delay伪指令
;=========================子程序delay结束========================;
;========================子程序display开始=======================;
display proc near ;开始定义子程序diaplay的伪指令,NEAR属性为段内近调用,调用程序和子程序在同一代码段中,只能被相同代码段的其他程序调用
push ax ;将寄存器ax中的数据送入栈中
mov bx,offset led ;bx为LED灯段码表led的首地址
mov al,byte ptr key_in ;将key_in中的内容送入al中
sub al,30h ;字符'0-9'所对应的ASCII码值为'30H-39H',故欲得到0~9的数值,只需用其ASCII码值减30H
cmp al,09h ;将al中的值与9进行比较,若等于9时则进行换码跳转dis2
jng dis2 ;跳转至dis2操作进行换码
sub al,07h ;字符'a-f'所对应的ASCII码值为'97H-102H',故欲得到a~f的数值,只需用其ASCII码值减07H
dis2:
xlat ;换码指令,用于改变al中的数据
mov dx,a8255 ;设置端口A,准备输出段码内容显示
out dx,al ;输出显示数据,段码
pop ax ;从栈顶取出数据送入ax
ret ;用栈中的数据,修改IP的内容,从而实现近转移
display endp ;结束子程序display伪指令
;========================子程序display结束=======================;
code ends
end start
运行结果:
运行程序,按下薄膜键盘上的按键,数码管显示按键的值。效果如下图所示: