打印

I2C从器件用ICD2单步运行有应答,全速运行没有应答

[复制链接]
3148|6
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
nqyijian|  楼主 | 2010-12-17 19:05 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
各位前辈,我用两个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)
    {;}
}
沙发
nqyijian|  楼主 | 2010-12-17 21:33 | 只看该作者
谁能救救我啊,在检测应答信号我设置断点,全速运行到断点处端口显示高电平,我再单步运行一步,端口马上显示低电平.....

使用特权

评论回复
板凳
zhaoyu2005| | 2010-12-18 09:13 | 只看该作者
烧到片子里看下对不,另外就是根据时钟频率,计算I2C速率,看满足要求不

使用特权

评论回复
地板
梅开二度| | 2010-12-19 21:13 | 只看该作者
用示波器看时序可解决。

使用特权

评论回复
5
yewuyi| | 2010-12-20 09:11 | 只看该作者
这可能是你检测应答的方式和时机不对造成的,请详细阅读IIC的协议手册,如果怕麻烦,可以只看对应IIC器件的手册确认。

使用特权

评论回复
6
hotpower| | 2011-1-4 10:58 | 只看该作者
主机IO模拟还行,从机还是用硬件模块好。
俺是菜鸟,学习学习

使用特权

评论回复
7
chengqing3968| | 2013-9-17 15:11 | 只看该作者
hotpower 发表于 2011-1-4 10:58
主机IO模拟还行,从机还是用硬件模块好。
俺是菜鸟,学习学习

敢问主机怎么模拟……求指导!谢谢

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

75

主题

539

帖子

1

粉丝