?? pcf8591ad.#2
字號:
;參考程序B: PCF8591AD.ASM PCF8591的AD轉換實驗.
;芯片PCF8951共有四個A/D輸入通道:AD0,AD1,AD2,AD3,分別與四個電位器(R1,R2,R3,R4)
;連接,用以調節電位器的輸出電壓。其中AD0通道既可測量電位器輸出電壓,也可用于測
;量從J1插座輸入的外接電壓,須用開關J2加以選擇。J4插座提供由PCF8591輸出的時鐘
;方波信號。SAA1064驅動四個數碼管顯示一路AD轉換后得到的數據。顯示格式如下表:
;通道號: AD轉換結果(高四位) AD轉換結果(低四位)
; 3 E 7
;選定channel=3(用戶可修改),用小改刀調節R4,可觀察到數碼管上顯示的數據的變化.
$include (C8051F020.inc)
CHIP_A EQU 090H ; PCF8591芯片的寫地址
CHIP_B EQU 070H ; SAA1064芯片的寫地址
COM EQU 17H ;SAA1064的控制命令
ADCOM0 EQU 0H ;PCF8591 AD 0通道的控制命令
ADCOM1 EQU 1H ;PCF8591 AD 1通道的控制命令
ADCOM2 EQU 2H ;PCF8591 AD 2通道的控制命令
ADCOM3 EQU 3H ;PCF8591 AD 3通道的控制命令
ADCOM EQU 50H ;PCF8591 A/D的控制命令
DACOM EQU 40H ;PCF8591 D/A的控制命令
;SMBus狀態:
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)主收發器接收數據成功;主機發送ACK
SMB_MRDBNACK EQU 58H ;(MR)主收發器接收數據成功;主機發送NACK
DSEG ; 數據段;
ORG 30H
RECEIVE_BYTEH: DS 1 ; 保存SMBus剛收到的16位數據的高字節
RECEIVE_BYTEL: DS 1 ; 保存SMBus剛收到的16位數據的低字節
TRANSMIT_BYTE: DS 1 ; 保存SMBus待發送的字節
SLA_ADD: DS 1 ; 保存從地址
WRI_ADD: DS 1 ; 保存從地址+ WRITE
READ_ADD: DS 1 ; 保存從地址+ READ
SUBADR_ADD: DS 1 ; 要訪問的器件地址
; 用于暫存數據的單元
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 ;剛發送的字節為l,表示地址;為0是數據字節
CSEG ;代碼段
ORG 00H ;復位
LJMP MAIN
ORG 03BH ;SMBus中斷向量
LJMP SMBus_ISR
;主程序
MAIN: MOV SP,#7H
MOV R1,#50H
MOV WDTCN,#0DEH ;禁止看門狗定時器
MOV WDTCN,#0ADH;
LCALL PORT_Init ;初始化I/O端口
; 初始化SMBus程序段
MOV SMB0CN,#04H ; 配置 SMBus在確認周期發送 ACK
MOV SMB0CR,#0C9H ; 設置時鐘速率=100 kHz (系統時鐘:11.0592MHZ)
ORL SMB0CN,#40H ; 允許SMBus
ORL EIE1,#02H ; 允許SMBus中斷
CLR SM_BUSY ; 為第一次傳輸清除SM_Busy標志
MAINB: SETB EA
ACALL READAD
LCALL EXCHG ; 數據轉換子程序:將二進制數轉換為使進制數
LCALL SAA1064 ;SAA1064驅動四位數碼管顯示子程序
AJMP MAINB ; 運行結束,重復運行.
READAD:MOV R1,#50H
;MOV DATA_BYTE,#2
MOV DATA_ADDR,#03H ;裝入PCF8591控制字:指定AD第3通道采樣
MOV DATA_COUNT,#1H ;裝入數據塊長度:一次只送一字節
MOV TRANSMIT_BYTE,DATA_BYTE ; 將待發送數據裝入TRANSMIT_BYTE
SETB EA ;開中斷
MOV SLA_ADD,#CHIP_A ;裝入從器件的寫地址
MOV SUBADR_ADD,DATA_ADDR ;將存儲器子地址裝入 SUBADR_ADD
LCALL RECEIVE ;調用接收子程序
MOV 30H,RECEIVE_BYTEL ;從PCF8591讀出的8位數據并存入30H
RET
;發送子程序SEND;發送單字節寫操作。
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
;接收子程序RECEIVE執行一次,AD讀出采樣數據(8位).
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 ;取SLA_ADD到A
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 中斷程序 ,處理SMBUS 中斷
SMBus_ISR:
PUSH PSW ; 保護現場
PUSH ACC ;
PUSH DPH ;
PUSH DPL ;
MOV A,SMB0STA ; 將當前SMBus狀態(SMB0STA)裝入累加器
; 每個狀態對應一個地址偏移量
ANL A,#7FH ; 屏蔽最高位
MOV @R1,A ;在50H---60H中存放SMB0STA和SMB0DAT,可查看中斷路徑
INC R1
MOV @R1,SMB0DAT;
INC R1
MOV DPTR,#SMB_STATE_TABLE ; DPTR指向狀態表的起始地址
JMP @A+DPTR ;轉移到當前狀態
;SMBuS狀態表 ;(SMB0STA =00H)
SMB_STATE_TABLE: ; SMB_BUS_ERROR總線錯誤(對所有方式)
ORG SMB_STATE_TABLE+SMB_BUS_ERROR
SETB STO ; 停止位置1,使硬件復位
JMP SMB_ISR_END ; 中斷返回
;SMB_START ; (SMB0STA =08H)
;主發送器/接收器發送起始位成功.再將從機寫地址送SMB0DAT并清除START位.
ORG SMB_STATE_TABLE+SMB_START
MOV SMB0DAT,WRI_ADD ; 裝載從地址+ W````
CLR STA ; 清除START位
JMP SMB_ISR_END ; 中斷返回
;SMB_RP_START ;(SMB0STA =10H)
;主發送器/接收器發送重復起始位成功.
;再將從機讀地址送SMB0DAT并清除START位.
ORG SMB_STATE_TABLE+SMB_RP_START
MOV SMB0DAT,READ_ADD ;裝載從地址+ R
CLR STA ; 清除START位
JMP SMB_ISR_END
;SMB_MTADDACK (SMB0STA =18H)
;主發送器(MT)發送從地址+W成功;收到 ACK(從機應答)
;再將要發的子地址送入SMB0DAT.
ORG SMB_STATE_TABLE+SMB_MTADDACK
MOV SMB0DAT,SUBADR_ADD ;裝載從器件的子地址到SMB0DAT.
SETB BYTE_SENT ;BYTE_SENT=1.在下一次中斷調用時存儲器地址剛被發送
JMP SMB_ISR_END
;SMB_MTADDNACK (SMB0STA =20H)
;主發送器(MT)發送從地址+W成功;收到 NACK(從機無應答)
;用確認查詢重試。發送 STOP+START
ORG SMB_STATE_TABLE + SMB_MTADDNACK
SETB STO
SETB STA
JMP SMB_ISR_END
;SMB_MTDBACK (SMB0STA =28H)
;主發送器(MT)發送數據字節成功;收到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 ;(SMB0STA =30H)
;主發送器(MT)發送數據成功;收到NACK,從機無應答.
;用確認查詢重試。發送STOP+START重試
ORG SMB_STATE_TABLE+SMB_MTDBNACK
SETB STO
SETB STA
JMP SMB_ISR_END
; SMB_MRADDACK ;(SMB0STA =40H)
;(MR)主收發器發送從地址+R成功;收到 ACK(從機應答).主機發送ACK.
ORG SMB_STATE_TABLE+SMB_MRADDACK
;SETB AA ;主機發送ACK,轉入SMB_MRDBACK
CLR AA
JMP SMB_ISR_END
; SMB_MRADDNACK ;(SMB0STA =48H)
;(MR)主收發器發送從地址+R成功;收到NACK(從機無應答),發送重復起始位重試
ORG SMB_STATE_TABLE+SMB_MRADDNACK
SETB STA
JMP SMB_ISR_END
;SMB_MRDBACK (SMB0STA =50H)
;(MR)主收發器接收數據成功;主機發送ACK .
ORG SMB_STATE_TABLE+SMB_MRDBACK
MOV RECEIVE_BYTEH, SMB0DAT
CLR AA ;主機發NACK(清除AA),下一次中斷來時轉入;SMB_MRDBNACK(58H)
SETB STO
CLR SM_BUSY;
JMP SMB_ISR_END
;SMB_MRDBNACK ;(SMB0STA =58H)
ORG SMB_STATE_TABLE+SMB_MRDBNACK
MOV RECEIVE_BYTEL, SMB0DAT
SETB STO
SETB AA ;主機發ACK,為下一次傳輸置位AA
CLR SM_BUSY;
JMP SMB_ISR_END
;狀態表結束,處理"SMB_MTDBACK"狀態碼的程序段。
;對于地址字節剛發出的狀態。通過檢查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
PORT_Init :
MOV OSCXCN,#67H ;啟動外部振蕩器11.0592MHZ`
CLR A ;最少等待1ms
DJNZ ACC,$ ; 等待 ~512us
DJNZ ACC,$ ;;等待 ~512us
WAITT:MOV A,OSCXCN ; 查詢 XTLVLD是否為1
JNB ACC.7,WAITT
ORL OSCICN,#8 ; 選擇外部振蕩器(11.0592MHZ)作為系統時鐘源
ORL OSCICN,#80H ; 使能丟失時鐘檢測器
MOV P0MDOUT,#00 ;P0口為開漏方式
MOV XBR0,#01H ;通過功能選擇開關將將SDA接P0.0引腳,SCL接P0.1引腳
MOV XBR2 ,#40H; 允許功能選擇開關和弱上拉
MOV P74OUT ,#0FFH; P4,P5,P6,P7為推拉式輸出
RET
LDELAY:MOV R4,#50H
LDE: ACALL DEL0
DJNZ R4,LDE
RET
DEL0:MOV R7,#0FFH ;延時子程序
TM: MOV R6,#0FFH
DJNZ R6,$
DJNZ R7,TM
RET
EXCHG: MOV A,30H ;數據格式轉換子程序.在31H中存放從PCF8591讀出的原始數據.
MOV B,A
ANL A,#0FH ;轉換為十進制數額村入7BH,7CH中
MOV 7CH,A
MOV A,B
ANL A,#0F0H
SWAP A
MOV 7BH,A
MOV 7AH,#11H
MOV 79H,DATA_ADDR ;AD通道號存入78H
MOV 78H,#10H
RET
SAA1064: ;向SAA1064依次連續寫入5個數 .要顯示的數據在78H,79H,7AH,7BH,7CH中
SETB EA
MOV R1,#50H
MOV DATA_COUNT,#5H ; 裝入待寫數據塊的長度
MOV SLA_ADD,#CHIP_B ; 裝入從器件的寫地址
MOV DATA_ADDR ,#0
MOV 78H,#10H
MOV R0,#78H
DISPP: MOV A,@R0
MOV DPTR,#BCD ;查表,找到顯示的數據(字型碼)
CLR BYTE_SENT
MOVC A,@A+DPTR
CJNE R0,#79H,DD
ADD A,#80H
DD: MOV TRANSMIT_BYTE ,A
MOV SUBADR_ADD,DATA_ADDR ; 將存儲器(SAA1064)的地址裝入 SUBADR_ADD
LCALL SEND
INC R0 ;地址加1
INC DATA_ADDR
DJNZ DATA_COUNT,DISPP ; 計數器減1,不為0則循環到開始處
CLR EA
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 17H ,0 ;COM
END
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -