vault backup: 2026-06-26 23:22:55

This commit is contained in:
2026-06-26 23:22:56 +08:00
parent f0272e1ceb
commit b5ab951ca8
9 changed files with 825 additions and 19 deletions
@@ -0,0 +1,186 @@
---
tags:
- 接口与通讯技术
- 定时器
- 计数器
- 可编程芯片
create time: 2026-06-26 23:05
---
# 8254 定时计数器
## 概述
8254(兼容 8253)是 Intel 公司生产的可编程定时/计数器芯片(Programmable Interval Timer, PIT),**在全部 4 套试卷中均有出现**,其中 **方波产生和计数初值计算** 是最高频题型。芯片内部包含 3 个独立的 16 位计数器,每个计数器有 6 种工作方式。
> [!tip] 考试要点
> - **计数初值计算**:`计数初值 = CLK频率 / 输出频率`
> - **方式 3(方波发生器)** 是最常考的工作方式
> - **控制字编写**:计数器选择 + 读写格式 + 工作方式 + 数制选择
> - **BCD 与二进制** 初值装入的区别
## 正文
### 1. 内部结构
```mermaid
graph TB
A["数据总线缓冲器 D0~D7"] --> B["读/写逻辑"]
B --> C["计数器 0"]
B --> D["计数器 1"]
B --> E["计数器 2"]
C --> F["CLK0, GATE0, OUT0"]
D --> G["CLK1, GATE1, OUT1"]
E --> H["CLK2, GATE2, OUT2"]
```
每个计数器有 3 条信号线:
| 信号 | 方向 | 功能 |
|------|------|------|
| **CLK** | 输入 | 时钟输入,每个下降沿使计数值减 1 |
| **GATE** | 输入 | 门控信号,控制计数的启动/暂停/触发 |
| **OUT** | 输出 | 根据工作方式输出不同波形 |
> [!question] 思考题
> 8254 的计数器是递增还是递减计数?计数值减到 0 后会怎样?
>
> 答:**递减计数**。装入初值后每来一个 CLK 下降沿计数值减 1。减到 0 后的行为取决于工作方式——方式 0 停止,方式 2/3 自动重装初值继续计数。
### 2. 端口地址
8254 占用 **4 个端口地址**:
| A1 A0 | 选中 | 说明 |
|:------:|:----:|------|
| 0 0 | 计数器 0 | 读写计数初值 |
| 0 1 | 计数器 1 | 读写计数初值 |
| 1 0 | 计数器 2 | 读写计数初值 |
| 1 1 | 控制寄存器 | 只写,用于写入控制字 |
> [!note] 每个计数器占用 1 个还是 2 个地址?
> 每个计数器只占用 **1 个端口地址**。16 位初值通过同一地址分两次写入(先低字节后高字节)。整个芯片共需 4 个端口地址。
### 3. 控制字格式
控制字写入控制寄存器(A1A0=11 的端口),格式如下:
```
D7 D6 D5 D4 D3 D2 D1 D0
[计数器] [读写格式] [工作方式] [数制]
00=计数器0 00=锁存 000=方式0 0=二进制
01=计数器1 01=仅低字节 001=方式1 1=BCD
10=计数器2 10=仅高字节 010=方式2
11=先低后高 011=方式3
100=方式4
101=方式5
```
> [!example] 控制字速算
> **要求**:计数器 0,方式 3(方波),先低后高,二进制
>
> D7D6=00(计数器 0), D5D4=11(先低后高), D3D2D1=011(方式 3), D0=0(二进制)
>
> 控制字 = `0011 0110B` = **36H**
>
> **要求**:同上但 BCD 计数 → D0=1 → 控制字 = **37H**
### 4. 六种工作方式
> [!tip] 考试重点
> 方式 2 和方式 3 的区别几乎每卷必考!
| 方式 | 名称 | 输出波形 | 触发 | 自动重装 | 典型应用 |
|:----:|------|----------|------|:--------:|----------|
| 0 | 计数结束中断 | 计数到 0 后 OUT 变高 | 软件 | 否 | 定时中断 |
| 1 | 可编程单稳态 | 触发后输出 N 个 CLK 宽度的负脉冲 | 硬件 | 否 | 单稳态触发器 |
| 2 | **频率发生器** | 每 N 个 CLK 输出 1 个 CLK 宽的负脉冲 | 软件 | 是 | **分频器** |
| 3 | **方波发生器** | 对称方波,占空比约 50% | 软件 | 是 | **方波产生** |
| 4 | 软件触发选通 | 计数到 0 后输出 1 个 CLK 宽的负脉冲 | 软件 | 否 | 软件定时选通 |
| 5 | 硬件触发选通 | 触发后计数到 0 输出 1 个负脉冲 | 硬件 | 否 | 硬件延迟脉冲 |
#### 方式 2 vs 方式 3 对比
```mermaid
graph LR
subgraph "方式 2 - 频率发生器"
A2["CLK 输入"] --> B2["计数器 N 分频"]
B2 --> C2["OUT: 周期性窄脉冲"]
end
subgraph "方式 3 - 方波发生器"
A3["CLK 输入"] --> B3["计数器 N 分频"]
B3 --> C3["OUT: 对称方波 50%"]
end
```
| 对比项 | 方式 2 | 方式 3 |
|--------|--------|--------|
| 输出波形 | 负脉冲(宽 1 个 CLK) | 对称方波 |
| 占空比 | 很小 | ≈ 50% |
| 输出频率 | CLK / N | CLK / N |
| 重装机制 | 计数到 1 时 OUT 变低,到 0 时重装 | 计数到 0 时自动重装,交替翻转 OUT |
> [!question] GATE 引脚在方式 2 和方式 3 中的作用?
> - GATE=0:暂停计数,OUT 输出高电平
> - GATE 上升沿:重新装入初值,开始计数
> - GATE=1:允许计数正常进行
### 5. 计数初值计算(核心公式)
$$
计数初值 = \frac{f_{CLK}}{f_{OUT}}
$$
> [!example] 试卷真题计算汇总
>
> | 题目来源 | CLK 频率 | 要求频率 | 计数初值 | 控制字 |
> |:--------:|:--------:|:--------:|:--------:|:------:|
> | 试题 A | 2 MHz | 2000 Hz | 1000 (03E8H) | 34H |
> | 试题 B | 1.193182 MHz | 100 Hz | 11932 (2EA4H) | 36H |
> | 试题 B | 1 MHz | 1 kHz | 1000 (03E8H) | 36H |
> | 试题 C | 1.19318 MHz | 1 kHz | 1193 (04A9H) | 36H |
> | 试题 D | 1 MHz | 1 kHz | 1000 (03E8H) | 36H |
### 6. BCD 计数 vs 二进制计数
| 项目 | 二进制(D0=0) | BCD(D0=1) |
|------|---------------|-------------|
| 计数范围 | 0000H~FFFFH (0~65535) | 0000~9999 |
| 初值装入 | 直接装入十六进制值 | 按 BCD 码装入 |
| 初值 1000 | 03E8H | 1000 (低字节=00, 高字节=10) |
> [!warning] BCD 方式装入初值的坑
> BCD 方式下初值 11932 的装入:
> - 低字节 = **32H**(低 2 位 BCD)
> - 高字节 = **11H**(高 2 位 BCD)
>
> 而不是 2EA4H!控制字也要从 36H 改为 **37H**(D0=1)。
### 7. 初始化编程模板
```asm
; 8254 初始化通用模板
; 假设端口地址为 PORT_0 ~ PORT_3
; 步骤 1:写控制字
MOV DX, PORT_3 ; 控制寄存器地址
MOV AL, 36H ; 控制字:计数器0, 方式3, 先低后高, 二进制
OUT DX, AL
; 步骤 2:写计数初值(先低后高)
MOV DX, PORT_0 ; 计数器 0 地址
MOV AX, 03E8H ; 计数初值 = 1000
OUT DX, AL ; 先写低字节 E8H
MOV AL, AH
OUT DX, AL ; 再写高字节 03H
```
> [!danger] 易错点
> 写初值时必须 **先低后高**(与控制字 D5D4=11 对应),而且低字节和高字节要 **分两次** `OUT` 到同一个端口地址。用 `OUT DX, AX` 一次写 16 位是错误的。
## 关联笔记
- [[8255A可编程并行接口]]
- [[8259A中断控制器]]
- [[8251A串行通信接口]]
- [[接口与通讯技术/试题册/index|试题册索引]]