1. 8155芯片概述

做嵌入式这么多年,8155这个芯片我接触得真不少。它虽然不是什么高大上的新器件,但在很多经典系统里都能看到它的身影。今天咱们就来聊聊这颗芯片,从里到外把它看透。

1.1 8155芯片简介

8155,全称是Intel 8155,一颗可编程的RAM/IO扩展芯片。说白了,它就是给单片机"扩容"用的。你想想看,早期的8051单片机,内部RAM才128字节,IO口也就那么几个,想做点复杂的事情根本不够用。这时候8155就派上用场了。

我个人习惯把它叫做"三合一"芯片。为什么?因为它集成了三样东西:

  • 256字节的静态RAM — 给系统增加存储空间
  • 22个可编程IO口 — 扩展输入输出能力
  • 一个14位可编程定时器/计数器 — 处理定时和计数任务

我记得刚入行那会儿,带我的老工程师就跟我说:"8155这芯片,你玩透了,单片机系统的IO扩展和存储管理基本就通了。"现在想想,这话一点不假。

核心特点:8155是Intel公司为MCS-51系列单片机配套设计的接口芯片,采用40引脚DIP封装,单一+5V供电。它通过地址/数据复用总线与单片机连接,大大简化了系统设计。

1.2 8155芯片内部结构

咱们来看看8155内部到底长什么样。我习惯把它分成几个功能模块来理解:

模块名称 功能描述 寄存器地址
256×8位静态RAM 数据存储,掉电丢失 00H~FFH
命令/状态寄存器 控制芯片工作模式,读取状态 命令寄存器:写入;状态寄存器:读出
PA口(8位) 可编程输入/输出端口A 01H
PB口(8位) 可编程输入/输出端口B 02H
PC口(6位) 可编程输入/输出/控制端口C 03H
定时器/计数器 14位减法计数器,可编程输出波形 04H(低8位)、05H(高6位+模式)

嗯,这里要注意一点:命令寄存器和状态寄存器共用同一个地址,但一个是只写,一个是只读。写操作时写入的是命令字,读操作时读出的是状态字。这个细节我在项目中吃过亏,后面会讲到。

1.3 8155芯片引脚功能

8155有40个引脚,咱们挑关键的来说。我把它分成几组:

电源与复位

  • VCC(引脚40):+5V电源
  • VSS(引脚20):地
  • RESET(引脚4):复位信号,高电平有效。复位后IO口全部变为输入模式

地址/数据总线

  • AD0~AD7(引脚12~19):地址/数据复用总线,和8051的P0口直接相连
  • ALE(引脚11):地址锁存使能,下降沿锁存地址
  • IO/M(引脚7):IO/存储器选择。高电平选IO口,低电平选RAM
  • CE(引脚8):片选信号,低电平有效

读写控制

  • RD(引脚9):读选通,低电平有效
  • WR(引脚10):写选通,低电平有效

IO端口

  • PA0~PA7(引脚21~28):A端口,8位
  • PB0~PB7(引脚29~36):B端口,8位
  • PC0~PC5(引脚37~39、1~3):C端口,6位

定时器

  • TIMER IN(引脚6):定时器时钟输入
  • TIMER OUT(引脚5):定时器输出

实战小技巧:我曾经在一个项目中,因为IO/M引脚的电平没处理好,导致读写RAM时老是出错。后来查了半天才发现,原来是IO/M信号和地址线有毛刺。解决办法是在IO/M引脚上加一个10kΩ上拉电阻,同时用施密特触发器整形一下。嗯,这种小坑,遇到了才知道疼。

1.4 8155芯片工作原理

8155的工作原理,说白了就是通过总线与单片机通信,然后根据命令字配置各个模块的工作模式。

咱们来看一个典型的读写时序:

// 8155初始化示例代码(C51)
#include <reg51.h>

#define CMD_PORT 0xFF00   // 命令寄存器地址
#define PA_PORT  0xFF01   // PA口地址
#define PB_PORT  0xFF02   // PB口地址
#define PC_PORT  0xFF03   // PC口地址
#define TIMER_L  0xFF04   // 定时器低8位
#define TIMER_H  0xFF05   // 定时器高6位+模式

void Init_8155(void)
{
    // 设置命令字:PA输出,PB输出,PC输出,禁止定时器
    // 命令字格式:D7 D6 D5 D4 D3 D2 D1 D0
    // D0: PA口模式(0=输入,1=输出)
    // D1: PB口模式(0=输入,1=输出)
    // D2,D3: PC口模式(00=输入,11=输出)
    // D4,D5: 定时器控制(00=禁止,01=停止,10=启动,11=启动并输出)
    // D6,D7: 未使用
    
    XBYTE[CMD_PORT] = 0x07;  // 0000 0111:PA、PB、PC全部输出
}

void Write_RAM_8155(unsigned char addr, unsigned char data)
{
    // 写RAM时,IO/M必须为低电平
    // 这里假设IO/M由地址线A8控制
    XBYTE[addr] = data;  // addr < 0x100 时自动选中RAM
}

unsigned char Read_RAM_8155(unsigned char addr)
{
    return XBYTE[addr];
}

为什么会这样设计?因为8155内部有地址译码逻辑。当CE为低电平时,芯片被选中。然后根据IO/M的电平,决定是访问RAM还是IO口。ALE下降沿时锁存地址,之后RD或WR信号控制数据的读写方向。

我刚开始做8155驱动时,总觉得时序很复杂。后来画了个时序图,一步一步分析,发现其实就三步:

  1. 送地址:通过AD0~AD7送出地址,ALE下降沿锁存
  2. 选方向:根据IO/M和CE确定访问对象
  3. 传数据:RD或WR有效时,数据在AD0~AD7上传输

避坑指南:我曾经在一个项目中,因为忽略了8155的复位状态,导致系统上电后IO口输出乱电平。8155复位后,所有IO口默认是输入模式,内部寄存器清零。如果你需要输出高电平,必须在初始化时先配置好方向,再写数据。否则,嘿嘿,你的外设可能会"抽风"。

关于定时器,我再多说两句。8155的定时器是14位的,可以产生方波、连续方波、单脉冲等多种波形。它的工作模式通过定时器高字节的高两位来设置:

M2 M1 输出模式 说明
00 单次方波 计数到0时输出高电平,然后停止
01 连续方波 自动重装,持续输出方波
10 单脉冲 计数到0时输出一个正脉冲
11 连续脉冲 自动重装,持续输出脉冲

嗯,这里要注意:定时器的计数初值要写入低8位和高6位(高两位是模式控制)。写入顺序是先写低8位,再写高6位+模式。这个顺序搞反了,定时器可能不工作。

好了,关于8155的概述就聊到这儿。这颗芯片虽然老,但它的设计思想——地址/数据复用、可编程IO、片内集成RAM——至今还在很多现代芯片中沿用。理解了8155,你就理解了单片机系统扩展的基本套路。