下面是汇编的:
-----启动-----
START1:
LCALL DEL5US
SETB SDA1
LCALL DEL5US
SETB SCL1
LCALL DEL5US
CLR SDA1
LCALL DEL5US
CLR SCL1
LCALL DEL5US
RET
-----结束-----
STOP1:
LCALL DEL5US
SETB SCL1
LCALL DEL5US
SETB SDA1
LCALL DEL5US
RET
-----应答检查-----
CACK1:
SETB SDA1
LCALL DEL5US
SETB SCL1
LCALL DEL5US
MOV C,SDA1
JC CACK1
CLR SCL1
CLR SDA1
LCALL DEL1MS
RET
-----应答-----
MACK1:
CLR SDA1
LCALL DEL5US
SETB SCL1
LCALL DEL5US
CLR SCL1
LCALL DEL5US
SETB SDA1
RET
入口:传递的地址在POINTER,数据在WR_BUF中,发送字节数在N中
资源占用:ACC、R0、R1、R3、C
WR_NB1:
CLR EA
SETB SDA1
SETB SCL1
LCALL START1
MOV A,#0A2H
LCALL WR8BIT1
LCALL CACK1
MOV A,POINTER
LCALL WR8BIT1
LCALL CACK1
MOV R3,N
MOV R1,#WR_BUF
WRNB11:
MOV A,@R1
LCALL WR8BIT1
LCALL CACK1
INC R1
DJNZ R3,WRNB11
LCALL STOP1
LCALL DEL10MS
SETB EA
RET
-----从从器件指定单元读N个字节数据-----
入口:传递的地址在POINTER,接收数据缓冲区RD_BUF,接收字节数在N中
资源占用:ACC、R0、R1、R3、C
RD_NB1:
MOV R3,N
RDNB11:
LCALL START1
MOV A,#0A2H
LCALL WR8BIT1
LCALL CACK1
MOV A,POINTER
LCALL WR8BIT1
LCALL CACK1
LCALL START1
MOV A,#0A3H#0A1H
LCALL WR8BIT1
LCALL CACK1
MOV R1,#RD_BUF
RDB1: LCALL RD8BIT1
MOV @R1,A
DJNZ R3,SACK1
LCALL STOP1
RET
SACK1:INC R1
LCALL MACK1
SJMP RDB1
-----字节发送-----
入口:要发送的数据在ACC中
每发送完一个字节,要调用一次CACK,以判断是否有应答
WR8BIT1:
PUSH ACC
MOV R0,#08H
WR_BIT1:
RLC A
MOV SDA1,C
LCALL DEL5US
SETB SCL1
LCALL DEL5US
CLR SCL1
DJNZ R0,WR_BIT1
POP ACC
RET
-----字节接收-----
出口:接收到的数据在ACC中
每接收完一个字节,要调用一MCACK/MNACK
RD8BIT1:
MOV R0,#08H
RD_BIT1:
SETB SDA1
LCALL DEL5US
SETB SCL1
LCALL DEL5US
MOV C,SDA1
RLC A
LCALL DEL5US
CLR SCL1
DJNZ R0,RD_BIT1
CLR SDA1
RET
以下的程序是C语言的程序,用于读24C01存贮器,稍加修改可以用于所有的I2C总线驱动。
/******************************************************************
** 名 称:ReadIIC_24C01
** 功 能:读24c01指定的地址的数据
** 输 入: address 24c01的地址
** 输 出: ddata 读出的数据
** 全局变量: 无
** 调用模块: write_8bit()delay()
** 备注:
******************************************************************/
uint8 ReadIIC_24C01(uint8 data address)
{
uint8 data ddata=0
uint8 data i=8
_nop_()
_nop_()
_nop_()
EA=0
SCL=1
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_() //Tsu:STA
SDA=0
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()//Thd:STA
SCL=0//START
write_8bit( (address<<1) | 0x01) //写页地址和 *** 作方式
ACK_R()
while (i--)
{
SDA=1
ddata<<=1
SCL=0
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
SCL=1
if (SDA) ddata|=0x01
}
SCL=0
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
SCL=1
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
SDA=0
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
SCL=1
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
SDA=1 //STOP
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
EA=1
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
delay(50)
_nop_()
_nop_()
_nop_()
return ddata
}
/******************************************************************
** 名 称:WriteIIC_24C01
** 功 能:将数据写入24c01指定地址
** 输 入: address 24c01的地址
** ddata 待写入的数据
** 输 出: 无
** 全局变量: 无
** 调用模块: write_8bit()delay()
** 备注:
******************************************************************/
void WriteIIC_24C01(uint8 data address,uint8 data ddata)
{
_nop_()
_nop_()
_nop_()
EA=0
SCL=1
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_() //Tsu:STA
SDA=0
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()//Thd:STA
SCL=0//START
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
write_8bit( (address<<1) &0xfe) //写页地址和 *** 作方式,对于24C32-24C256,page不起作用
ACK_R()
write_8bit(ddata) //发送数据
ACK_R()
SDA=0
_nop_()
_nop_()
_nop_()
SCL=1
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
SDA=1 //STOP
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
EA=1
_nop_()
_nop_()
_nop_()
delay(50)
_nop_()
_nop_()
_nop_()
}
/******************************************************************
** 名 称:write_8bit
** 功 能:将一个字节数据写入24c01
** 输 入: 无
** 输 出: 无
** 全局变量: 无
** 调用模块: 无
** 备注:
******************************************************************/
void write_8bit(uint8 data ch)
{
uint8 data i=8
_nop_()
_nop_()
_nop_()
SCL=0
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
while (i--)
{
SDA=(bit)(ch&0x80)
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
ch<<=1
SCL=1
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
SCL=0
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
}
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
}
/******************************************************************
** 名 称:ACK_R
** 功 能:等待24c01ACK信号
** 输 入: 无
** 输 出: 无
** 全局变量: 无
** 调用模块: 无
** 备注:
******************************************************************/
void ACK_R(void)
{
_nop_()
_nop_()
_nop_()
SDA=1
SCL=0
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
SCL=1
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
while(SDA)
{
_nop_()
} //ACK
SCL=0
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
_nop_()
}
第二种写法是对的I2C开始时序(START)的定义为,SCL为高的时候,SDA由高转为低。可以理解为,初始状态即为SDA、SCL均为高。故在SDA SCL的初始状态加delay没有意义
I2C总线协议规定:,在SCL保持高电平期间,SDA上的电平出现负跳变,定义为I2C总线的启动信号,它标志着一次数据传输的开始for(i=0i<8i++) //传输8位数据
{
scl=1//串行时钟信号线高电平有效
delay() //延时
k=(k<<1)|sda;//每传输一位后,向左移1位,传输下一位数据。至于为什么或SDA,应该不会这么写吧,具体问题中是不同
}
以上只是个人观点
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)