📄 pcf8574ab.asm
字号:
;实验29 程序PCF8574AB.ASM
;用I2C(与SUNBUS兼容)虚拟总线的方法编程.调用I2C通用子程序软件包.
;程序功能:PCF8574是带SUMBUS总线的串口转并口的数据转换芯片.一个8位
;口连结8个开关(K1-K8)作输入,二个8位输出锁存口分别连结8个LED灯,指示二个8位
;输出.程序安排二个8位输出口锁存的数据电平相反.
; 运行参考程序,在连续输出三组数据:#0AAH,#55H;#0FH,#0F0H及#00H,#0FFH之后,
;处于输入状态,等待用户通过开关K1~K8输入数据并显示出来。
$include (C8051F020.inc)
SLA1W EQU 70H ;PCF8574 A片写的节点地址(地址开关S1:000H)
SLA1R EQU 71H ;PCF8574 A片读的节点地址
SLA2W EQU 72H ;PCF8574 B片写的节点地址 (地址开关S2:001H )
SLA2R EQU 73H ;PCF8574 B片读的节点地址
SLA3W EQU 74H ;PCF8574 C片写的节点地址 ((地址开关S3:010H)
SLA3R EQU 75H ;PCF8574 C片读的节点地址
SLA EQU 60H
COM EQU 17H
SLAW EQU 62H
SLAR EQU 63H
NUMBYT EQU 61H ;被传送的字节数存放单元
MTD EQU 20H ;发送数据缓冲区首地址
MRD EQU 30H ;接收字节缓冲区首地址
VSCL EQU P0.1 ;模拟I2C总线时钟线
VSDA EQU P0.0 ;模拟I2C总线数据线
ORG 0
SJMP MAIN
MAIN: MOV WDTCN,#0DEH ;禁止看门狗定时器
MOV WDTCN,#0ADH;
MOV XBR2,#40H ;交叉开关使能
ACALL INITA ;作为输入用的芯片应先初始化。
ACALL OUTPUT1 ;输出数据0AAH
ACALL DELAY ;延时
ACALL OUTPUT2 ;输出数据55H
ACALL DELAY ;延时
ACALL OUTPUT3 ;输出数据0FH
ACALL DELAY ;延时
ACALL OUTPUT4 ;输出数据0F0H
ACALL DELAY ;延时
ACALL OUTPUT5 ;输出数据0H
ACALL DELAY ;延时
LOOP: ACALL PCFIO ;从输入器件U1读取开关K1~K8的状态数据并存入
AJMP LOOP ;MRD中,再送U2,U3去。
OUTPUT1: MOV A,#0AAH ;输出数据0AAH
PUSH ACC
ACALL WRITEB
POP ACC
CPL A
ACALL WRITEC
RET
OUTPUT2: MOV A,#55H ;输出数据55H
PUSH ACC
ACALL WRITEB
POP ACC
CPL A
ACALL WRITEC
RET
OUTPUT3: MOV A,#0FH ;输出数据0FH
PUSH ACC
ACALL WRITEB
POP ACC
CPL A
ACALL WRITEC
RET
OUTPUT4: MOV A,#0F0H ;输出数据0F0H
PUSH ACC
ACALL WRITEB
POP ACC
CPL A
ACALL WRITEC
RET
OUTPUT5: MOV A,#0H ;输出数据0H
PUSH ACC
ACALL WRITEB
POP ACC
CPL A
ACALL WRITEC
RET
PCFIO : ACALL READA ;从输入器件U1读取开关K1~K8的状态数据并存入MRD中
MOV A,MRD
MOV B,A
ACALL WRITEB ;将读入的数据送器件B
MOV A,B
CPL A ;将读入的数据取反后送器件C
ACALL WRITEC
RET
READA: MOV SLAW,#SLA1W ;读A口
MOV SLAR,#SLA1R
WRA: MOV SLA,SLAR
MOV NUMBYT,#1
LCALL RDNBYT
RET
INITA: MOV SLAW,#SLA1W ;初始化:应置输入口锁存器为高电平
MOV SLAR,#SLA1R
MOV MTD,#0FFH
MOV SLA,SLAW
MOV NUMBYT,#1
LCALL WRNBYT
RET
WRITEB: MOV SLAW,#SLA2W ;将数据送器件B
MOV SLAR,#SLA2R
ACALL WRBC
RET
WRITEC: MOV SLAW,#SLA3W ;将数据送器件C
MOV SLAR,#SLA3R
ACALL WRBC
RET
WRBC: MOV MTD,A
MOV SLA,SLAW
MOV NUMBYT,#1
LCALL WRNBYT
RET
DELAY: MOV R7,#50 ;5s
DL2: MOV R6,#100 ;100ms
DL1: MOV R5,#250 ;1ms假定晶振为6MHZ
DL0: DJNZ R5,DL0
DJNZ R6,DL1
DJNZ R7,DL2
RET
;发送一个字节数据(WRBYT)子程序,该子程序是向虚拟IIC总线的数据线VSDA上发送
;一个字节数据的操作。调用本子程序前将要发送的数据送入A中。占用资源:R0,C。
WRNBYT: MOV R3,NUMBYT
LCALL STAA ;启动IIC总线
MOV A,SLA ;发送SLAW字节
LCALL WRBYT
LCALL CACK ;检查应答位
JB F0,WRNBYT ;非应答位则重发
MOV R1,#MTD
WRDA: MOV A,@R1
LCALL WRBYT
LCALL CACK
JB F0,WRNBYT
INC R1
DJNZ R3,WRDA
LCALL STOP
RET
;向被控器件发送N个字节数据(WRNBYT)子程序
WRBYT: MOV R0,#08H ;8为数据长度送R0中
WLP: RLC A ;发送数据左移,使发送位入C
JC WR1 ;判断发送"1"还是"0",发送"1"转WR1
AJMP WR0 ;发送"0"转WR0
WLP1: DJNZ R0,WLP ;8位是否发送完,未完转WLP
RET ;8位发送完结束
WR1: SETB VSDA ;发送"1"程序段
SETB VSCL
NOP
NOP
CLR VSCL
CLR VSDA
AJMP WLP1
WR0: CLR VSDA ;发送"0"程序段
SETB VSCL
NOP
NOP
CLR VSCL
AJMP WLP1
;通用N字节接收子程序(RDNBYT)
RDNBYT:MOV R3,NUMBYT
LCALL STAA ;发送启动位
MOV A,SLA ;发送寻址字节(读)
LCALL WRBYT
LCALL CACK ;检查应答位
JB F0,RDNBYT ;非正常应答时重新开始
RDN: MOV R1,#MRD ;接收数据缓冲区首址MDR入R1
RDN1: LCALL RDBYT ;读入一个字节到接收数据缓冲中
MOV @R1,A
DJNZ R3,ACK ;N节读完否?未完转ACK
LCALL MNACK ;N个字节读完发送非应答位
LCALL STOP ;发送停止信号
RET ;子程序结束
ACK: LCALL MACK ;发送应答位
INC R1 ;指向下一个接收数据缓冲单元
SJMP RDN1 ;转读入下一个字节数据
CACK: SETB VSDA ;置VSDA为输入方式
SETB VSCL ;使VSDA上数据有效
CLR F0 ;预设F0=0
MOV C,VSDA ;输入VSDA引脚状态
JNC CEND ;检查VSDA状态,正常应答转CEND,且F0=0
SETB F0 ;无正常应答,F0=1
CEND: CLR VSCL ;子程序结束,使VSCL=0
RET
MACK: CLR VSDA;发送应答位MACK子程序
SETB VSCL
NOP
NOP
CLR VSCL
SETB VSDA
RET
MNACK: SETB VSDA ;发送非应答位 MNACK子程序
SETB VSCL
NOP
NOP
CLR VSCL
CLR VSDA
RET
;从VSDA上接收一个字节数据(RDBYT)子程序,该子程序用来从VSDA上读取一个字节数据.执行本程序后,从VSDA上读取的一个字节存放在R2或A中。资源占用:R0,R2,C。
RDBYT: MOV R0,#08H ;8位数据长度如R0
RLP: SETB VSDA ;置VSDA为输入方式
SETB VSCL ;使VSDA上数据有效
MOV C,VSDA ;读入VSDA引脚状态
MOV A,R2 ;读入"0"程序段,由C拼装入R2中
RLC A
MOV R2,A
CLR VSCL ;使VSCL=0可继续接收数据位
DJNZ R0,RLP ;8位读完否?未读完转RLP
RET
STAA: SETB VSDA;启动STAA子程序
SETB VSCL
NOP
NOP
CLR VSDA
NOP
NOP
CLR VSCL
RET
STOP:CLR VSDA;停止(STOP)子程序
SETB VSCL
NOP
NOP
SETB VSDA
NOP
NOP
CLR VSDA
CLR VSCL
RET
END
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -