打印
[ZLG-ARM]

LPC2214的IIC的问题

[复制链接]
2886|9
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
smallwind1|  楼主 | 2011-2-18 16:37 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
我用的是IIC的从设备是pcf8563,但是调试的时候出现很奇怪的问题。就是我进IIC中断以后,SI无法被清0,所以程序执行不正常。

我的开发环境是ADS1.2
以下是我的主函数和iic的程序,在进入中断函数以后,我使用I2CONCLR寄存器把I2CONSET寄存器的中断标志位SI清0,但是在debug模式下,并没有清0.很是郁闷。。
main()
{
    uint8 test1[8] = {0};
    uint8 test2[8] = {0,0,0,1,0,0,0,1};
    I2C_Init(400000);
    ISendStr(0xa2,0x00,test1,8);

   while(1);
}

#include  "config.h"
#include  "LPC2214.h"
#include   "LPC2294.h"

/* 以下为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&0xF8)
  {
    case  0x08:
    if(1==I2C_suba_en) I2DAT = I2C_sla&0xFE;    // 指定子地址读时,先写入地址
  else I2DAT = I2C_sla;                     // 否则直接发送从机地址
  
  I2CONCLR = 0x28;        // SI=0
  //I2CONSET = 0x
  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;
  }
}

/**********************************************
*名称:I2C_Init()
*功能:I2C初始化,包括初始化其终端为向量IRQ中断
*入口参数:fic     初始化I2C总线速率,最大值为400K
*出口参数:无
***********************************************/
void I2C_Init(uint32 fi2c)
{
   if(fi2c>400000)   fi2c = 400000;
   
   IRQEnable();                            //打开中断
   
   PINSEL0 = (PINSEL0&0xFFFFFF0F)|0x50;   //设置IIC控制口有效
   
   I2SCLH = (Fpclk/fi2c + 1)/2;           //设置IIC时钟为fi2c
   I2SCLL = (Fpclk/fi2c)/2;
   I2CONCLR = 0x2C;
   I2CONSET = 0x40;                        //使能主IIC
   
   /*设置IIC中断允许*/
   VICIntSelect = 0x00000000;             //设置所有通道为IRQ中断
   VICVectCntl0 = 0x29;                   //IIC通道分配到IRQ slot0
   VICVectAddr0 = (int)IRQ_I2C;           //设置IIC中断向量地址
   VICIntEnable = 0x200;                  // 使能IIC中断
   
}

/****************************************************************************
* 名称:ISendByte()
* 功能:向无子地址器件发送一字节数据。
* 入口参数:sla  器件地址
*          dat  要发送的数据
* 出口参数:返回值为0时表示出错,为1时表示操作正确。
* 说明:使用前要初始化好I2C引脚功能和I2C中断,并已使能I2C主模式
****************************************************************************/
uint8  ISendByte(uint8 sla, uint8 dat)
{
/* 参数设置 */
I2C_sla = sla;  // 写操作的器件地址
I2C_buf = &dat;  // 待发送的数据
I2C_num = 1;   // 发送1字节数据
I2C_suba_en = 0;  // 无子地址
I2C_end = 0;

I2CONCLR = 0x2C;
I2CONSET = 0x60;             // 设置为主机,并启动总线

while(0==I2C_end);
if(1==I2C_end) return(1);
else return(0);
}

/****************************************************************************
* 名称:ISendStr()
* 功能:向有子地址器件发送多字节数据。
* 入口参数:sla  器件从机地址
*          suba  器件子地址
*          s  数据发送缓冲区指针
*          no  发送数据个数
* 出口参数:返回值为0时表示出错,为1时表示操作正确。
* 说明:使用前要初始化好I2C引脚功能和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 = 0x6C;
I2CONSET = 0x60;             // 设置为主机,并启动总线

while(0==I2C_end);
if(1==I2C_end) return(1);
else return(0);
}

/****************************************************************************
* 名称:IRcvByte()
* 功能:向无子地址器件读取一字节数据。
* 入口参数:sla  器件地址
*          dat  接收数据的变量指针
* 出口参数:返回值为0时表示操作出错,为1时表示操作正确。
* 说明:使用前要初始化好I2C引脚功能和I2C中断,并已使能I2C主模式
****************************************************************************/
uint8  IRcvByte(uint8 sla, uint8 *dat)
{
/* 参数设置 */
I2C_sla = sla+1;  // 读操作的器件地址
I2C_buf = dat;
I2C_num = 1;
I2C_suba_en = 0;  // 无子地址
I2C_end = 0;

I2CONCLR = 0x2C;
I2CONSET = 0x60;             // 设置为主机,并启动总线

while(0 == I2C_end);
if(1 == I2C_end)
{
  return(1);
}
else
{
  return(0);
}
}

/****************************************************************************
* 名称:IRcvStr()
* 功能:向有子地址器件读取多字节数据。
* 入口参数:sla  器件地址
*          suba  器件子地址
*          s  数据接收缓冲区指针
*        no   读取数据个数
* 出口参数:返回值为0时表示操作出错,为1时表示操作正确。
* 说明:使用前要初始化好I2C引脚功能和I2C中断,并已使能I2C主模式
****************************************************************************/
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);
}

相关帖子

沙发
amini| | 2011-2-20 16:01 | 只看该作者
帮你顶上去,求解。

使用特权

评论回复
板凳
maoyanketi| | 2011-2-20 16:46 | 只看该作者
程序中写上SI清零也无法被清0吗?

使用特权

评论回复
地板
smallwind1|  楼主 | 2011-2-22 13:33 | 只看该作者
3# maoyanketi

对,SI无法清零,后来发现IIC如果是在ADS的debug里进行调试,观察寄存器的话,确实没法清零,好像这个不能实时的反应IIC总线上的实际情况,现在的问题是我能读,不能写,还有就是如果把读函数放到while循环里,读函数只能执行一次,第二就执行不了

使用特权

评论回复
5
smallwind1|  楼主 | 2011-2-22 13:33 | 只看该作者
SI无法清零,后来发现IIC如果是在ADS的debug里进行调试,观察寄存器的话,确实没法清零,好像这个不能实时的反应IIC总线上的实际情况,现在的问题是我能读,不能写,还有就是如果把读函数放到while循环里,读函数只能执行一次,第二就执行不了。
就是说只能读一次,写操作无法进行

使用特权

评论回复
6
-自己人| | 2011-2-23 12:29 | 只看该作者
永远不明白IIC啊

使用特权

评论回复
7
快乐出发| | 2011-2-23 14:48 | 只看该作者
唉,我还是不明白啊。怎么办呢?

使用特权

评论回复
8
foreverly| | 2011-2-23 22:40 | 只看该作者
见得多了就明白了。

使用特权

评论回复
9
smallwind1|  楼主 | 2011-2-24 16:20 | 只看该作者
问题已经解决了,只是具体原因还是不清楚,我同事刚开始给我的模板上可能有点问题吧,也不是很清楚啊,两个模板明明一模一样,但是第一个弄了半天就是只能读一次,后来重新给我传了一个模板就ok了,总之,总结了一下最近调试IIc的经验

IIC调试最好不要在debug里调试,单步调试观察寄存器并不能反映实际总线上运行的情况,因为实际总线上的传输可能信号变化很快,寄存器上的值并不能反映实时的寄存器值。
另外实验的时候发现,如果晶振的电容不焊接的话,在调试的时候有时候读取时间的时候,时间不发生变化,所以建议按照现在的原理图把电容进行焊接好。

现在用的模板是周立功给的模板,如果看网上的一些资料的话,IIC的初始化函数里一般都少了开中断函数,如果测试进不了中断,那么就要注意了,我现在采用的方式是进IIC初始化以后,配置通信速率,然后就是开中断,函数名称是:IRQEnable();
注意一定要开中断,很多时候你调试的时候发现没反应的时候,请查一下中断时候在程序运行的过程中打开了。当然有的周立功的模板的启动文件里可能把中断设置为常开,那么此时没必要用IRAEnable();函数进行开中断了。

我的IIC已经ok了,希望大家以后也ok,下一步搞IAP。。。

使用特权

评论回复
10
vivisa| | 2011-2-24 17:34 | 只看该作者
学习了。

使用特权

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

本版积分规则

0

主题

52

帖子

1

粉丝