原创 完成lpc22xx 的I2C多字节子地址问题

2008-11-14 11:54 3191 2 2 分类: MCU/ 嵌入式

lpc221x在其开发板上带的源码里面是不支持2bytes的子地址,只有单字节,所以是不能接像AT24C256 多字节子地址的器件,必顺跟据I2C的状态表来修改中断程序和传输函数.


第一步,修改中断函数:原函数如下,


/****************************************************************************
* 名称:IRQ_I2C()
* 功能:I2C中断,通过判断I2C状态字进行相应的操作。
* 入口参数:无
* 出口参数:无
****************************************************************************/
void  __irq  IRQ_I2C(void)
{  uint8  sta;


   sta = I2STAT;                    // 读出I2C状态字
   switch(sta)
   {  case  0x08:                   // 己发送起始条件
            if(1==I2C_suba_en) I2DAT = I2C_sla&0xFE; // 指定子地址读时,先写入地址
              else I2DAT = I2C_sla;                     // 否则直接发送从机地址
            I2CONCLR = 0x28;        // SI="0"
            break;
           
      case  0x10:
            I2DAT = I2C_sla;        // 重启动总线后,发送从地址
            I2CONCLR = 0x28;        // SI="0"
            break;
  
      case  0x18:                   // 已发送SLA+W,并已接收应答
            if(0==I2C_suba_en)      // 无子地址,则直接发送数据
            {  if(I2C_num>0)
               {  I2DAT = *I2C_buf++;
                  I2CONCLR = 0x28;
                  I2C_num--;
               }
               else
               {  I2CONSET = 0x10;  // 无数据发送,结束总线
                  I2CONCLR = 0x28;
                  I2C_end = 1;      // 设置总线操作结束标志
               }
               break;
            }
            if(1==I2C_suba_en)      // 发送子地址
            {  I2DAT = I2C_suba;
               I2CONCLR = 0x28;
            }
            if(2==I2C_suba_en)
            {  I2DAT = I2C_suba;
               I2CONCLR = 0x28;
               I2C_suba_en = 0;     // 子地址己处理
            }
            break;
           
      case  0x28:                   // 已发送I2C数据,并接收到应答
            if(0==I2C_suba_en)      // 无子地址,则直接发送数据
            {  if(I2C_num>0)
               {  I2DAT = *I2C_buf++;
                  I2CONCLR = 0x28;
                  I2C_num--;
               }
               else
               {  I2CONSET = 0x10;  // 无数据发送,结束总线
                  I2CONCLR = 0x28;
                  I2C_end = 1;
               }
               break;
            }
            if(1==I2C_suba_en)      // 若是指定地址读,则重新启动总线
            {  I2CONSET = 0x20;
               I2CONCLR = 0x08;
               I2C_suba_en = 0;     // 子地址己处理
            }
            break;
  
  
      case  0x20:
      case  0x30:
      case  0x38:
            I2CONCLR = 0x28;        // 总线进入不可寻址从模式
            I2C_end = 0xFF;         // 总线出错,设置标志
            break;
  
  
      case  0x40:                   // 己发送SLA+R,并已接收到应答
            if(1==I2C_num)          // 最后一字节,接收数据后发送非应答信号
            {  I2CONCLR = 0x2C;     // AA="0",接收到数据后产生非应答
            }
            else                    // 接收数据并发送应答信号
            {  I2CONSET = 0x04;     // AA="1",接收到数据后产生应答
               I2CONCLR = 0x28;
            }
            break;
           
      case  0x50:
            *I2C_buf++ = I2DAT;     // 读取数据
            I2C_num--;
            if(1==I2C_num)
            {  I2CONCLR = 0x2C;     // AA="0",接收到数据后产生非应答
            }
            else
            {  I2CONSET = 0x04;     // AA="1",接收到数据后产生应答
               I2CONCLR = 0x28;
            }
            break;
     
      case  0x58:
            *I2C_buf++ = I2DAT;     // 读取最后一字节数据
            I2CONSET = 0x10;        // 结束总线
            I2CONCLR = 0x28;
            I2C_end = 1;
            break;
     
      case  0x48:
            I2CONCLR = 0x28;        // 总线进入不可寻址从模式
            I2C_end = 0xFF;
            break;
           
      default:
            break;
   }
  


   VICVectAddr = 0x00;              // 中断处理结束
}


状态的意义详情请参考“80C51系列派生器件8XC552/562概述”数据手册中的表4,数据手册可通过下面的地址从网上下载:http://www.semiconductors.philips.com/acrobat/various/8XC552_562OVERVIEW_2.pdf


其中case  0x08:  的状态是A START condition has been transmitted 接下发送子地址,因此,if(1==I2C_suba_en) I2DAT = I2C_sla&0xFE; // 指定子地址读时,先写入地址
              else I2DAT = I2C_sla;                     // 否则直接发送从机地址
            I2CONCLR = 0x28;        // SI="0"
            break;
要改成,


         if(I2C_suba_en != 0)


                {I2DAT = I2C_sla&0xFE; // 指定子地址读时,先写入地址


                  I2C_suba_en--;}
              else I2DAT = I2C_sla;                     // 否则直接发送从机地址
            I2CONCLR = 0x28;        // SI="0"
            break;


这样可以在读重启动之前写入子地址,接下来就会进入case 18


 case  0x18:                   // 已发送SLA+W,并已接收应答
            if(0==I2C_suba_en)      // 无子地址,则直接发送数据
            {  if(I2C_num>0)
               {  I2DAT = *I2C_buf++;
                  I2CONCLR = 0x28;
                  I2C_num--;
                  }
               else
               {  I2CONSET = 0x10;  // 无数据发送,结束总线
                  I2CONCLR = 0x28;
                  I2C_end = 1;      // 设置总线操作结束标志
                  }
               break;
            }
            if(I2C_suba_en!= 0)      // 发送子地址
            {  I2DAT = I2C_suba[I2C_suba_en];


               I2C_suba_en--;
               I2CONCLR = 0x28;
            }
            break;
因此还需要全局建立一个子地址数组,高位在高下标


接下进入case 0x10 发送读与器件地址,这里不用改,


再进入case 50  收数据,这里也不用改,


再进入case 58 收完最后结束
以上是读取数据,另外写数据不用变,在case 18里面可以接着地址写。


到此中断改造完毕,


其它函数如  uint8  ISendStr(uint8 sla, uint8 suba, uint8 *s, uint8 no)


双字节地址改成 uint8  ISendStr(uint8 sla, uint16 xsuba, uint8 *s, uint8 no)


这里需要把xsuba付给全局建立一个子地址数组。

PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
我要评论
0
2
关闭 站长推荐上一条 /3 下一条