本帖最后由 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);//读
.....
} |