/***** ;FileName: IicSMasU.a51 ;Describe: 51 系列模拟I2C 总线主控器驱动程序 ;Date: 2003/11/12 ;*****/ $include (IicSMasU.inc) public _IicTxdRxd public SlvAddr public SubAddr /******************************************************************************* * ;Name: bit _IicTxdRxd(TxdByte,RxdByte,&IicDataBuf) ;Describe: 发送数据给被控器/接收来自被控器的数据 ;Input: TxdByte=要发送数据的字节数 ; RxdByte=要接收数据的字节数 ; IicDataBuf=发送/接收缓冲区的首字节 ; (SlvAddr(被控器地址),SubAddr(单元地址)) ;Output: C(Retry=1):操作失败标志 ; IicDataBuf=接收到的数据的首字节(主接收时有效) ;调用说明: ; A.现行地址写: SlvAddr(写) !!!(带SubAddr 的器件不能使用该子程序) ; TxdByte=(发送数据字节数(SubAddr 为第一个要发送的数据)) ; RxdByte=0 ; B.指定地址写: SlvAddr(写),SubAddr ; TxdByte=(1+发送数据字节数) ; RxdByte=0 ; C.现行地址读: SlvAddr(读)
; TxdByte=0 ; RxdByte=要接收数据的字节数 ; D.指定地址读: SlvAddr(读),SubAddr ; TxdByte=1 ; RxdByte=要接收数据的字节数 ;Nesting level: 1 ;Change: A,C,R1, R4~R7 ;******************************************************************************* ****/ BitSegIicSM SEGMENT BIT overlayable RSEG BitSegIicSM Retry: dbit 1 指明I2C 最后的数据传送失败应该重复操作 BITEA: DBIT 1 存中断状态 DataSegIicSM SEGMENT DATA overlayable RSEG DataSegIicSM SlvAddr: ds 1 被控器地址 SubAddr: ds 1 单元地址 TxdByte equ r7 要发送数据的字节数(第一传递参数) RxdByte equ r5 要接收数据的字节数(第二传递参数) WaitXTm macro X 延时X 个机器周期 if X=0 exitm endif if X=1 nop endif if X=2 nop nop endif if X=3 nop nop nop endif if X>255 error "the number of X is too much" else mov r6,#X/2 DJNZ r6,$ endif
endm CodeSegIicSM SEGMENT CODE RSEG CodeSegIicSM _IicTxdRxd: SETB Retry 设置错误标志位 /***** ;发送起动条件 ;*****/ SendStart: SETB SDA SETB SCL WaitXTm IicDelay CLR SDA 产生起始信号 WaitXTm IicDelay CLR SCL 结束起动条件 /***** ;送被控器地址地址,数据 ;*****/ SendSlaAdr: MOV A,SlvAddr CJNE TxdByte,#0,SendSlaAdr1 SETB ACC.0 TxdByte=0 时进行读操作 SendSlaAdr1: SETB C 检测应答位时释放SDA 线 CALL XmByte JC IicErr 无应答出错 JB ACC.0,ReceiveData SlaAdr.0=1 时进行读操作 ;写操作 MOV A,SubAddr SendData: SETB C 检测应答位时释放SDA 线 CALL XmByte JC IicErr 无应答出错 MOV A,@R1 INC R1 DJNZ TxdByte,SendData DEC R1 MOV A,RxdByte JNZ SendStart RxdByte>0 时进行读操作 JMP SendStop
/***** ;Name: RcvByte ;Describe: 接收1 字节数据(接收8 位,发送+1 位(非)应答位) ;Input: C=1:发送非应答位(通知slave 停止通信) ; C=0:发送应答位(通知slave 继续发送后续字节) ;Output: A=接收到的数据, C=(非)应答位 ;Use: A,R4,C,R6(WaitXTm) ;*****/ RcvByte: MOV A,#0FFH 释放SDA 线允许输入 /***** ;Name: XmByte ;Describe: 发送1 字节数据(发送8 位,接收1 位(非)应答位) ;Input: A=待发送的数据, C=1(检测应答位时释放SDA 线) ;Output: C=1:slave 非应答(slave 不响应) ; C=0:slave 应答(slave 接收成功) ;Use: A,R4,C,R6(WaitXTm) ;*****/ XmByte: MOV R4,#9 设置数据格式为8 位+1 位(非)应答位 RXBit: RLC A 左移数据 MOV SDA,C output data SETB SCL MOV C,SDA input data WaitXTm IicDelay CLR SCL WaitXTm IicDelay DJNZ R4,RXBit 重复操作直到处理完所有数据位 RET ReceiveData: MOV A,RxdByte CJNE A,#2,ReceiveData1 RxdByte=1(最后一个字节)时,发送非应答位(C=1) ;否则发送应答位(C=0) ReceiveData1: CALL RcvByte MOV @R1,A INC R1 DJNZ RxdByte,ReceiveData /***** ? ;产生I2C 停止条件程序 ;*****/ SendStop: CLR Retry 清除错误标志位 IicErr: 出错返回 CLR SDA SETB SCL WaitXTm IicDelay SETB SDA MOV C,Retry RETURN ERROR FLAG(C=Retry) RET END
C语言声明: extern bit IicTxdRxd(uchar TxdByte,uchar RxdByte, uchar *IicDataBuf); //函数定义(程序入口地? extern data uchar SlvAddr; //被控器从地址 extern data uchar SubAddr; //单元地址子地?
直接调用即可。
|