各位前辈,我用两个IO口模拟I2C主模式,现在调试程序的时候发现,从器件用ICD2单步运行有应答,全速运行没有应答。百思不得其解,麻烦各位能不能帮我看一下,是我的输入输出方向不正确,还是程序的时序有问题,谢谢各位了。
//--------------------------------------------------------------------------//
//--------------- 软件模拟I2C通信 ----------------//
//--------------- ----------------//
//--------------- ----------------//
//--------------------------------------------------------------------------//
#include"pic.h"
CONFIG1 = 0X1CF5;
CONFIG2 = 0XFFCF;
#define uchar unsigned char
#define SCL RC5
#define SDA RB1
#define TRIS_SDA TRISB1
uchar I2C_Count,i;
bit ACK; //应答标记
void I2C_Delay(); //I2C延迟,用于波形建立
void I2C_Start(); //产生I2C起始位
void I2C_Stop(); //产生I2C结束位
void I2C_Restart(); //产生I2C重复起始位
void I2C_DataOut(uchar data); //主器件发送数据
void I2C_AckOut(); //主器件发送应答
void I2C_NoAckOut(); //主器件发送非应答
void I2C_Error(); //I2C错误处理程序
void I2C_Init(); //I2C初始化
void I2C_Write(uchar IC_addr,uchar addr,uchar data ); //主器件向地址为IC_addr的从器件的addr地址处存入data
uchar I2C_DataIn(); //读数据,发送应答位
uchar I2C_8BitsIn(); //接收8位数据
uchar I2C_DataLastIn(); //读数据,发送非应答位
uchar I2C_Read(uchar IC_addr,uchar addr); //主器件8位读IC_addr的从器件的addr地址,返回数据
void Initialize_CPU();
void I2C_Delay()
{
uchar i;
for(i=0;i<3;i++);
}
void I2C_Init() //I2C初始化
{
ANSELB = 0X00;
TRISC = 0x00; //SDA、SCL设为输出
TRISB = 0x00;
PORTC = 0X00;
PORTB = 0X00;
}
void I2C_Start() //I2C起始位
{
SDA = 1;
I2C_Delay();
SCL = 1;
I2C_Delay();
SDA = 0;
I2C_Delay();
SCL = 0;
I2C_Delay();
}
void I2C_Stop() //I2C停止位
{
SDA = 0;
I2C_Delay();
SCL = 1;
I2C_Delay();
SDA = 1;
I2C_Delay();
}
void I2C_Restart() //I2C重复起始位
{
SCL = 0;
I2C_Delay();
SDA = 1;
I2C_Delay();
SCL = 1;
I2C_Delay();
SDA = 0;
I2C_Delay();
SCL = 0;
I2C_Delay();
}
void I2C_Error() //I2C错误处理
{
I2C_Stop();
return;
}
void I2C_DataOut(uchar data) //I2C主器件对从器件发送1个字节
{
uchar i;
for(i=0;i<8;i++)
{
if(data&0x80) //高字节在前
SDA = 1;
else
SDA = 0;
I2C_Delay();
SCL = 1; //产生时钟波形
I2C_Delay();
SCL = 0;
data = data<<1;
}
I2C_Delay();
SDA = 1; //释放总线
TRIS_SDA = 1; //SDA设置为输入,准备检测从器件应答
I2C_Delay();
SCL = 1; //发送第九个时钟信号,从器件产生应答
I2C_Delay();
I2C_Count = 5;
while(--I2C_Count)
{
if(SDA==0)
{
ACK = 1; //SDA==1,无应答,ACK=0
break;
}
else ACK = 0; //SDA==0,有应答,ACK=1
}
SCL = 0; //时钟信号结束
TRIS_SDA = 0; //重新设置SDA为输出
I2C_Delay();
}
uchar I2C_DataIn() //I2C从从器件接收一个字节,并发送一个应答位,表明进行连续读操作
{
uchar buff;
SDA = 1; //释放总线
buff = I2C_8BitsIn(); //SDA开始接收一个8位数据
I2C_AckOut(); //发送应答位
return buff; //返回接收值
}
uchar I2C_DataLastIn() //I2C从从器件接收一个字节,并发送一个非应答位,表明读操作结束
{
uchar buff;
SDA = 1; //释放总线
buff = I2C_8BitsIn(); //SDA开始接收一个8位数据
I2C_NoAckOut(); //发送非应答位
return buff; //返回接收值
}
void I2C_AckOut() //主器件发送应答
{
SDA = 0;
I2C_Delay();
SCL = 1;
I2C_Delay();
SCL = 0;
I2C_Delay();
}
void I2C_NoAckOut() //主器件发送非应答
{
SDA = 1;
I2C_Delay();
SCL = 1;
I2C_Delay();
SCL = 0;
I2C_Delay();
}
uchar I2C_8BitsIn() //主器件从总线上读8位数据
{
TRIS_SDA = 1;
uchar i,buff = 0x00;
for(i=0;i<8;i++)
{
I2C_Delay();
SCL = 0;
I2C_Delay();
SCL = 1; //产生时钟信号高电平,开始接收数据
I2C_Delay();
if(SDA==1) buff = buff + 0X01; //接收数值判断
I2C_Delay();
buff = buff<<1;
}
SCL = 0; //接收完毕
TRIS_SDA = 0; //接收完毕,SDA重新设置为输出
I2C_Delay();
return buff; //返回接收到的数据
}
//-----------------------------------------------------------------------------------//
//----------------- 向I2C目标器件,目标地址,写入一个数据 ------------------------//
//----------------- IC_addr : 目标I2C器件地址 ------------------------//
//----------------- addr : I2C器件中数据存储地址 ------------------------//
//----------------- data : I2C器件中存入数据 ------------------------//
//-----------------------------------------------------------------------------------//
void I2C_Write(uchar IC_addr,uchar addr,uchar data)
{
I2C_Start(); //发送起始位
I2C_DataOut(IC_addr&0xfe); //发送I2C数据寻址命令
if(ACK==0) I2C_Error();
I2C_DataOut(addr); //发送器件内部数据保存目标地址
if(ACK==0) I2C_Error();
I2C_DataOut(data); //发送写数据
if(ACK==0) I2C_Error();
I2C_Stop(); //发送停止位
while(1) //判断器件擦写完毕
{
I2C_Start(); //产生起始位
I2C_DataOut(IC_addr&0xfe); //写入器件地址
I2C_Stop(); //产生停止位
if(ACK==1) break; //如果有应答,表示器件擦写完成,写操作完成
}
}
//-----------------------------------------------------------------------------------//
//----------------- 读取I2C器件目标地址一个数据 ------------------------//
//----------------- IC_addr : 目标I2C器件地址 ------------------------//
//----------------- addr : I2C器件中数据存储地址 ------------------------//
//----------------- Read_data : 返回读到的数据 ------------------------//
//-----------------------------------------------------------------------------------//
uchar I2C_Read(uchar IC_addr,uchar addr)
{
uchar Read_data;
I2C_Start(); //发送起始位
I2C_DataOut(IC_addr&0xfe); //发送寻址命令
if(ACK==0) I2C_Error();
I2C_DataOut(addr); //发送读地址
if(ACK==0) I2C_Error();
I2C_Restart();
I2C_DataOut(IC_addr|0x01); //寻址码和写命令
if(ACK==0) I2C_Error();
Read_data = I2C_DataLastIn(); //接收8位数据
I2C_Stop(); //发送停止位
return Read_data;
}
void Initialize_CPU()
{
OSCCON = 0x1F; //设置晶振
}
//----------------------------- 主函数 ------------------------------------------//
void main()
{
Initialize_CPU();
I2C_Init();
I2C_Write(0xA0,0x00,0xfe);
i = I2C_Read(0xA0,0x00);
while(1)
{;}
} |