📄 wsmbus24c02.asm
字号:
;参考程序B:WSMBUS24C02.ASM程序清单如下:
;WSMBUS24C02.ASM程序功能:AT24C02读/写并显示在数码管上读/写地址的范围:00H--3FH
;用8255驱动四位LED数码管,显示存储单元的地址和内容,显示格式:
;存储器的地址 存储器单元的内容
; 00H---3FH 10H---4FH
$include (C8051F020.inc) ; SFR声明
PPA EQU 8000H ;8255的端口地址.用数码管显示AT24C02读/写的数据
PPB EQU 8001H
PPC EQU 8002H
CWR EQU 8003H
AT24C02 EQU 0A0H ; AT24C02芯片的写地址
;SMBus状态(SMB9STA):
SMB_BUS_ERROR EQU 00H ;(所有方式)总线错误
SMB_START EQU 08H
;(MT&MR)主收发器发送起始位成功.再将从机写地址送SMB0DAT
SMB_RP_START EQU 10H
;(MT&MR)主收发器重复发送起始位成功,再将从机读地址送SMB0DAT
SMB_MTADDACK EQU 18H
;(MT)主收发器发送从地址+W成功;收到 ACK(从机应答)
;再将从器件的子地址送入SMB0DAT
SMB_MTADDNACK EQU 20H ;(MT)主收发器发送从地址+W成功;收到 NACK.
SMB_MTDBACK EQU 28H ;(MT)主收发器发送数据字节成功;收到ACK(从机应答)
SMB_MTDBNACK EQU 30H ;(MT)主发送器发送数据成功;收到NACK(从机无应答).
SMB_MTARBLOST EQU 38H ;(MT)总线竞争失败
SMB_MRADDACK EQU 40H ;(MR)主收发器发送从地址+R成功;收到 ACK(从机应答)
SMB_MRADDNACK EQU 48H ;(MR)主收发器发送从地址+R成功;收到NACK
SMB_MRDBACK EQU 50H ;(MR)主收发器接收数据成功;主机将AA清另 ,发送ACK
SMB_MRDBNACK EQU 58H ;(MR)主收发器接收数据成功;主机发送NACK ,1'STO
DSEG ; 数据段
ORG 30H;
TRANSMIT_BYTE: DS 1 ;保存SMBus待发送的字节
RECEIVE_BYTE: DS 1 ; 保存SMBus刚收到的字节
SLA_ADD: DS 1 ;保存从地址
WRI_ADD: DS 1 ; 保存从地址+ WRITE
READ_ADD: DS 1 ; 保存从地址+ READ
MEM_ADD: DS 1 ;要访问的EEPROM存储器地址
; 用于暂存数据的单元
DATA_COUNT: DS 1 ;计数器变量
DATA_BYTE: DS 1 ; 数据
DATA_ADDR: DS 1 ; 存储器地址
BSEG
ORG 00H
RW: DBIT 1 ;R/W命令位。L为READ,0为WRITE
SM_BUSY: DBIT 1 ;SMBus忙标志(软件保存)
BYTE_SENT: DBIT 1 ; 用于表示刚发送的字节。即
; BYTE_SENT为l表示是EEPROM地址; BYTE_SENT为0表示是数据字节
CSEG ;代码段
ORG 00H ;复位
LJMP MAIN
ORG 03BH ;SMBus中断向量
LJMP SMBus_ISR
;主程序
MAIN: MOV SP,#7H
MOV WDTCN,#0DEH ;禁止看门狗定时器
MOV WDTCN,#0ADH;
LCALL PORT_Init ;初始化I/O端口及系统时钟
; 初始化SMBus
MOV SMB0CN,#04H ; 配置 SMBus在确认周期发送 ACK
MOV SMB0CR,#0D8H ; 设置时钟速率=100 kHz ,系统时钟为8MHZ.
ORL SMB0CN,#40H ; 允许SMBus
ORL EIE1,#02H ; 允许SMBus中断
CLR SM_BUSY ; 为第一次传输清除SM_Busy标志
SETB EA ;开中断
; TESTW: 依次连续写入64个递增的数到EEPROM24C01中去
MOV DATA_BYTE,#10H ;装入待写的数据
MOV DATA_ADDR,#00H ; 装入待写数据的首地址
MOV DATA_COUNT,#040H ; 装入待写数据块的长度
TESTW: ;发送数据DATA_BYTE到存储器地址DATA_ADDR
MOV SLA_ADD,#AT24C02 ; 装入从器件的写地址
MOV TRANSMIT_BYTE,DATA_BYTE ; 将待发送数据装入TRANSMIT_BYTE
MOV MEM_ADD,DATA_ADDR ; 将存储器(EEPROM24C01)的地址装入 MEM_ADD
LCALL SEND ; 调用发送子程序
INC DATA_BYTE ;存入的数据递增
INC DATA_ADDR ;地址加1
DJNZ DATA_COUNT,TESTW ; 计数器减1,不为0则循环到开始处
; TESTR: 从EEPROM24C01中依次连续读出96个递增的数,并在数码管上显示出来.
MOV DATA_ADDR,#00H ; 装入首地址
MOV DATA_COUNT,#40H ; 装入数据块长度
TESTR: ;发送DATA_BYTE到存储器地址DATA_ADDR
MOV SLA_ADD,#AT24C02 ;装入从器件的写地址
MOV MEM_ADD,DATA_ADDR ;将存储器地址装入 MEM_ADD
LCALL RECEIVE ; 调用接收子程序
MOV A,RECEIVE_BYTE ;将接收到的字节装入累加器
LCALL EXCH ;将累加器A中的数(压缩的BCD码)存如7AH,7BH中.
LCALL DISPLED ;在数码管上显示刚读出来的数据
INC DATA_ADDR ;地址加1
DJNZ DATA_COUNT,TESTR ; 计数器减1,不为0则循环到开始处
SJMP $ ; 运行结束,原地等待.
;发送子程序SEND;
;子程序SEND向EEPROM发送单字节
;假设从地址、存储器地址和要发送的数据已经装入到它们各自的变量中。
;该子程序管理SM_BUSY位,设置 RW=WRITE,装入 WRI_ADD,开始写操作。
SEND:
PUSH ACC ;保存累加器
JB SM_BUSY,$ ;等待SMBus空闲
CLR RW ; RW= 0(写)
MOV A,SLA_ADD ; 取SLA_ADD到A
MOV WRI_ADD,A ;将SLA_ADD+ WRITE保存到WRI_ADD
SETB SM_BUSY ; 占用SMBus
SETB STA ; 启动发送过程
JB SM_BUSY,$ ;等待发送结束(在中断中处理)
POP ACC
RET
; 接收子程序RECEIVE
;假设从地址和存储器已经装入到它们各自的变量中。
;该子程序管理 SM_BUSY位,设置 RW=READ,装入 READ_ADD和 WRI_ADD,启动传输过程。
;接收过程包括一个写待访问存储器地址的操作、一个重复起始位和一个读操作。
RECEIVE:
PUSH ACC ;保存累加器
JB SM_BUSY,$ ;等待 SMBus空闲
SETB RW ;RW= l(读)
MOV A,SLA_ADD ;取SLA_ADD到A
MOV WRI_ADD,A ;保存SLA_ADD+ WRITE到WRI_ADD
MOV A,SLA_ADD
ORL A,#01
MOV READ_ADD,A ; 保存SLA_ADD+READ到 READ_ADD
SETB SM_BUSY ; 占用SMBus
SETB STA ; 启动发送过程
JB SM_BUSY,$ ;等待接收结束(在中断服务中处理)
POP ACC ; 恢复累加器
RET
;SMBus 中断程序
;用状态码SMB0STA值查找表,寻找8字节的程序段.
;从状态表的开始位置向下偏移,偏移量为其状态代码值(8的整数倍)。
SMBus_ISR:
PUSH PSW ; 保护现场
PUSH ACC ;
PUSH DPH ;
PUSH DPL ;
MOV A,SMB0STA ; 将当前SMBus状态装入累加器;每个状态对应一个地址偏移量
ANL A,#7FH ; 屏蔽最高位,因为使该位为 1的状态在本例
; 中没有定义
MOV DPTR,#SMB_STATE_TABLE ; DPTR指向状态表的起始地址
JMP @A+DPTR ;转移到当前状态
;SMBuS状态表
SMB_STATE_TABLE:
ORG SMB_STATE_TABLE+SMB_BUS_ERROR ;( SMB0STA=00H),ERROR总线错误
SETB STO ; 停止位置1使硬件复位
JMP SMB_ISR_END ; 中断返回
;SMB_START,主发送器/接收器已发送起始位,R/W位总是为0(W),因先写存储器地址
ORG SMB_STATE_TABLE+SMB_START ; (SMB0STA=08H)
MOV SMB0DAT,WRI_ADD ; 装载从地址+ W
CLR STA ; 清除START位
JMP SMB_ISR_END ; 中断返回
;SMB_RP_START
;主发送器/接收器:已发送重复起始位
ORG SMB_STATE_TABLE+SMB_RP_START ;( SMB0STA=10H)
MOV SMB0DAT,READ_ADD ;装载从地址+ R
CLR STA ; 清除START位
JMP SMB_ISR_END
;SMB_MTADDACK,主发送器:已发送从地址+WRITE,收到ACK
ORG SMB_STATE_TABLE+SMB_MTADDACK ;( SMB0STA=18H)
MOV SMB0DAT,MEM_ADD ;装载存储器地址
SETB BYTE_SENT ;BYTE_SENT=1.在下一次中断调用时存储器地址刚被发送
JMP SMB_ISR_END
;SMB_MTADDNACK
;主发送器:已发送从地址+WRITE,收到 NACK。从器件不应答
;用确认查询重试。发送 STOP+START
ORG SMB_STATE_TABLE+SMB_MTADDNACK ;( SMB0STA=20H)
SETB STO
SETB STA
JMP SMB_ISR_END
;SMB_MTDBACK ;(SMB0STA=28H)
;主发送器:已发送数据字节;收到ACK。该状态在读和写操作中都要用到.
;检查BYTE_SENT:如果为1,则说明刚发出的是存储器地址;为0,刚发出的是数据字节
ORG SMB_STATE_TABLE+SMB_MTDBACK
JBC BYTE_SENT,ADDRESS_SENT ;如果BYTE_SENT=1,清除该位并转到
;ADDRESS_SENT去执行状态表以外的处理程序
JMP DATA_SENT ; 如果BYTE_SENT=0,数据刚被发出,
; 传输过程完成,转到传输结束
;SMB_MTDBNACK
;主发送器:已发送数据字节;收到NACK,从器件不应答
;用确认查询重试。发送STOP+START重试
ORG SMB_STATE_TABLE+SMB_MTDBNACK ;( SMB0STA=30H)
SETB STO
SETB STA
JMP SMB_ISR_END
; SMB_MTARBLOST
;主发送器:竞争失败,不应发生此情况。如果发生,重新启动传输
ORG SMB_STATE_TABLE+SMB_MTARBLOST ;( SMB0STA=38H)
SETB STO
SETB STA
JMP SMB_ISR_END
; SMB_MRADDACK
;主接收器:从地址+READ已发送。收到ACK
;设置为在下一次传输后发送NACK,因为那将是最后的字节
ORG SMB_STATE_TABLE+SMB_MRADDACK ;9(40H)
CLR AA ;在确认周期发送NACK
JMP SMB_ISR_END
; SMB_MRADDNACK
;主接收器:已发送从地址+READ。收到 NACK
;从器件不应答。发送重复起始位重试
ORG SMB_STATE_TABLE+SMB_MRADDNACK ;( SMB0STA=48H)
SETB STA
JMP SMB_ISR_END
;SMB_MRDBACK
;主接收器:已收到数据字节, ACK已发送
;不应出现,因为 AA已在前一状态被清除。如果发生,发送 STOP
ORG SMB_STATE_TABLE+SMB_MRDBACK ;( SMB0STA=50H)
SETB STO
JMP SMB_ISR_END
;SMB_MRDBNACK
;主接收器:已收到数据字节。已发送 NACK
;读操作完成。读数据寄存器并发送STOP
ORG SMB_STATE_TABLE+SMB_MRDBNACK ;( SMB0STA=58H)
MOV RECEIVE_BYTE, SMB0DAT
SETB STO
SETB AA ; 为下一次传输置位AA
CLR SM_BUSY;
JMP SMB_ISR_END
;状态表结束:
;检查RW位确定处理方法。如果为读,则转到RW_READ,如果为写,则将待发送数据装入SMBODAT。
ADDRESS_SENT:
JB RW,RW_READ
MOV SMB0DAT,TRANSMIT_BYTE ;装入数据
JMP SMB_ISR_END ;中断返回
;对于地址字节刚发出的状态。重复发送START,启动存储器读操作
RW_READ:
SETB STA ;重复发送START
JMP SMB_ISR_END ;中断返回
;写操作,数据字节已发出。传输过程结束。发送STOP,释放总线,中断返回
DATA_SENT:
SETB STO ;发送STOP后中断返回
CLR SM_BUSY ; 释放 SMBus
JMP SMB_ISR_END ; 中断返回
;SMBus ISR exit
;恢复寄存器,清除SI位,从中断返回
SMB_ISR_END:
CLR SI
POP DPL
POP DPH
POP ACC
POP PSW
RETI
EXCH:MOV B,A
ANL A,#0FH
MOV 74H,A
MOV A,B
SWAP A
ANL A,#0FH
MOV 73H,A
MOV A,B
MOV A,DATA_ADDR
MOV B,A
ANL A,#0FH
MOV 71H,A
MOV A,B
SWAP A
ANL A,#0FH
MOV 70H,A
MOV A,B
MOV 72H,#15H
RET
;显示功能子程序,显示2个字节,被显示的字节在7AH,7BH中
DISPLED: ACALL PORT_Init
ACALL C8255 ;8255初始化,为显示数据作准备
MOV R2,#01H
MOV R5,#5
MOV R0,#70H
DSP1: MOV DPTR,#PPB
MOV A,R2
MOVX @DPTR,A
MOV A,@R0
CJNE A,#15H,SS
AJMP DSP2
SS: ANL A,#0FH
DSP2: MOV DPTR,#BCD
MOVC A,@A+DPTR
MOV DPTR,#PPC
MOVX @DPTR,A
ACALL DEL0
MOV A,R2
RL A
MOV R2,A
INC R0
DJNZ R5,DSP1
MOV DPTR,#PPB
MOV A,#0H
MOVX @DPTR,A
RET
BCD: DB 3FH,06H,5BH,4FH ;显示数值,0,1,2,3
DB 66H,6DH,7DH,07H ;4,5,6,7
DB 7FH,6FH,77H,7CH ;8,9,A,B
DB 39H,5EH,79H,71H ;C,D,E,F
DB 73H,3EH,31H,6EH ;P,U,Z,Y
DB 0FFH,00H ;8,灭
C8255:
MOV A,#80H ; 设置PC口,PB口为输出,PA口为输入
MOV DPTR,#CWR ;#8003H为8255的控制寄存器地址
MOVX @DPTR,A
RET
PORT_Init :
ORL OSCICN,#06H ; 将内部振荡器频率设置为8MHz
MOV P0MDOUT,#00 ;P0口为开漏方式
MOV XBR0,#01H ;通过功能选择开关将将SDA接P0.0引脚,SCL接P0.1引脚
MOV XBR2 ,#40H; 允许功能选择开关和弱上拉
MOV P74OUT ,#0FFH; P4,P5,P6,P7为推拉式输出
MOV EMI0CF ,#2cH
;EMIF工作在地址/数据复用方式,只用外部存储器,ALE高/低脉宽占1个SYSCLK周期
MOV EMI0TC ,#6cH;地址建立/保持时间占0个SYSCLK周期,/WR和/RD占12个周期
RET
LDELAY:MOV R4,#2H
LDE: ACALL DEL0
DJNZ R4,LDE
RET
DEL0:MOV R7,#06FH ;延时子程序
TM: MOV R6,#0FFH
DJNZ R6,$
DJNZ R7,TM
RET
END
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -