📄 lm74saa1064.asm
字号:
;LM74SAA1064.ASM程序清单如下:2005.11.3
$include (C8051F020.inc) ; SFR声明
SAA1064ADR EQU 070H ; SAA1064芯片的写地址
; SMBus状态及其对应的偏移地址:
SMB_BUS_ERROR EQU 00H ;(所有方式)总线错误
SMB_START EQU 08H ; (MT&MR)已发送起始位
SMB_RP_START EQU 10H ; (MT&MR)重复起始位
SMB_MTADDACK EQU 18H ; (MT)已发送从地址+W;收到 ACK
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)收到数据字节;已发送ACK
SMB_MRDBNACK EQU 58H ;(MR)收到数据字节;已发送NACK
DSEG ; 数据段;
ORG 30H;
SLA: DS 1 ;保存从地址
SLAW: DS 1 ; 保存从地址+ WRITE
SUBADR: DS 1 ;要访问的器件SAA1064的子地址
; 用于暂存数据的单元
COUNT: DS 1 ;存放数据数目的单元
DATA1: DS 1 ; 存放数据的单元
SUBADDR: DS 1 ; 存放SAA1064的子地址SUBADR
BSEG
ORG 20H
RW: DBIT 1 ;R/W命令位。l=READ,0=WRITE
SM_BUSY: DBIT 1 ;SMBus忙标志(软件保存)
BYTE_SENT : DBIT 1
CSEG ;代码段
ORG 00H ;复位
LJMP MAIN
ORG 033H ;SPI中断向量
LJMP SPI_ISR
ORG 03BH ;SMBus中断向量
LJMP SMBus_ISR
ORG 100H
;主程序
MAIN: MOV SP,#7
MOV WDTCN,#0DEH ;禁止看门狗定时器
MOV WDTCN,#0ADH;
LCALL SPI_SMBUS_Init ;初始化I/O端口
ABC: LCALL LM74 ;LM74采集温度值(16位数),存入40H,41H中
CLR SM_BUSY ; 为第一次传输清除SM_Busy标志
SETB EA
MOV SUBADDR,#00H ; 装入SAA1064的子地址(SUBADR=00H)
MOV COUNT,#6H ; 装入待写数据块的长度
MOV SLA,#SAA1064ADR ; 装入从器件的写地址(70H)
MOV R0,#7AH ; R0做计数器用.从RAM 7AH单元开始
MOV A,#02
MOV EIE1,A ; 允许SMBus中断,不允许SPI中断
LCALL SEND ; SAA1064的发送子程序SEND
LCALL DELY
SJMP MAIN; 运行一遍,再循环运行.
TAB: DB 3FH,06H,5BH,4FH,66H,6DH,7DH,07H,7FH,6FH,39H,17H
;COM=#17H是SAA1064的控制命令 ;共阴极7段LED数码管的显示字形编码表;(0,1,2,3,4,5,6,7,8,9,C,COM)
;SAA1064的发送子程序SEND;
;SEND子程序向SAA1064写入六位数据(17H+三位温度值+字符"C").
; 依次连续写入6个数到SAA1064中去:17H+四位数字+"C"
;该子程序管理SM_BUSY位,设置 RW=WRITE,装载 SLAW,启动写操作。
SEND: ;SEND子程序用中断方式向SAA1064写入六位数据(0,17H,及四位温度值)
PUSH ACC ;保存累加器
JB SM_BUSY,$ ;等待SMBus空闲
CLR RW ; RW= 0(写)
MOV A,SLA ; 取SLA_ADD到A
MOV SLAW,A ;将SLA_ADD+ WRITE保存到SLAW
SETB SM_BUSY ; 占用SMBus
SETB STA ; 启动发送过程
JB SM_BUSY,$ ;等待发送结束(在中断中处理)
POP ACC
RET
;SMBus 中断程序
;在中断程序中实现对不同状态码的软件处理,SMBus状态码表被分成8字节的状态段,
;用状态码索引值查找表,寻找8字节的程序段,;从状态表的开始位置向下偏移,偏移量为;其状态代码值。每个状态用ORG命令起始。
SMBus_ISR:
PUSH PSW ; 保护现场
PUSH ACC ;
PUSH DPH ;
PUSH DPL ;
MOV A,SMB0STA ; 将当前SMBus状态装入累加器,每个状态对应一个地址偏移量
MOV DPTR,#SMB_STATE_TABLE ; DPTR指向状态表的起始地址
JMP @A+DPTR ;转移到当前状态
;SMBuS状态表
SMB_STATE_TABLE: ; SMB_BUS_ERROR总线错误.
ORG SMB_STATE_TABLE+SMB_BUS_ERROR ;1.( 状态寄存器SMB0STA =00H)
SETB STO ; 停止位置1使硬件复位
JMP SMB_ISR_END ; 中断返回
;SMB_START
;主发送器/接收器:已发送起始位,再发送读和写操作的存储器地址
ORG SMB_STATE_TABLE+SMB_START ; 2.( 状态寄存器SMB0STA =08H)
MOV SMB0DAT,SLAW ; 装载从地址+ W
CLR STA ; 清除START位
JMP SMB_ISR_END ; 中断返回
;SMB_RP_START
;主发送器/接收器:已发送重复起始位
;该状态只应在读操作期间出现,在已发出存储器地址,并得到确认之后发出
ORG SMB_STATE_TABLE+SMB_RP_START ;3(状态寄存器SMB0STA =10H)
CLR STA ; 清除START位
JMP SMB_ISR_END
;SMB_MTADDACK
;主发送器:已发送从地址+WRITE,收到ACK
ORG SMB_STATE_TABLE+SMB_MTADDACK ;4.( 状态寄存器SMB0STA =18H)
MOV SMB0DAT,SUBADDR ;装载存储器地址
SETB BYTE_SENT ;BYTE_SENT=1.存储器地址刚被发送出去。
JMP SMB_ISR_END
;SMB_MTADDNACK
;主发送器:已发送从地址+WRITE,收到 NACK。从器件不应答
;用确认查询重试。发送 STOP+START
ORG SMB_STATE_TABLE + SMB_MTADDNACK ;5.( 状态寄存器SMB0STA =20H)
SETB STO
SETB STA
JMP SMB_ISR_END
;SMB_MTDBACK ;6(状态寄存器SMB0STA =28H)
;主发送器:已发送数据字节;收到ACK。主机共需发送六个字节到SAA1064
;检查DATA_COUNT,六个字节送完否?送完了,就转DATA_SENT,传输结束
;由于状态码的地址存放间隔只有8字节的空间。所以在指令码需要多于8字节的场合,
;程序要转到状态表以外的代码空间。
ORG SMB_STATE_TABLE+SMB_MTDBACK
DJNZ COUNT,ADDRESS_SENT
JMP DATA_SENT
;SMB_MTDBNACK
;主发送器:已发送数据字节;收到NACK,从器件不应答
;用确认查询重试。发送STOP+START重试
ORG SMB_STATE_TABLE+SMB_MTDBNACK ;7(状态寄存器SMB0STA =30H)
SETB STO
SETB STA
JMP SMB_ISR_END
; SMB_MTARBLOST
;以下是处理"SMB_MTDBACK"状态码的程序段。
;写SAA1064,则将待发送数据装入SMBODAT。
ADDRESS_SENT:
MOV DPTR,#TAB ;查表,找到显示的数据(字型码)
MOV A,@R0 ;RO初值=7AH
MOVC A,@A+DPTR ;查表,找出RAM 7AH---7EH中的数据的字型码.
CJNE R0,#7CH,SS ;在个位后面加小数点
ADD A,#80H
SS: MOV DATA1 ,A
INC R0
MOV SMB0DAT,DATA1 ;将要显示的数据(字型码)送SAA1064
JMP SMB_ISR_END ; 中断返回
;这是一个写操作,数据字节已发出。传输过程结束。发送STOP,释放总线,中断返回
DATA_SENT:
SETB STO ;发送STOP后中断返回
CLR SM_BUSY ; 释放 SMBus
JMP SMB_ISR_END ; 中断返回
;恢复寄存器,清除SI位,从中断返回
SMB_ISR_END:
CLR SI
POP DPL
POP DPH
POP ACC
POP PSW
RETI
SPI_SMBUS_Init :
ORL OSCICN,#01H ; 将内部振荡器频率设置为4MHz
MOV XBR0,#03;选择P0.0~P0.3分别为SPI接口的SCK、MISO、MOSI和NSS
;选择P0.4~P0.5分别为SMBUS总线的SDA,SCL
MOV XBR1,#0
MOV XBR2 ,#40H; 允许功能选择开关和弱上拉
; 初始化SMBus程序段
MOV SMB0CN,#04H ; 配置 SMBus在确认周期发送 ACK
MOV SMB0CR,#0ECH ; 设置时钟速率=100 kHz(内部振荡器频率设置为4MHz)
ORL SMB0CN,#40H ; 允许SMBus
MOV A,#03
MOV EIE1,A ; 允许SMBus中断,允许SPI中断
MOV SPI0CFG ,#11000111B ;选择在时钟的第2个边沿采样,
;SCK的空闲状态为高电平,移位数为8位
MOV SPI0CN,#00000011B ;允许主方式,允许SPI
MOV SPI0CKR,#19 ;按照SPI0CKR的计算公式,选择SPI0CKR中的值应该为19
RET
LM74: ;LM74采样温度值(二进制16位数)
MOV R4,#2 ;要从LM74读入的数据有两个字节
SETB EA ;CPU开中断
MOV A,EIE1
ANL A,#01
MOV EIE1,A ;置ESPI0位为1,允许SPI申请中断
MOV R1,#40H ;数据接收区首地址.
SETB P0.7
ACALL DEL0
CLR P0.7
ACALL DEL0
MOV SPI0DAT,A ;启动SPI发送,产生SCK.
ACALL DEL0 ;中断服务程序从MISO端接收来自LM74的高8位(MOV A,SPI0DAT)
MOV SPI0DAT,A ;启动SPI发送,产生SCK
ACALL DEL0 ;中断服务程序从MISO端接收来自LM74的低8位(MOV A,SPI0DAT)
CJNE R4,#0,LM74
SETB P0.7
LCALL EXHH ;整理温度数据
RET
SPI_ISR:PUSH ACC
PUSH PSW
CLR SPIF
MOV A,SPI0DAT
MOV @R1 ,A ;取下一个数
INC R1
DJNZ R4,BACK ;是否接收到2个数?未完转中断返回
MOV A,EIE1 ;已完,置ESPI0位为0,
ANL A,#0FEH
MOV EIE1,A ;置ESPI0位为0,禁止SPI申请中断
BACK: POP PSW
POP ACC
RETI
POP ACC
RETI
EXHH: MOV A,41H ; 2x(41h)+2x(40h)
RLC A
MOV A,40H
RL A
ADDC A,#0
ACALL EXCH ;将温度值由二进制数转化为十进制数.
MOV 7DH,#0 ;
MOV A,41H
ANL A,#40H
CJNE A,#40H,PP1 ;加小数点
MOV 7DH,#5H
PP1: MOV 79H,#0
MOV A,40H ;从40H最高位位符号判别位,
ANL A,#80H
CJNE A,#80H,PP2 ; 正号:79H<--#0
MOV 79H,#40H ;负号: 79H<--#40H ("-")
PP2: RET
EXCH : MOV B,#10 ;将温度值由二进制数转化为三位十进制数
DIV AB
MOV 7CH,B ; 7AH存百位数
MOV B,#10
DIV AB
MOV 7AH,A ; 7BH存十位数
MOV A,B
MOV 7BH,A
MOV A,7CH ; 7CH存个位数
MOV 7CH,A
MOV 7EH,#0AH ;SAA1064显示"C"字
MOV 7AH,#0BH ;当用SAA1064显示时,(TAB+0AH)=#17H,
RET ;#17H是SAA1064的控制命令COM
DEL0: MOV R6,#0FH
TM: MOV R7,#0FFH
DJNZ R7,$
DJNZ R6,TM
RET
;长延时子程序
DELY:MOV R5,#0FFH
TTM1: LCALL DEL0
DJNZ R5,TTM1
RET
END
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -