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

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;              // 中断处理结束
}

 

I2C master主要状态解析
1 ,写,
  发送起始位-->x08-->发设备地址和写标志--->0x18--->发送第一个数据-->0x28-->结束

2,读
  发送送起始位-->x08-->发设备地址和写标志--->0x40-->收第一个数据-->0x50-->data-->0x58

状态的意义详情请参考“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_sla&0x01 == 1)&&(I2C_suba_en!=0)){I2DAT = I2C_sla&0xFE;}
            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;
            }
     else      // 发送子地址
            {  I2DAT = I2C_suba[I2C_suba_en-1];
               I2C_suba_en--;
               I2CONCLR = 0x28;
            }
            break;

其中CASE   0x28 发送其它地址位,发完后重启再到读的命令,所以改成如下   

      case  0x28:  // 已发送I2C数据,并接收到应答
            if((I2C_suba_en==0) && (I2C_sla & 0x1)==1 )     // 若是指定地址读,则重新启动总线
             { I2CONSET = 0x20;
               I2CONCLR = 0x08;     // 子地址己处理
             }
            if((0==I2C_suba_en)&& (I2C_sla & 0x1)==0 )   // 无子地址,则直接发送数据
            {  if(I2C_num>0)
               {  I2DAT = *I2C_buf++;
                  I2CONCLR = 0x28;
                  I2C_num--;
               }
               else
               {  I2CONSET = 0x10;  // 无数据发送,结束总线
                  I2CONCLR = 0x28;
                  I2C_end = 1;
               }
              }
   if(0!=I2C_suba_en)
     {I2DAT = I2C_suba[I2C_suba_en-1];
               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付给全局建立一个子地址数组。

 

另外全局变量要改成如下部分

volatile uint8  I2C_sla;           // 从机地址(即器件地址) && msb 读操作时请设置为1,写操作时请设置为0
volatile uint8  I2C_suba[4];       // 子地址
volatile uint8  *I2C_buf;          // 数据缓冲区指针 (读操作时会被更改)
volatile uint8  I2C_num;           // 操作数据个数 (会被更改)
volatile uint8  I2C_end;           // 操作结束标志,为1时表示操作结束,为0xFF时表示操作失败 (会被设置)
volatile uint8  I2C_suba_en;       // 子地址个数,当个数=0 为没子地址(会被更改)

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值