实验3 可编程并行接口8255实验
一、实验目的
1:了解8255芯片结构及编程方法。
2:了解8255输入/输出实验方法。
3:掌握8255控制键盘及显示电路的基本功能及编程方法。
4:掌握一般键盘和显示电路的工作原理。
二、实验内容
1:8255并行I/O输入/输出实验
8255是Intel公司生产的可编程外围接口电路,简称PPI。它有A、B、C三个八位端口寄存器,通过24位端口线与外部设备相连,其中C口可分为上半部和下半部。这24根端口线全部为双向三态。三个端口可分二组来使用,可分别工作于三种不同的工作方式。
(1)将实验的线路连接好后进行编程,将8255的C口作为输入,输入信号由8个逻辑电平开关提供,A口作为输出,其内容由发光二极管来显示。
(2)编程从8255C口输入数据,再从A口输出。
(3)接线,如下表所示。
待接线接口1 | 待接线接口2 |
8255的CS端 | I/O地址译码的Y1端 |
8255的JP6端(PA7——PA0),A口 | LED显示的JP2端(L7——L0) |
8255的JP8端(PC7——PC0),C口 | 逻辑开关的JP1端(K7——K0) |
(4)程序的流程图,如下图所示。
2:4*4键盘键号显示实验
(1)编程程序
设置8255C口键盘输入、A口为数码管段码输出,使得在小键盘上每按一个键,8位数码管上显示出相应字符。即,8255控制寄存器端口地址28BH、A口的地址288H、C口的地址28AH。
(2)接线,如下表所示。
待接线接口1 | 待接线接口2 |
8255的CS端 | I/O地址译码的Y1端 |
8255的JP6端(PA7——PA0) | 数码管的JP3端(DP——A) |
8255的JP8端(PC7——PC0) | 4*4键盘的JP13端(行3——列0) |
数码管的S0端 | +5V |
(3)程序的流程图,如下图所示。
三、源程序(含注释)
实验内容1:
P8255A EQU 288H ;a port P8255C EQU 28AH ;c port P8255reg EQU 28BH ;register port, CS code segment assume cs:code start: ;写方式控制字 mov bx,200 ; BX <- 200 L1: mov cx,0 ; CX <- 0 L2: loop L2 ; 若 CX == 0,跳出循环,所以相当于 NOP dec bx ; BX-- jne L1 ; if BX != 0 goto L1 ; delay mov dx,P8255reg ;move cs to dx,便于写入控制命令 mov al,10001001b ;方式0输出,A口输出且PC输入,所以是10001001 out dx,al ;output to leds next: mov dx,P8255C ;move c-port to dx in al,dx ;input to al mov dx,P8255A ;move a-port to dx out dx,al ;output al mov ah,1 ;use function-1 int 16h je next ;if zf==1, jump to next exit: mov ah,4ch ;return dos int 21h code ends end start |
实验内容2:
a8255 equ 288H ;8255 A c8255 equ 28aH ;8255 C k8255 equ 28bH ;8255 CS data segment table1 dw 0770h,0B70h,0D70h,0E70h,07B0h,0BB0h,0DB0h,0EB0h ;键盘行列码表 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' ;字符表 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 stacks segment stack db 100 dup (?) stacks ends code segment assume cs:code,ds:data,ss:stacks,es:data start: cli ;禁止中断发生 mov ax,data ;data放入ax mov ds,ax ;data进入ds mov es,ax ;data进入es mov ax,stacks ;堆栈stacks放入ax mov ss,ax ;堆栈进入ss mov dx,offset mes ;输出mes提示信息 mov ah,09 ;use function-9 int 21h ;在屏幕上显示字符串 ;need to add mov dx,k8255 ;move cs to dx,便于写入控制命令 mov al,10000001b ;方式0输出,A口输出且C口高四位输出,低四位输入 out dx,al ;控制字写入dx main_key: call key ;调用key子程序 call display ;调用display子程序 cmp byte ptr key_in,'E' ;比较是否按下“E” jnz main_key ;zf==0 jump to main-key mov ax,4c00h ;返回dos(4cH) int 21h key proc near key_loop: mov ah,1 ;use function-1 int 16h ;按下任何键,将其对应字符的ASCII码送入AL中,并在屏幕上显示该字符 jnz exit ;zf==0 jump to exit ;need to add mov dx,c8255 ;选定c口 in al,dx ;从c口输入 and al,0FH ;和0000 1111作与运算,消除高位保留低位 cmp al,0FH ;与0FH进行比较,如果没有按键按下,则相等 jz key_loop ;zf==1 jump to key_loop call delay ;调用延时 ;need to add mov ah,al ;al移动到ah,即行码存入ah mov dx,k8255 ;选定控制口 mov al,10001000b ;方式0输出,A口输出且C口高四位输入,低四位输出 out dx,al ;控制字写入dx mov dx,c8255 ;选定c口 in al,dx ;从c口输入 and al,0F0H ;和1111 0000作与运算,消除低位保留高位 cmp al,0F0H ;与F0H进行比较,如果没有按键按下,则相等 jz key_loop ;zf==1 jump to key_loop mov si,offset table1 ;si保存行列码表的首地址 mov di,offset char ;di保存字符表的首地址 mov cx,16 ;待查字符个数为16,即0-9和A-F key_tonext: cmp ax,[si] ;比较ax和行列码表 jz key_findkey ;zf==1,则跳转到key-findkey(即找到对应码了) dec cx ;cx--(没找到,则待查找个数减1) jz key_loop ;zf==1,则跳转到key-loop(如果移动出了字符表,则继续主循环) add si,2 ;si+=2(没找到,则码表移动) inc di ;di++(没找到,则字符表移动) jmp key_tonext ;无条件跳转到key-tonext,继续查找 key_findkey: mov dl,[di] ;比较dl和字符表 mov ah,02 ;use function-2 int 21h ;屏幕显示一个字符 mov byte ptr key_in,dl ;字符存入key-in,便于比较是否为E key_waitup: mov dx,k8255 ;控制字端口调用 mov al,81h ;1000 0001写入al out dx,al ;写入控制字 mov dx,c8255 ;调用c口 mov al,0fh ;0000 1111写入al out dx,al ;写入控制字 in al,dx ;读行扫描 and al,0fh ;作与运算,消除高位 cmp al,0fh ;比较低位是否有按下 jnz key_waitup ;zf==0 继续扫码 call delay ;调用延时 ret ;使用堆栈 exit: mov byte ptr key_in,'E' ;E送入key-in ret ;使用堆栈 key endp delay proc near push ax ;堆栈塞入数据 mov ah,0 ;use function-0 int 1ah ;等待输入 mov bx,dx ;dx送入bx delay1: mov ah,0 ;use function-0 int 1ah ;等待输入 cmp bx,dx ;比较dx和bx jz delay1 ;zf==1 继续等待输入 mov bx,dx ;dx送入bx delay2: mov ah,0 ;use function-0 int 1ah ;等待输入 cmp bx,dx ;比较dx和bx jz delay2 ;zf==1 继续等待输入 pop ax ;堆栈弹出数据 ret ;使用堆栈 delay endp display PROC near push ax mov bx,offset LED ;led首地址送入bx mov al,byte ptr key_in ;key-in送入al sub al,30h ;al减去30H,因为0-9的ASCII是30H-39H,因此减去之后得到数字本身 cmp al,09h ;比较是哪一个数字 jng DIS2 ;if not greater, jump to dis2(即是数字就跳转到dis2) sub al,07h ;al减去07H,因为A-F的ASCII是97H-102H,因此减去之后得到字母本身 DIS2: xlat mov dx,a8255 ;选定a口 out dx,al ;a口输出 pop ax ;弹出数据 ret display endp code ends end start |
四、遇到的问题和解决过程
问题1:在实验2中,一开始按下键盘后所输出的数是沿键盘主对角线对称的那个数。
解决1:经过线路检查发现,实验箱上的接口是A——DP,而实验指导书上的内容是DP——A,因此需要将并口接线旋转并口接线180°再插入到数码管的接口。
问题2:在实验2中,发现数码管在遇到字母按键输入时,无法正常显示。
解决2:对程序进行断点测试,发现在下面代码段中的【jng DIS2】无法成功编译。后续改成jle指令(小于等于)之后,程序可以正常运行。我们怀疑可能存在的问题是实验室电脑上的编译器无法兼容jng指令(不大于)。(后续重启程序,修改为jng后也可以正常运行,因此我们也不太确定这个问题所引发的原因。)
问题3:在实验2中,实验指导书令S0接地(GND),此时无论键盘输入什么内容,数码管都不会显示。
解决3:实验指导书编写错误(如下图所示),应该是令S0接VCC(+5V)。只有将S0赋高电平使得位选成功后,才会在右边第一个数码管显示。
问题4:在实验2中,实验指导书上的图标注键盘的行是C口的高4位,如果不仔细甄别会写错代码的方式控制字。
解决4:实验指导书编写错误(如下图所示)。经过分析后得出,键盘的行应该是C口的低4位,因此需要在对键盘的行进行输入的时候,应该对pc低位进行输入设置,并写出对应的方式控制字。同理,对键盘的列进行相应的控制字编写。
五、实验结果
实验内容1:
(1)拨码开关输入,LED灯输出
如下图所示,当设置低5位拨码开关为1、高3位拨码开关为0时,LED会进行对应的显示,即低5位处于亮起状态、高3位处于熄灭状态。
(2)完整操作过程
完整操作过程如视频附件3-1.mp4所示。在视频中,我们依次测试了拨码开关先设置为1和再设置为0的结果。
实验内容2:
(1)键盘输入非E字母
如下图所示,当按下按键【A】时,数码管显示A,且PC屏幕上显示A。
(2)键盘输入数字
如下图所示,当按下按键【2】时,数码管显示2,且PC屏幕上显示2。
(3)键盘输入E字母
如下图所示,当按下按键【E】时,数码管显示E,且PC屏幕上显示E。同时,可以看到程序检测到用户输入【E】并执行终止,并输出【done!】字符串。
(4)完整操作过程
完整操作过程如视频附件3-2.mp4所示。在视频中,我们依次测试了数字、非E字母和E字母。
六、体会与总结
1:进一步巩固了8255方式控制字的使用。在实验2中,如果需要对8255的输入/输出端口进行修改,需要进行以下两个步骤。第一,在开头对端口进行重定义,并注意A口到C口的地址是依次分布的,例如在本实验中A口是288H、B口是289H、C口是28AH。第二,对方式控制字进行修改,但是有可能修改后的控制字仍然保持不变。例如,如果在键盘的列输入时,将输出从A口变为B口,则需要把控制字从【10001001】变成【10001001】,虽然二者在码字内容上相同,但是编写的思路是不同的。编写思路如下表所示,其中橘色部分为二者思路不同的地方。
D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 | |
输出是A口 | 特征位1 | A组采用方式0,置为00 | A口输出,置为0 | PC高位输入,置为1 | B组默认为0 | B口默认为0 | PC低位输入,置为1 | |
输出是B口 | 特征位1 | A组默认为00 | A口默认为0 | PC高位输入,置为1 | B组采用方式0,置为0 | B口输出,置为0 | PC低位输入,置为1 |
2:学习了一般键盘和显示电路的工作原理。一般的矩阵键盘是通过行和列的输入判断按键是否按下的,例如在本实验中,行由低4位进行控制,列由高4位进行控制,且初始时行码和列码均为1,当有按键按下后,对应的位置会变为0。一般的显示电路是采用段码和位码对数码管进行显示控制,例如在本实验中,通过VCC片选S0,即选中第0个数码管,并通过段码片选进行数字图案的显示。段码的控制如下图所示。