由于项目需求,需要用到I2C,但SH79F084A没有I2C功能,只能通过使用IO口去模拟I2C,P3_2为SDA,P3_3为SCL,但是写完之后,测试读写数据没有任何反应,引脚也没有变化。下面贴上作为I2C主机模式的代码,请帮忙检查哪里需要更改的,望大神们指点一二,谢谢。
#include <SH79F084A.H>
#include "intrins.h"
#include "datatype.h"
#include "delay.h"
sbit SDA = P3^2; //IIC总线串行数据线
sbit SCL = P3^3; //IIC总线串行时钟线
U8 AckFlag;/*应答标志位*/
void I2C_Delay(void)
{
_nop_();
_nop_();
_nop_();
_nop_();
_nop_(); // >=4.7uS
}
void I2C_SDA_IO(U8 input)
{
if(input == 1)//SDA输出,p3.2
{
SETBIT(P3M0, 2);
SETBIT(P3M1, 2);
}
else//SDA输入,p3.2
{
SETBIT(P3M0, 2);
CLRBIT(P3M1, 2);
}
}
void I2C_SCL_IO(U8 input)
{
if(input == 1)//SCL输出,P3.3
{
SETBIT(P3M0, 3);
SETBIT(P3M1, 3);
}
else//SCL输入,P3.3
{
SETBIT(P3M0, 3);
CLRBIT(P3M1, 3);
}
}
void Init_I2C(void)
{
I2C_SDA_IO(OUT);
I2C_SCL_IO(OUT);
SDA = 1;
_nop_();
SCL = 1;
_nop_();
}
//---------------------------------------------------------------
// SW I2C: start signal.
// <comment>
// SDA _____
// \____________
// SCL ________
// \_________
//
// Return value: None
//---------------------------------------------------------------
void I2C_Start(void)
{
SDA = 1; /*发送起始条件的数据信号*/
_nop_();
SCL = 1;
I2C_Delay();
SDA = 0; /*发送起始信号*/
I2C_Delay();
SCL = 0; /*钳住I2C总线,准备发送或接收数据 */
_nop_();
_nop_();
}
//---------------------------------------------------------------
// SW I2C: stop signal.
// <comment>
// _________
// SDA __________/
// ____________
// SCL _______/
//---------------------------------------------------------------
void I2C_Stop(void)
{
SDA = 0; /*发送结束条件的数据信号*/
_nop_();
SCL = 1; /*发送结束条件的时钟信号*/
I2C_Delay();
SDA = 1; /*发送I2C总线结束信号*/
I2C_Delay();
}
void I2C_SendAck(void)
{
SCL = 0;
I2C_Delay();
SDA = 0;
I2C_Delay();
SCL = 1;
I2C_Delay();
}
void I2C_SendNoAck(void)
{
SCL = 0;
I2C_Delay();
SDA = 1;
I2C_Delay();
SCL = 1;
I2C_Delay();
}
bit I2C_CheckAck(void)
{
bit tempBit;
SDA = 1;
I2C_Delay();
SCL = 0;
I2C_Delay();
tempBit = SDA;
SCL = 1;
I2C_Delay();
if(tempBit == 1)
{
return 0; //noACK
}
else
{
return 1; //AckFlag
}
}
void Ack_I2c(bit a)
{
if(a == 0)
SDA = 0; /*在此发出应答或非应答信号 */
else
SDA = 1;
_nop_();
_nop_();
SCL = 1;
I2C_Delay();
SCL = 0; /*清时钟线,钳住I2C总线以便继续接收*/
_nop_();
_nop_();
}
/*******************************************************************
字节数据传送函数
函数原型: void I2C_SendByte(U8 Data);
功能: 将数据Data发送出去,可以是地址,也可以是数据,发完后等待应答,并对
此状态位进行操作.(不应答或非应答都使ack=0 假)
发送数据正常,ack=1; AckFlag=0表示被控器无应答或损坏。
********************************************************************/
void I2C_SendByte(U8 Data)
{
U8 BitCount;
for(BitCount = 0; BitCount < 8; BitCount++) /*要传送的数据长度为8位*/
{
if((Data<<BitCount) & 0x80)
SDA = 1; /*判断发送位*/
else
SDA = 0;
_nop_();
SCL = 1; /*置时钟线为高,通知被控器开始接收数据位*/
I2C_Delay();
SCL = 0;
}
_nop_();
_nop_();
SDA = 1; /*8位发送完后释放数据线,准备接收应答位*/
_nop_();
_nop_();
SCL = 1;
_nop_();
_nop_();
if(SDA == 1)
AckFlag = 0;
else
AckFlag = 1; /*判断是否接收到应答信号*/
SCL = 0;
_nop_();
_nop_();
}
/*******************************************************************
字节数据传送函数
函数原型: U8 I2C_RcvByte(void)
功能: 用来接收从器件传来的数据,并判断总线错误(不发应答信号),
发完后请用应答函数。
********************************************************************/
U8 I2C_RcvByte(void)
{
U8 RcvByte = 0;
U8 BitCount;
SDA = 1; /*置数据线为输入方式*/
for(BitCount = 0; BitCount < 8; BitCount++)
{
_nop_();
SCL = 0; /*置时钟线为低,准备接收数据位*/
I2C_Delay();
SCL = 1; /*置时钟线为高使数据线上数据有效*/
_nop_();
_nop_();
RcvByte = RcvByte<<1;
if(SDA == 1)
RcvByte = RcvByte + 1; /*读数据位,接收的数据位放入retc中 */
_nop_();
_nop_();
}
SCL = 0;
_nop_();
_nop_();
return RcvByte;
}
/*******************************************************************
向无子地址器件发送字节数据函数
函数原型: U8 I2C_WriteByte_NoRegister(U8 slaveAddr,U8 Data);
功能: 从启动总线到发送地址,数据,结束总线的全过程,从器件地址slaveAddr。
如果返回1表示操作成功,否则操作有误。
注意: 使用前必须已结束总线。
********************************************************************/
U8 I2C_WriteByte_NoRegister(U8 slaveAddr,U8 Data)
{
I2C_Start(); /*启动总线*/
I2C_SendByte(slaveAddr); /*发送器件地址*/
if(AckFlag == 0)
return 0;
I2C_SendByte(Data); /*发送数据*/
if(AckFlag == 0)
return 0;
I2C_Stop(); /*结束总线*/
return 1;
}
/*******************************************************************
向有子地址器件发送多字节数据函数
函数原型: U8 I2C_WriteBytes(U8 slaveAddr, U8 regAddr, U8 *pData, U8 size);
功能: 从启动总线到发送地址,子地址,数据,结束总线的全过程,
从器件地址slaveAddr,子地址regAddr,发送内容是pData指向的内容,发送size个字节。
如果返回1表示操作成功,否则操作有误。
注意: 使用前必须已结束总线。
********************************************************************/
U8 I2C_WriteBytes(U8 slaveAddr, U8 regAddr, U8 *pData, U8 size)
{
U8 i;
I2C_Start(); /*启动总线*/
I2C_SendByte(slaveAddr); /*发送器件地址*/
if(AckFlag == 0)
return 0;
I2C_SendByte(regAddr); /*发送器件子地址*/
if(AckFlag == 0)
return 0;
for(i = 0; i < size; i++)
{
I2C_SendByte(*pData); /*发送数据*/
if(AckFlag == 0)
return 0;
pData++;
}
I2C_Stop(); /*结束总线*/
return 1;
}
/*******************************************************************
向无子地址器件读字节数据函数
函数原型: U8 I2C_ReadByte_NoRegister(U8 slaveAddr,U8 *pRcvData);
功能: 从启动总线到发送地址,读数据,结束总线的全过程,
从器件地址slaveAddr,返回值在pRcvData。
如果返回1表示操作成功,否则操作有误。
注意: 使用前必须已结束总线。
********************************************************************/
U8 I2C_ReadByte_NoRegister(U8 slaveAddr,U8 *pRcvData)
{
I2C_Start(); /*启动总线*/
I2C_SendByte(slaveAddr+1); /*发送器件地址*/
if(AckFlag == 0)
return 0;
*pRcvData = I2C_RcvByte(); /*读取数据*/
Ack_I2c(1); /*发送非就答位*/
I2C_Stop(); /*结束总线*/
return 1;
}
/*******************************************************************
向有子地址器件读取多字节数据函数
函数原型: U8 I2C_ReadBytes(U8 slaveAddr, U8 regAddr, U8 *pRcvData, U8 size);
功能: 从启动总线到发送地址,子地址,读数据,结束总线的全过程,
从器件地址slaveAddr,子地址regAddr,读出的内容放入pRcvData指向的存储区,读size个字节。
如果返回1表示操作成功,否则操作有误。
注意: 使用前必须已结束总线。
********************************************************************/
U8 I2C_ReadBytes(U8 slaveAddr, U8 regAddr, U8 *pRcvData, U8 size)
{
U8 i;
I2C_Start(); /*启动总线*/
I2C_SendByte(slaveAddr); /*发送器件地址*/
if(AckFlag == 0)
return 0;
I2C_SendByte(regAddr); /*发送器件子地址*/
if(AckFlag == 0)
return 0;
I2C_Start(); /*启动总线*/
I2C_SendByte(slaveAddr+1); /*发送器件地址*/
if(AckFlag == 0)
return 0;
for(i = 0; i < size-1; i++)
{
*pRcvData = I2C_RcvByte(); /*读取数据*/
Ack_I2c(0); /*发送就答位*/
pRcvData++;
}
*pRcvData = I2C_RcvByte();
Ack_I2c(1); /*发送非就答位*/
I2C_Stop(); /*结束总线*/
return 1;
}
|