实验4 定时器与计数器实验
一、实验目的
1:掌握8253的计数特点和编程方法。
2:掌握8253各类工作方式的基本工作原理。
3:掌握PC机中断处理系统的基本原理。
4:学会编写中断服务程序。
二、实验内容
1:8254计数器实验
8253/8254 内部结构:
【1】三个 16 位“减一”计数单元:
分别称为 CNTO、CNT1 和 CNT2。三个计数器相互独立、可以工作在不同的方式。每一个计数器都有对应的三条输入、输出信号线;CLK 外部计数脉冲输入线,OUT 计数器溢出信号线和 GATE 门控输入信号线(控制计数器是否工作)。
【2】控制寄存器:
芯片内部四个寄存器之一,占用一个寄存器单元的地址,由三个计数器共用。只能写入不能读出,用于设定计数器的工作方式。编程时在程序的初始化部分中,通过对该寄存器写入相应的命令字来设定对应计数器的工作方式。
【3】内部寄存器的地址定义:
芯片内部具有四个寄存器,CNTO、CNT1、CNT2 和控制寄存器,它们都有不同的地址。这些地址是由芯片的引脚 A1、A0 来设定,在系统中如果将A1、A0 与地址总线的A1、AO 连接,那么就会对应四个独立的 I/0 地址(参见表)。
【4】8253/8254 的编程命令:
作为可编程器件,8253/8254 是通过命令字来控制其工作方式的,命令字有两类:
- 初始化编程命令:用于设定计数器的功能、工作方式;
- 锁存读出命令:用于读出计数器中的计数值,或计数器的状态(8254)。
(1)8253/8254 的初始化控制字:
用于设定 8253/8254 内部三个定时计数器的 6 中工作方式、计数模式和读写指示(参见图)。
(2)8253/8254 的初始化编程:
在 8253/8254 工作之前,必须确定其工作方式、计数模式和读写指示等,这些都是通过向 8253 控制寄存器写入命令字来实现的。对 8253/8254 初始化所包含的内容有:
- 设置命令字:命令字中包含了计数器的工作方式、计数模式等相关的设定等,是使用输出指令将对应的命今字写入 8253 的控制寄存器中来实现的;
- 设置计数器的初值:8253/8253 为 1 位计数器。16 位初值的设定分为 8 位或 16 位设定两种方式,初值的设定应紧跟在“设置命令字”后。在写入计数初值时应当与前面命令字中相关设定位(WR1、WRO)保持一致。如:当使用 16 位初值设定时(WR1、WRO=11),必须使用两条指令完成初值的写入,即先写低 8 位初值后再写高 8 位初值:若采用8位初值设定时,当只写入高 8 位(WR1、WRO=10) 时,则低8 位自动清零;同理若只写入低8位 (WR1、WRO=01) ,则高8位自动清零(参见上图)。
- 8253 是一个可编程的定时计数器;
- 8253 具有三个计数器:CNTO、CNT1 和 CNT2,还有一个控制寄存器,它们各占一个地址(由引脚 A1、AO 确定);
- 在每一个计数器 CNTi 中,有三个部分构成:初值寄存器 CR、减一计数器 CE 和输出锁存器 OL;
- 初始化编程是 8253 正常工作的必要条件。初始化编程操作的顺序是:先想控制寄存器写入命令字,然后写入初值。如果是 16 位初值时,必须是先写入低8 位初值,然后再写入高 8 位初值;
- 输出锁存命令(读计数器的计数值),将当前的计数器的计数值捕捉到“输出锁存器OL”中。读命令对计数器的工作状态不会产生任何有影响。
【5】按图连接电路,将计数器 0 设置为方式 2,计数器初值为 N(N<=OFH),用手逐个输入单脉冲,编程使计数值在屏幕上显示,用逻辑笔观察OUT0电平变化(当输入N+1个脉冲后OUT0变高电平)。并将计数过程记录下来。
【6】接线表
待接线接口1 | 待接线接口2 |
8254的CLK0 | 单脉冲/正脉冲 |
8254的CS | I/O译码的Y0 |
8254的OUT0 | LED显示的L7 |
8254的GATE0 | +5V |
【7】程序的流程图
2:8254定时器实验
(1)按下图连接电路,将计数器0、计数器1分别设置工作方式,CLKO连接时钟1MHZ,由T0进行1000分频后变为1000HZ,再由T1进行1000分频后得1HZ。
(2)接线
待接线接口1 | 待接线接口2 |
8254的CLK0 | 1MHz的时钟 |
8254的CS | I/O译码的Y0 |
8254的OUT0 | 8254的CLK1 |
8254的GATE0和GATE1 | +5V |
8254的OUT1 | 逻辑笔 |
(3)程序的流程图
3:系统中断实验
(1)在 PC/XT 系统中,中断系统是由两片 8259A 构成(如图),可以管理 15 级中断。电路特点如下:
- 两片 8259A的 CASO~CAS2 同名端互联,从片 8259A 的INT 与主 8259A 的第二级中断请求输入连接;
- 主片 8259A 的端口地址在 020H~03FH 范围内有效,从片 8259A 的端口地址在0AOH~0BFH 范围内有效。由于将芯片的 AO 与地址总线的最低位连接,所以两个芯片的有效地址分别为 20H、21H 和 AOH、A1H;
- 主从片 8259A 的中断触发极性都为边沿(上升沿)有效;
- 选择为全嵌套方式,即 IRO 最高、IR1、IR2(从片的 IRO~IR7)、然后是主片的 IR3~IR7;
- 主、从芯片均采用非缓冲结构,主片的 SP/EN 端接高电平,从片的 SP/EN 端接低电平;
- 设定 0~7级对应的中断号为 08H~0FH,8~15 级对应的中断号为 70~77H。
系统上电时,ROM BIOS 对 8259A 的主片和从片要执行初始化命令、进行初始化操作。
【注意】:从系统安全性考虑,用户在使用系统中断资源时不应当在对其初始化,更不能擅自修改初始化设计。使用者只有严格遵守这些协议和约定才能有效的开发出用户的中断资源。
(2)中断向量和中断向量表:
当 CPU 响应某一个中断请求并转向对应的服务程序时是如何从主程序“准确”地跳转到对应的服务程序入口中的呢?答案便是:依靠“中断向量表”实现的。为了方便中断的处理,将所有的中断入口地址存放在一个连续的存储区域,并按照中断类型号的顺序依次排放。这样类似于一个数据表格的存储空间就称之为“中断向量表”。在这个表中,每一个中断向量要占用 4 个连续的存储单元。前两个单元(低地址)存放中断入口的偏移量;后两个单元(高地址)存放段地址,这样 256 个中断向量攻占用了 1024 个存储单元。
(3)CPU获取中断类型码的方法:
- CPU 内部中断时,由硬件电路自动提供;
- 软中断 INT n在指令的代码中提供;
- 可屏蔽的外中断 INTR 通过硬件(8259A)提供;
可见不同类型的中断其类型码的获取方式各不相同。
当 CPU 响应某一中断时,首先要将标志寄存器(16 位)、当前的段寄存器 CS 和指令指针寄存器的内容压入堆栈(占用 6 个栈单元),然后根据中断类型码重新组装CS、IP 值(即中断向量表的地址),通过中断向量表提供的中断服务程序入口地址( CS 值和 IP 值),准确的跳转到中断服务程序的入口。
(4)对于 PC/AT 及 286 以上微机内又扩展了一片 8259 中断控制,IRQ2 用于两片 8259 之间级连,对外可以提供 16 个中断源:
(5)实验内容:实验电路如图,直接用手动产单脉冲作为中断请求信号(只需连接一根导线)。要求每按一次开关产生一次中断,在屏幕上显示一次“TPCA Interrupt!”,中断10 次后程序退出。
(6)接线
待接线接口1 | 待接线接口2 |
总线的MIRQx | 单脉冲1/正脉冲 |
总线的SIRQx | 单脉冲2/正脉冲 |
(7)程序的流程图
1:系统中断主中断MIRQ3。
2:系统中断主中断MIRQ10。
(8)实验改进:编写IRQ3和IRQ10的中断嵌套程序。
三、源程序(含注释)
1:8254计数器实验
io8253a equ 283h io8253b equ 280h code segment assume cs:code start: ;补充编程,设置8253通道0的工作方式,送计数初值为0FH mov al,14h ;计数器0,方式2,(读/写低字节)0001 0100 mov dx,io8253a ;向控制口写控制字 out dx,al mov al,0fh ;写初值 mov dx,io8253b ;cnt0口 out dx,al lll: ;补充编程,读计数初值 in al,dx ;向cpu中输入脉冲 call disp ;调显示子程序 push dx mov ah,06h ;6号功能,直接读写 mov dl,0ffh ;输入,dl是输入字符的ascii int 21h ; pop dx jz lll ;if zf==1, jump to lll mov ah,4ch ;退出 return dos int 21h ;补充,显示子程序 disp proc near push dx and al,0fh ;清空高4位 mov dl,al ;数据转移到dl cmp dl,9 ;把dl和9比较 jle next ;if dl - 9 <= 0, jump to next(说明是数字) add dl,37h ;字母,a的ascii是41H,a的hex是0aH,因此需要加37H jmp output ;jump to output,否则会继续执行next里面的指令 next: add dl,30h ;0的ascii是30H,0的hex是00H,因此需要加30H output: mov ah,02h ;2号功能,打印一个字符 int 21h mov dl,0dh ;加回车符 int 21h mov dl,0ah ;加换行符 int 21h pop dx ret ;子程序返回 disp endp code ends end start |
2:8254定时器实验
io8253a equ 280h io8253b equ 281h io8253c equ 283h code segment assume cs:code start: mov al,00100111b ;控制字 00_10_011_1 mov dx,io8253c ;选定控制口 out dx,al ;写控制字 mov dx,io8253a ;选定cnt0 mov al,10H ;只写1000的高字节,输出 BCD 码的 1000 out dx,al ;写初值 mov dx,io8253c ;选定控制口 mov al,01110110b ;控制字 01_11_011_0 out dx,al ;写控制字 mov dx,io8253b ;选定cnt1 mov al,0E8H ;输出二进制的 1000=3E8H out dx,al ;写初值的低位 mov al,03H out dx,al ;写初值的高位 mov ah,4ch ;程序退出 int 21h code ends end start |
3:系统中断实验
(1)中断IRQ3
DATA SEGMENT MESS DB 'IRQ3!',0DH,0AH,'$' ;print的字符串 DATA ENDS CODE SEGMENT ASSUME CS: CODE, DS:DATA START: MOV AX, CS ;获取程序所在的段地址 MOV DS, AX ;把段地址加载到数据段寄存器ds,便于程序访问数据 MOV DX, OFFSET INT3 ;将INT3标签的偏移地址加载到DX寄存器中,准备用于设置IRQ3的中断向量 MOV AX,250BH ;设置IRQ3的中断向量 INT 21H IN AL,21H ;读中断屏蔽控制器 AND AL,0F7H ;开放IRQ3中断(将AL寄存器中的数据与1111 0111按位与操作,将IRQ3的屏蔽位清零) OUT 21H, AL ;将修改后的值写回中断控制器端口 MOV CX,10 ;记中断循环次数为10次 STI ;设置中断标志位,允许中断响应 LL: JMP LL ;程序进入一个无限循环 ;标签LL和JMP LL用于创建一个无限循环,程序会一直在这个循环中运行,等待IRQ3中断的发生 INT3: ;中断服务程序 MOV AX, DATA ;将数据段地址加载到AX寄存器 MOV DS, AX ;将数据段寄存器DS设置为数据段的值 MOV DX, OFFSET MESS ;将消息字符串的偏移地址加载到DX寄存器中,准备用于显示消息 MOV AH,09 ;DOS 9号功能,显示字符串 INT 21H MOV AL,20H ;将AL寄存器设置为20H,这是EOI(End of Interrupt)命令的值 OUT 20H, AL ;向中断控制器的20H端口发送EOI命令,表示中断处理完成 LOOP NEXT ;循环计数器CX递减,如果CX不为零,则跳转到标签NEXT,否则继续执行下一条指令 IN AL,21H ;从中断控制器的21H端口读取数据,以准备关闭IRQ3中断 OR AL,08H ;将AL寄存器的最低位设置为1,表示关闭IRQ3中断 OUT 21H, AL ;将修改后的值写回中断控制器端口,关闭IRQ3中断 STI ;置中断标志位 MOV AH,4CH ;返回DOS INT 21H NEXT: IRET
CODE ENDS END START |
(2)嵌套中断IRQ3和IRQ10
DATA SEGMENT MESS_BEGIN3 DB 'IRQ3 Begin!',0DH,0AH,'$' MESS_END3 DB 'IRQ3 End!',0DH,0AH,'$' MESS_BEGIN10 DB 'IRQ10 Begin!',0DH,0AH,'$' MESS_END10 DB 'IRQ10 End!',0DH,0AH,'$' ;int3和int10的提示字符 DATA ENDS CODE SEGMENT ASSUME CS:CODE, DS:DATA START: MOV AX, CS MOV DS, AX MOV DX, OFFSET INT3 MOV AX,250BH INT 21H ; 设置IRQ3的中断向量 MOV DX, OFFSET INT10 MOV AX,2572H INT 21H ; 设置IRQ10的中断向量 IN AL,21H ; 读中断屏蔽控制器 AND AL,0F7H ; 开放IRQ3中断 OUT 21H, AL IN AL,0A1H ; 读中断屏蔽控制器 AND AL,0FBH ; 开放IRQ10中断 OUT 0A1H, AL MOV CX,10 ; 记中断循环次数为10次 STI LL: JMP LL INT3: ; 中断服务程序 PUSH DX PUSH AX MOV AX, DATA MOV DS, AX MOV DX, OFFSET MESS_BEGIN3 MOV AH,09 ; 显示每次中断提示信息 INT 21H CALL DELAY MOV DX, OFFSET MESS_END3 MOV AH,09 ; 显示每次中断提示信息 INT 21H MOV AL,20H OUT 20H, AL ; 发出EOI结束命令 POP AX POP DX LOOP NEXT JMP EXIT INT10: PUSH DX PUSH AX MOV AX, DATA MOV DS, AX MOV DX, OFFSET MESS_BEGIN10 MOV AH,09 ; 显示每次中断提示信息 INT 21H CALL DELAY MOV DX, OFFSET MESS_END10 MOV AH,09 ; 显示每次中断提示信息 INT 21H MOV AL,20H OUT 0A0H, AL OUT 20H, AL ; 发出EOI结束命令 POP AX POP DX LOOP NEXT JMP EXIT NEXT: IRET EXIT: IN AL,21H OR AL,08H ; 关闭IRQ3中断 OUT 21H, AL IN AL,0A1H OR AL,04H ; 关闭IRQ10中断 OUT 0A1H, AL STI ; 置中断标志位 MOV AH,4CH ; 返回DOS INT 21H DELAY PROC NEAR PUSH CX MOV BX,0FFH LOOP1_DELAY: MOV CX,0FFFFH LOOP2_DELAY: LOOP LOOP2_DELAY DEC BX JNZ LOOP1_DELAY POP CX RET DELAY ENDP CODE ENDS END START |
四、遇到的问题和解决过程
问题1:在进行实验2的过程中,逻辑笔并没有出现闪烁的情况。
解决1:经代码验证后,发现是忘记将cnt1的控制字写入控制口中,而直接把控制字写入了cnt0的端口,因此逻辑笔处小灯不会发生变化。
问题2:在进行实验3的过程中,发现优先级高的中断打断优先级低的中断会出现错误的情况。当int10打断int3的时候,屏幕显示的具体结果为:int3开始——int10开始——int10结束——程序卡死。
解决2:未解决,怀疑可能是现场保护有问题或者是硬件设备有问题。
五、实验结果
1:8254计数器实验
(1)用手逐个输入单脉冲,计数值在屏幕上显示
在本实验中,计数的初值是F,每按下一个脉冲后,计数器会进行减1操作。同时,当结果减到1时,若再按下一个脉冲,则会reset到F。实验的具体结果如下图组所示。
脉冲0:计数结果为F。
脉冲1:计数结果为E。
......
脉冲14:计数结果为1。
脉冲15:计数结果为F。
(2)完整操作过程
完整操作过程如视频附件4-1.mp4所示。在视频中,我们不断按下单脉冲,并观察屏幕上显示的结果。
2:8254定时器实验
在本实验中,我们先利用cnt0进行计数,把频率从1MHz降低至1000Hz,再利用cnt1进行计数,把频率从1000Hz继续降低至1Hz,最终实现逻辑笔处的灯执行1秒1次闪烁的过程。同时,我们观察【脉冲】处的闪烁情况,可以发现原始clk0的频率非常高。实验的具体结果如下图组所示。
3:系统中断实验
(1)IRQ3中断
在本实验中,按下一次单脉冲,则屏幕上会新增一行【IRQ3!】的输出,表示int3执行一次。
(2)IRQ10和IRQ3嵌套中断
在本实验中,由于int10的优先级比int3高,所以理论上int10可以立马打断int3,而int3无法立马打断int10,需要等int10执行完成后再执行int3。如果不设计互相打断,则按下主片IR3所连接的脉冲就会执行int3,按下从片IR10所连接的脉冲就会执行int10。
六、体会与总结
1:定时计数器由8253实现。8253一共有4个端口,分别是计数器0、计数器1、计数器2、控制寄存器,其地址分别是00、01、10、11。每个计数器有6种可选择的工作方式,设置工作方式时通过控制寄存器实现。6种控制方式的基本功能如下图所示。
2:8253的方式控制字。方式控制字由8位二进制数组成,分别对应计数器选择、读写字节数、工作方式、码制。在方式控制字的初始化程序中,首先需要将dx指向控制端口,并向al中送入方式控制字,进行一次out,然后需要将dx指向目标计数器,并向al中送入计数器的初值(需要区分高8位和低8位)。方式控制字的编写如下图所示。
【1】计数器选择:
【2】读写字节数
【3】工作方式
【4】码制
3:中断控制由8259实现。8259的优先级可以采用固定优先级和循环优先级。在固定优先级中,在单片中IR0优先权最高,IR7最低。一般全嵌套方式与特殊全嵌套方式的区别如下图所示。