永远的追求--freefish笔记 https://bbs.21ic.com/?53166 [收藏] [复制] [RSS]

日志

LF2407的IIC通讯

已有 1066 次阅读2006-1-16 15:40

LF2407没有IIC接口,对于微机继电保护来说,使用IIC的EEPROM芯片存放整定值最方便,与MCU接口只有两根线,而且只在初始化时读入就可以.既然没有就用IO口线模拟一个出来.以下程序参考了刘和平老师的书,但是书中的例子有些小错误不能用,我按照IIC协议修改了两天,运行通过,操作24C16完全正确.


注意这是在CCS仿真环境下的模拟,烧到FLASH前请把延时时间放大5-8倍,否则时序无法配合.口线号:IOPC0为SCL,IOPC2作为SDA,2407内有弱上拉,可以省略上拉电阻.


/************************IIC BUS ,OPREATe at 100kHz*/
void  I2CStart()                         /*I2C启动*/
{
   int  k; 
   PCDATDIR = PCDATDIR & 0xFFFE;            /* (IOPC0)SCL=0 */
   PCDATDIR = PCDATDIR | 0x0202;            /* (IOPC1)SDA为输出1 */
   for (k = 17;k >= 0;k--) { }              /* 软件延时5.1us */
   PCDATDIR = PCDATDIR | 0x0003;             /* SDA=SCL=1 */ 
   for (k = 8;k >= 0;k--) { }                /* 软件延时2.55us */ 
   PCDATDIR = PCDATDIR & 0x0FFFD;             /* (IOPC1)SDA=0 */
   for (k = 8;k >= 0;k--) { }                 /* 软件延时2.55us */ 
      PCDATDIR = PCDATDIR & 0x0FFFE;             /* (IOPC0)SCL=0  */  
}



void  I2CSendByte(int  data)                      /* 向I2C总线写入数据子程序  */   
{
 int   flag,sz,k;                           /* 定义局部寄存器   */
  PCDATDIR = PCDATDIR | 0x0200;                  /* (IOPC1)SDA为输出0 */
  for (flag = 0x0080;flag != 0x00; flag = flag/2)
  {
    PCDATDIR = PCDATDIR & 0x0FFFE;              /* (IOPC0)SCL=0 */
    for (k = 8;k >= 0;k--) { }                   /* 软件延时2.55us */ 
    sz = data & flag;                       /* 屏蔽掉相应的位 */
    if (sz == 0) PCDATDIR = PCDATDIR & 0x0FFFD;  /* 如果相应的位为0,则(IOPC1)SDA=0*/
    else  PCDATDIR = PCDATDIR | 0x0002;          /* 如果相应的位为1,则(IOPC1)SDA=1 */
    for (k = 8;k >= 0;k--) { }                   /* 软件延时2.55us */
    PCDATDIR = PCDATDIR | 0x0001;                 /* (IOPC0)SCL=1,在SCL=1期间数据线上的状态必须保持不变 */
    for (k = 17;k >= 0;k--)  {  }                 /* 软件延时5.1us */
  }
  PCDATDIR = PCDATDIR & 0x0FFFE;                /* (IOPC0)SCL=0 */
}



int I2CRECACK()   /*检查应答位子程序 */
{
 int  k;
   PCDATDIR = PCDATDIR & 0x0FFFE;      /* SCL=0*/
   for (k = 17; k >= 0; k--) {   }   /* 软件延时5.1us*/
   PCDATDIR=PCDATDIR | 0x0001;        /* SCL=1,在SCL=1期间数据线上的状态必须保持不变*/
   for (k = 8; k >= 0; k--) {   }      /* 软件延时2.55us*/
   PCDATDIR = PCDATDIR & 0x0FDFF;      /* IOPC0(SDA为输入)*/
   for (k = 1; k >= 0; k--) {   }      /* 软件延时600ns */
   for (k = 6; k >= 0; k--) {   }      /* 软件延时1.95us */
   PCDATDIR = PCDATDIR & 0x0FFFE;      /* SCL=0*/
   k = PCDATDIR & 0x0002;            /* k值存储应答位,若K=0,则表示操作成功 若k=1,则表示操作失败*/ 
   return ( k );
}



int I2CRecByte()                                   /* 从I2C总线读取数据*/
{
  int   k = 0;
  int   flag;
  int   sz;
  int   rev = 0;
  PCDATDIR = PCDATDIR & 0xFDFF;                   /* IOPC1(SDA为输入)*/
  PCDATDIR = PCDATDIR & 0xFFFE;                   /* SCL=0 */
  for (flag = 0x0080;flag != 0x0000;flag = flag/2)
   {
    for (k = 17; k >= 0; k--) {    }             /* 软件延时5.1us*/
    PCDATDIR = PCDATDIR | 0x0001;                  /* SCL=1 */
    for (k = 8; k >= 0; k--) {    }             /* 软件延时2.55us*/
    sz = PCDATDIR & 0x0002;                      /* 取得应该读取的相应位 */
    if (sz == 0x0002)  rev = rev | flag;          /* 若读取的相应位为1,则rev值的相应位置1 */
    for (k = 8; k >= 0; k--) {    }             /* 软件延时2.55us*/
    PCDATDIR = PCDATDIR & 0xFFFE;                  /* SCL=0 */
   }
  return(rev);
}



void  I2CAck()                        /* 对I2C总线产生应答*/
{
  int k;
  PCDATDIR = PCDATDIR & 0x0FFFE;     /* SCL=0 */
  for (k = 8; k >= 0; k--) {k=k;}  /* 软件延时2.55us*/
  PCDATDIR = PCDATDIR | 0x0200;      /* 设置(IOPC1)SDA为输出*/
  PCDATDIR = PCDATDIR & 0x0FFFD;    /* SDA=0 */
  for (k = 8; k >= 0; k--) {k=k;}  /* 软件延时2.55us*/
  PCDATDIR = PCDATDIR | 0x0001;      /* SCL=1 */
  for (k = 17; k >= 0; k--) {    }  /* 软件延时5.1us*/
  PCDATDIR = PCDATDIR & 0x0FFFE;    /* SCL=0 */
}


 
void  I2CNoAck()                    /* 不对I2C总线产生应答*/
{
  int k;
  PCDATDIR = PCDATDIR & 0x0FFFE;  /* SCL=0 */
  for (k = 8;k > 0;k--) {  }      /* 软件延时2.55us */
  PCDATDIR = PCDATDIR | 0x0100;    /* 设置(IOPC1)SDA为输出口 */
  PCDATDIR = PCDATDIR | 0x0002;    /* SDA=1 */
  for (k = 8;k > 0;k--) {  }      /* 软件延时2.55us */
  PCDATDIR = PCDATDIR | 0x0001;    /* SCL=1 */
  for (k = 17;k > 0;k--){  }      /* 软件延时5.1us*/
  PCDATDIR = PCDATDIR & 0x0FFFE;  /* SCL=0 */
}



void  I2CStop()                        /* 停止I2C总线 */
{
  int k;
  PCDATDIR = PCDATDIR & 0x0FFFE;     /* (IOPC0)SCL=0 */
  for (k = 8;k > 0;k--) {  }         /* 软件延时2.55us */
  PCDATDIR = PCDATDIR | 0x0200;       /* 设置(IOPC1)SDA为输出口 */
  PCDATDIR = PCDATDIR & 0x0FFFD;     /* SDA=0 */ 
  for (k = 8;k > 0;k--) {  }         /* 软件延时2.55us */
  PCDATDIR = PCDATDIR | 0x0001;       /* SCL=1 */ 
  for (k = 17;k > 0;k--){  }         /* 软件延时5.1us */
  PCDATDIR = PCDATDIR | 0x0002;       /* (IOPC1)SDA=1 */
  for (k = 17;k > 0;k--){  }         /* 软件延时5.1us*/
  PCDATDIR = PCDATDIR & 0X0FFFE;     /* SCL=0 */
}


 
int read(array,adress,control,n)  /* 读数据子程序*/
    int *array,adress,control,n;
{
 int dat,buf;
  I2CStart();               /* 设置I2C总线的开始状态 */
  buf = control & 0xFFFE;
  I2CSendByte(buf);            /* 送出控制字节(R/W=0) */
  dat=I2CRECACK();           /* 检查应答位*/
  I2CSendByte(adress);        /* 送出地址字节 */
  dat=I2CRECACK();           /* 检查应答位*/
  I2CStart();               /* 再设置I2C总线的开始状态 */
  I2CSendByte(control);        /* 送出控制字节(R/W=1) */
  dat=I2CRECACK();           /* 检查应答位*/
  if (dat == 0)
  {
    for (;n != 1;n--) 
    {
      int i;
      dat = I2CRecByte();        /* 读取一个字节的数据 */
      I2CAck();               /* 产生应答信号 */
      i = (dat<<8) & 0xFF00;      /* 移到高8位 */
      dat = I2CRecByte();       /* 读取一个字节的数据 */
      I2CAck();               /* 产生应答信号 */
      dat =  dat &  0x00FF;
      dat = dat | i;
      *array = dat;            /* 把读取的数据存入数组 */
      array++;
    }
    dat=I2CRecByte();          /* 接收最后一个高字节的数据 */
    I2CAck();                 /* 产生应答信号 */
    *array  = (dat<<8) & 0xFF00;
    dat=I2CRecByte();          /* 接收最后一个字节的数据 */
    I2CNoAck();               /* 不产生应答信号 */
    dat = dat & 0x00FF;
    *array = *array | dat;     /* 把读取的数据存入数组 */
    dat = 0x00;              /* dat值赋0,表示前面的操作成功 */
  }
  return(dat);
}


int write(array,adress,control,n)    /* 写数据子程序,不超过8个字*/
   int *array,adress,control,n;
{
  int dat,buf;
  PCDATDIR = PCDATDIR & 0xFFDF;     /* 写操作开始,打开写保护:(IOPC5)WP=0 */
  I2CStart();
  dat = control;
  I2CSendByte(dat);               /* 送出控制字节(R/W=0) */
  dat = I2CRECACK();
  I2CSendByte(adress);           /* 送出地址字节 */
  dat = I2CRECACK();
  if ( dat == 0)
  {
   for(;n != 0;n--,array++) 
    { 
      buf = (*array);
      buf = (buf & 0xFF00) >> 8;
      I2CSendByte(buf);            /* 写出一个字节数据 */
      dat = I2CRECACK();
      if(dat == 1) break;        /* 如果无应答位,则写数据失败,终止写操作 */
      buf = *array;
      buf = buf & 0x00FF;   
      I2CSendByte(buf);            /* 写出一个字节数据 */
      dat = I2CRECACK();
      if(dat == 1) break;        /* 如果无应答位,则写数据失败,终止写操作 */
    }
  }
  PCDATDIR = PCDATDIR | 0x0020;      /* 写操作完成,设置写保护:(IOPC5)WP=1 */
  return(dat);
}



/* 通用读写24C16子程序,入口参数为输入/输出缓冲区首地址array,*/
/* 24LC256的块内地址adress,控制字节control,需要读写的字数n */
int EEPROM(array,adress,control,n)
    int    *array,adress,control,n;  
{
  int  dat;
 dat = control & 0x0001;
 switch (dat)  
 {
   case 1 :
   {
     dat = read(array,adress,control,n);    /* 调用读数据子程序 */
     break; 
   }
   case 0 :
   {
     dat = write(array,adress,control,n);   /* 调用写数据子程序*/
     break;
   }     
  }  
   I2CStop();                                /* 停止IIC总线*/
   return(dat);                        /* 返回一个状态字,为0表示操作是否成功 */
}


路过

鸡蛋

鲜花

握手

雷人

发表评论 评论 (1 个评论)

hz 2006-6-1 14:11

8错

8错