3、8155的I/O口编程:控制字格式、工作模式设置与输入输出操作实例

好,咱们接着往下聊。上一章我们把8155的硬件引脚和内部结构理清了,这一章就进入实战环节——怎么让8155的I/O口真正干活。

说白了,8155的I/O口编程就是三件事:写控制字、设模式、读写数据。听起来简单,但我在项目里见过不少新手在这上面翻车。嗯,咱们一个一个来拆解。

3.1 8155控制字格式——这个寄存器决定了所有

8155内部有一个8位的命令寄存器,地址是00H(当IO/M=1时)。你往这个地址写一个字节,就能控制整个芯片的工作状态。这个字节就叫控制字

控制字的每一位都有特定含义,我习惯把它分成三组来看:

符号 功能说明
D7、D6 PA模式 00=输入,01=输出,10=选通,11=双向
D5、D4 PB模式 00=输入,01=输出,10=选通,11=保留
D3、D2 PC模式 00=输入,01=输出,10=选通(低4位),11=选通(高4位)
D1 INTE 0=禁止中断,1=允许中断
D0 TM 0=禁止定时器,1=启动定时器

重点提醒:控制字写入后立即生效。但如果你要改变I/O口的工作模式,建议先让系统进入一个安全状态,比如先把输出口置为高阻或已知电平。我曾经在调试一个电机控制板时,直接在运行中改了PA口模式,结果电机突然反转……嗯,从那以后我改控制字前都会先停掉外设。

3.2 I/O口工作模式设置——三种模式,三种玩法

8155的A口和B口各有四种模式,但实际常用的就三种:基本输入输出、选通输入输出、双向选通。C口比较特殊,它既可以做基本I/O,也可以做选通控制信号。

3.2.1 基本输入输出模式(模式0)

这是最简单的模式。你把PA或PB设为00或01,它们就是纯粹的输入或输出口。没有握手信号,没有中断,你写什么它就输出什么,你读什么它就是输入什么。

举个例子,假设我们要把PA口设为输出,PB口设为输入:

; 控制字:PA输出(01), PB输入(00), PC输入(00), 禁止中断, 禁止定时器
; 二进制:01 00 00 0 0 = 40H

MOV A, #40H      ; 控制字=40H
MOV DPTR, #8000H ; 8155命令寄存器地址(假设CS=8000H)
MOVX @DPTR, A    ; 写入控制字

; 现在PA口是输出,向PA口写数据
MOV DPTR, #8001H ; PA口地址
MOV A, #0FFH     ; 让PA口所有引脚输出高电平
MOVX @DPTR, A

; 读PB口数据
MOV DPTR, #8002H ; PB口地址
MOVX A, @DPTR    ; 读入PB口状态

我的小技巧:在基本输出模式下,如果你想让某个引脚输出低电平,直接写0就行。但要注意,8155的输出驱动能力有限,我测过大概能拉4个TTL负载。如果你要驱动LED,记得串个限流电阻,别直接怼上去。

3.2.2 选通输入输出模式(模式1)

这个模式就有点意思了。它引入了握手信号,用C口的某些引脚来做控制。说白了,就是告诉CPU:数据准备好了,快来拿;或者告诉外设:数据已经就绪,快来取。

选通模式下,C口的引脚分配是这样的:

C口引脚 选通输入 选通输出
PC0 AINTR (A口中断请求) AOUT (A口缓冲器满/空)
PC1 ABF (A口缓冲器满) ASTB (A口选通)
PC2 ASTB (A口选通) AINTR (A口中断请求)
PC3 BINTR (B口中断请求) BOUT (B口缓冲器满/空)
PC4 BBF (B口缓冲器满) BSTB (B口选通)
PC5 BSTB (B口选通) BINTR (B口中断请求)

你想想看,有了这些信号,CPU就不需要一直轮询了。外设准备好数据后,通过选通信号通知8155,8155再通过中断告诉CPU。这样CPU就能腾出手干别的事。

注意:选通模式下,C口的引脚功能是固定的,你不能随意分配。我见过有人把PC0当普通IO用,结果发现它一直在产生中断……嗯,那是因为C口已经被选通模式占用了。

3.2.3 双向选通模式(模式2)

这个模式只有A口能用。说白了就是A口既能输入也能输出,而且带握手信号。C口的高5位(PC3-PC7)被用来做控制。

我个人很少用这个模式,因为太复杂了。除非你要接一个双向数据总线,比如和某个智能外设通信,否则基本输入输出加软件握手就够用了。

3.3 输入输出操作实例——来点实战

光说不练假把式。咱们来写一个完整的例子:用8155的PA口控制8个LED,PB口读取8个按键状态。

3.3.1 硬件连接

  • PA0-PA7 → 8个LED(通过300Ω电阻接地)
  • PB0-PB7 → 8个按键(按下为低电平,上拉电阻到VCC)
  • 8155的CS接地址译码器输出,假设基地址为8000H
  • IO/M引脚接高电平(I/O地址模式)

3.3.2 软件实现

; 初始化8155
INIT_8155:
    MOV A, #43H      ; 控制字:PA输出(01), PB输入(00), PC输出(01), 禁止中断, 禁止定时器
    MOV DPTR, #8000H ; 命令寄存器地址
    MOVX @DPTR, A
    RET

; 主循环:读取按键状态,控制LED亮灭
MAIN_LOOP:
    ; 读取PB口按键状态
    MOV DPTR, #8002H ; PB口地址
    MOVX A, @DPTR    ; 读入按键值
    CPL A            ; 取反,因为按下为低电平
    ; 现在A中存放的是按键状态,1表示按下

    ; 将按键状态输出到PA口,控制LED
    MOV DPTR, #8001H ; PA口地址
    MOVX @DPTR, A    ; 输出到LED

    ; 延时一下,防止抖动
    LCALL DELAY_10MS

    SJMP MAIN_LOOP   ; 无限循环

; 简单的延时子程序
DELAY_10MS:
    MOV R7, #50
DELAY_LOOP:
    MOV R6, #100
    DJNZ R6, $
    DJNZ R7, DELAY_LOOP
    RET

避坑指南:我曾经在写这个程序时,发现按键按下后LED反应很迟钝。查了半天,原来是忘了加去抖延时。按键在按下和释放的瞬间会有机械抖动,如果不做软件去抖,8155可能会读到多次跳变。10ms的延时基本够用,如果环境干扰大,可以加到20ms。

3.3.3 选通模式下的输入输出

如果你要用选通模式,比如从一个A/D转换器读取数据,代码会稍微复杂一点:

; 设置A口为选通输入模式
; 控制字:PA选通输入(10), PB输出(01), PC选通(10), 允许中断, 禁止定时器
; 二进制:10 01 10 1 0 = 9AH

MOV A, #9AH
MOV DPTR, #8000H
MOVX @DPTR, A

; 等待A/D转换完成(通过查询ABF信号)
WAIT_ADC:
    MOV DPTR, #8003H ; C口地址(在选通模式下,C口内容反映状态)
    MOVX A, @DPTR
    ANL A, #02H      ; 检查PC1(ABF)位
    JZ WAIT_ADC      ; 如果ABF=0,说明数据还没准备好

    ; 数据已就绪,读取PA口
    MOV DPTR, #8001H
    MOVX A, @DPTR    ; 读入A/D转换结果

    ; 处理数据...

你想想看,用选通模式的好处就是不用猜数据什么时候到。ABF信号会明确告诉你:数据在缓冲器里了,快来拿。这比定时轮询靠谱多了。

3.4 小结

这一章咱们把8155的I/O口编程讲透了。控制字是总开关,模式选择决定了你怎么用,而输入输出操作就是最终的目的。我个人建议,刚开始学的时候先用基本模式,把读写操作跑通了,再尝试选通模式。别一上来就搞双向选通,容易把自己绕进去。

下一章我们会讲8155的定时器,那个东西也挺有意思的。咱们到时候再聊。