打印

I2C中断问题

[复制链接]
9105|8
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
yueyinji1989|  楼主 | 2012-10-17 16:26 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 yueyinji1989 于 2012-10-17 16:43 编辑

你们好,我在做I2C中断操作实验的时候遇到些问题,向各位请教。最近问题比较多,希望能谅解。

是这样的。做LPC2138的I2C中断操作的时候,不知道中断操作如何引起和进行下去。例如(源代码在下面):
    在main函数里的ISendStr(CAT24WC02,0x00,data_buf,10);调用这个子函数后,其中的I2CONSET=0x60,引起I2C中断,之后看I2C的中断函数
————————————————————————————————————
uint8  ISendStr(uint8 sla, uint8 suba, uint8 *s, uint8 no)
  {  /* 参数设置 */
  I2C_sla = sla;
  I2C_suba = suba;
  I2C_buf = s;
  I2C_num = no;
  I2C_suba_en = 2;
  I2C_end = 0;
  I2CONCLR = 0x2C;
  I2CONSET = 0x60;             // 设置为主机,并启动总线
  while(0==I2C_end);
  if(1==I2C_end) return(1);
  else return(0);
  }

——————————————————————————————————————
读状态:sta=I2STAT;请问此时的状态是什么?)然后他如何继续进行下去?如何进去到状态 case 0x18 去写数据?当写完之后,再到子函数IRcvStr,再进入中断,此时再读状态吗?又是多少?如何进去到case 0x50 去读出数据?

这些问题是连续的,其实就是硬件如何按程序运行下去,主要是为什么!

能有高人帮我解答吗?谢谢!
——————————————————————————————————————
/************************************************* ***************************
  * 名称: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;              // 中断处理结束
  }

——————————————————————————————————————
全部代码:
/************************************************* ***************************
  * 文件名:I2CINT.C
  * 功能:硬件I2C软件包,利用中断方式操作。
  * 说明:主程序要配置好I2C总线接口(GPIO、总线时钟)
  ************************************************** **************************/
  #include  "config.h"
  /* 以下为I2C操作时所需要的变量,在调用I2C子程序前要设置好这些变量 */
  volatile  uint8  I2C_sla;           // 从机地址
  volatile  uint8  I2C_suba;          // 子地址
  volatile  uint8  *I2C_buf;          // 数据缓冲区指针 (读操作时会被更改)
  volatile  uint8  I2C_num;           // 操作数据个数 (会被更改)
  volatile  uint8  I2C_end;           // 操作结束标志,为1时表示操作结束,为0xFF时表示操作失败 (会被设置)
  volatile  uint8  I2C_suba_en;       // 子地址使能控制,读操作时请设置为1,写操作时请设置为2 (会被更改)
  /************************************************* ***************************
  * 名称:IRQ_I2C()
  * 功能:I2C中断,通过判断I2C状态字进行相应的操作。
  * 入口参数:无
  * 出口参数:无
  ************************************************** **************************/
  void  __irq  IRQ_I2C(void)
  {  uint8  sta;
  sta = I2STAT;                    // 读出I2C状态字
  switch(sta)
  {
       .............
  }
  VICVectAddr = 0x00;              // 中断处理结束
  }
  /************************************************* ***************************
  * 名称:ISendStr()
  * 功能:使用硬件I2C发送数据。
  * 入口参数:无
  * 出口参数:返回值为0时表示出错,为1时表示操作正确。
  * 说明:使用前设置好参数
  ************************************************** **************************/
  uint8  ISendStr(uint8 sla, uint8 suba, uint8 *s, uint8 no)
  {  /* 参数设置 */
  I2C_sla = sla;
  I2C_suba = suba;
  I2C_buf = s;
  I2C_num = no;
  I2C_suba_en = 2;
  I2C_end = 0;
  I2CONCLR = 0x2C;
  I2CONSET = 0x60;             // 设置为主机,并启动总线
  while(0==I2C_end);
  if(1==I2C_end) return(1);
  else return(0);
  }
  /************************************************* ***************************
  * 名称:IRcvStr()
  * 功能:使用硬件I2C读取数据。
  * 入口参数:无
  * 出口参数:返回值为0时表示出错,为1时表示操作正确。
  * 说明:使用前设置好参数
  ************************************************** **************************/
  uint8  IRcvStr(uint8 sla,uint8 suba,uint8 *s,uint8 no)
  {  if(0==no) return(0);
  /* 参数设置 */
  I2C_sla = sla+1;
  I2C_suba = suba;
  I2C_buf = s;
  I2C_num = no;    I2C_suba_en = 1;    I2C_end = 0;       I2CONCLR = 0x2C;    I2CONSET = 0x60;             // 设置为主机,并启动总线
  while(0==I2C_end);
  if(1==I2C_end) return(1);
  else return(0);
  }
  /************************************************* ***************************
  * 文件名:I2CTEST.C
  * 功能:使用硬件I2C对E2PROM进行操作,利用中断方式操作。
  * 说明:将跳线器JP4_LED1、JP9短接。
  ************************************************** **************************/
  #include  "config.h"
  #define   CSI24WC02 0xA0            /* 定义器件地址 */
  #define         LED1CON      (1<<22)
/*******************************
*名称:I2C_Init()
*功能:I2C初始化
*入口参数:无
*出口参数:无
*******************************/
  void I2C_Init(void)
{
...
}

void DelayNS(uint32 dly)
{
...
}
//报错
void WrEepromErr(void)
{
..}

main()
{
  uint8 i;
  uint8 data_buf[30];
  PINSEL0=0x00000050;
  PINSEL1=0;
  IO0DIR=LED1CON;
  IO0SET=LED1CON;
  I2C_Init();
for(i=0 ; i<10; i++)data_buf=i+'0';
ISendStr(CAT24WC02, 0X00, data_buf,10);//写
DelayND(1);

for(i=0; i<10; i++)data_buf=0;
IRcvStr(CAT24WC02,0x00,data_buf,10);//读
.....


}

相关帖子

沙发
阿南| | 2012-10-17 18:06 | 只看该作者
楼主需要去了解I2C通信原理和ARM中断部分的原理。这些只能是自己看书,别人帮不了你,呵呵。

使用特权

评论回复
板凳
yueyinji1989|  楼主 | 2012-10-17 22:20 | 只看该作者
哎啊,斑竹,就是看了好久也没头绪,继续看下去吧。。。
2# 阿南

使用特权

评论回复
地板
yueyinji1989|  楼主 | 2012-10-18 11:18 | 只看该作者
看了,结合上面的例程,自己写了个大概的流程,不知道对不对,希望有高人可以指点下,谢谢!
————————————————————————————————————————————
I2C通信中断操作过程(以LPC2138例程):
1、ISendStr,设置参数后进入I2C中断,此时状态寄存器为0x08,然后判断数据格式SLA+W.(此题从地址
为0xA0,8位,但SLA是7位的,所以最后一位R/W位,为0,所以进入主发送器模式.)
2、重启动条件,状态寄存器为0x10,此题即(SLA+W),继续写入.
3、此时已发送SLA+W+ACK,状态寄存器为0x18(应答)或20,(非应答);或38(仲裁丢失),(此题为0x18,将要写入数据).
4、此时已写入数据+ACK,状态寄存器为0x28(应答),将继续写.
5、直到接收到非应答信号,此时,已发送SLA+W,已接收非ACK,进入0x20,停止(因I2CONCLR=0x28,STO为1,停止)
6、此时已发送数据+非ACK,进入0x30,停止,原因同上。
7、丢失仲裁,进入0x38,总线不可寻。

此为主发送器模式,写。

读与写类似:
1、IRcvStr,进入I2C中断,此时从地址为0XA0+1,状态寄存器为0x08.(此题,因要从指定地址读,应先
写入地址,所以把SLA&0XFE,使其最后一位为0,写.)
2、重启动条件,0x10,此时再把SLA重新赋予I2DAT,最后一位为1,(SLA+R)进入主接收器模式。
3、此时已发送SLA+R,已接收ACK,状态寄存器为0x40,判断是否接收到最后一个数据,否,设置AA=1,应答,进入4;是,设置AA=0,非应答,进入5。
4、此时已接收数据+ACK,再判断是否接收到最后一位,返回ACK,继续 或 非ACK,停止。
5、此时已接收数据+非ACK,判断STA,ST0,SI位.(此题I2CONCLR=0X28,停止)
6、此时已发送SLA+R,接收非ACK,总线不可寻。

使用特权

评论回复
5
阿南| | 2012-10-18 14:11 | 只看该作者
如果看的差不多了,那就开始调试吧。先测试一下是否有产生中断,慢慢来不着急。

使用特权

评论回复
6
yueyinji1989|  楼主 | 2012-10-18 17:26 | 只看该作者

调试完成,还行!谢谢

本帖最后由 yueyinji1989 于 2012-10-18 17:27 编辑

5# 阿南

使用特权

评论回复
7
small泡泡| | 2013-11-13 14:20 | 只看该作者
我也看看这个

使用特权

评论回复
8
xiaolixiaoyue| | 2017-10-20 13:56 | 只看该作者
怎么调试成功的,我也在调试这个程序,参考的也是这个资料。谢谢

使用特权

评论回复
9
xiaolixiaoyue| | 2017-10-20 13:58 | 只看该作者

大神,怎么调成功的,我也参考的这个资料。

使用特权

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

本版积分规则

42

主题

281

帖子

0

粉丝