?? lm74saa1064.#3
字號:
;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 + -