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的定时器,那个东西也挺有意思的。咱们到时候再聊。