打印
[ZLG-ARM]

求教lpc2214的I2C问题(期待中~~)

[复制链接]
3946|19
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
hmlxy|  楼主 | 2007-8-1 16:10 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
大家好!小弟在使用lpc2214的I2C时遇到如下问题,请大家帮忙分析一下。

我的I2C上挂有PCF8563时钟芯片和24C64存储芯片,我的I2C使用的是查询方式,但是我的程序中还用到了两个串口,两个串口的接收是中断方式,发送是查询方式,现在问题如下:

1.当我在I2C操作时,把系统中断都关闭(当然主要是针对串口接收中断),这时从PCF8563时钟芯片中读到数据一直无错误,当然这种方法使通讯的成功率大大降低。

2.当我在I2C操作时,不关闭中断(当然主要是针对串口接收中断),这时从PCF8563时钟芯片中读到数据会出错,现象是:程序运行一段时间后,从PCF8563种读出的时间的“分钟”数会无故变为23分(我的程序没有对PCF8563进行写操作),然后时间又正常一段时间,但再过一段时间(1秒至2分钟左右),时间又会复位为23分,当然这种方法通讯的成功率很高,这也是我所需要的。
我分析可能是在I2C操作时,产生的串口接收中断影响了IC2总线的操作时序,但不明白的是为什么时间总是复位为23分(我把程序中的I2C写操作全部屏蔽了,且把对24c64的任何操作也屏蔽了,结果还是这样)
请问有什么方法既能保证我的通讯无误又能保证我的I2C操作无误?

请周工及各路朋友多多指教!
非常感您的阅读!期待您的解答!

相关帖子

沙发
hmlxy|  楼主 | 2007-8-2 08:39 | 只看该作者

~~~~

使用特权

评论回复
板凳
zlgARM| | 2007-8-2 11:33 | 只看该作者

hmlxy

您好:
    是否可以把问题转换一下。首先,I2C是否能单独通讯正确;然后,加上UART,再观察I2C和UART通讯是否都正确,如果不正确,是什么地方起了冲突?(一般都是共享资源部分发生冲突)。这个时候您可能需要改变资源的使用算法。

使用特权

评论回复
地板
hmlxy|  楼主 | 2007-8-2 12:35 | 只看该作者

谢谢zlgARM

zlgARM:非常感谢您的回答
  您说的方法我也试过,当没有加入串口时,I2C单独通讯是正确的,但加入串口后,I2C的读上来的数据就会出错,这种现象在上位机通过串口对ARM访问频率高的时候更容易发生。
  我的串口程序对共享资源部分只有读操作,没有写操作,所以我感觉不像是共享资源冲突问题。
  还有就是我的I2C使用的是查询方式,而串口接收是中断方式,不知道在I2C操作的时候,突然来了一个串口中断,会不会影响I2C的时序?

使用特权

评论回复
5
swill_333| | 2007-8-2 15:38 | 只看该作者

LPC2214不能同是开TIME1和TIMER0中断

LPC2214不能同是开TIME1和TIMER0中断
我用LPC2214,
1,    Timer0 用作10mS定时,是UCOS的时钟节拍
2,    Timer1 用作100uS定时,是无线解码
3,    只要我打开Timer1中断  
 VICIntEnable=1<<5;// 使能定时器1中断
 全速运行程序,就会进入;  
 取数据中止
  DataAbort
  B       DataAbort

4,请问各位高手有没有碰到此现象,有什么方法解决吗?

使用特权

评论回复
6
zlgARM| | 2007-8-2 15:57 | 只看该作者

hmlxy

您好:
   这个问题,需要实地调试和了解代码。
   与其凭空猜测,不如直面代码、直接调试。
   建议您建立一个单纯的调试例程,内里仅包含UART和I2C的代码,尽量精简(除去一切无关的细节),再发上来看看。谢谢!

使用特权

评论回复
7
hmlxy|  楼主 | 2007-8-2 16:34 | 只看该作者

谢谢zlgARM

zlgARM:您好!
  我也正准备这样做,这几天有点忙,过几天我做个调试程序,在把结果拿出来讨论一下,谢谢!
  
swill_333 你好!
  关于你说的现象,我感觉不应该是你说的“LPC2214不能同是开TIME1和TIMER0中断”,因为我也试过在程序中同时使用的TIMER0和TIME1,但程序运行没有错误,其实有很多情况可以引起数据中止,比如你访问的存储区超出了范围(使用指针或数组时若不小心可能出现这种情况)。你可以先看看跟踪一下程序看是不是代码的问题!
  但还是建议使用软定时器。
  小弟我也是初学者,这里只能给点参考意见,可能我的理解也不一定正确,还请谅解

使用特权

评论回复
8
hmlxy|  楼主 | 2007-8-5 13:53 | 只看该作者

zlgARM请进,我按您的要求写了个单纯的调试例程

zlgARM:您好!
    我按您的要求写了个单纯的调试例程,去掉了定时器中断、串口0接收中断、外部中断等等,目前只保留了串口1接收中断和I2C操作,但是现象跟原来基本一样,只是有一点不同,就是现在I2C操作错误的几率变小了,原来是1秒至2分钟左右,现在是1秒至10分钟左右。下面是我的代码,请您帮忙分析一下,如果能提供您的邮箱,我可以把整个工程发给您,谢谢!

//用户主程序
int  main(void)

  IO_PortConf();                        //IO端口配置程序;
  WP_SET1();                            //24C64写保护
  I2C_Query_Init(100000);               //I2C总线初始化(100k的速率) 
  UART1_Initial(57600, 8,1,2);          // 初始化串口1
  UART1_Open();                         // 打开串口开始接收数据   
  //主循环部分
  while(1)
  {    
    if(Rx_flag==1)       // 判断接收缓冲区中是否有数据需要处理
    { 
      UART1_Close();
      MCNP_V20_dataParse();
      Rx_flag=0;
      UART1_Open();      
      UART1_SendByteStream(Tx_start,0x00);
    }      
    Read_SysDateTime();  // 读系统日期时间     
    Set_SysDateTime();   
  }
  return(0);  
}

//对通讯接收缓冲区中接收到的数据包进行解析,并进行相应的处理 
void MCNP_V20_dataParse(void)
{ uint16    i;
  uint8    anao;    
  Tx_num=0;  
  switch((Rx_buffer[3]<<8) | Rx_buffer[4])    // 取出命令号     
  {
    //读取系统时间 (格式:年|月|日|时|分|秒|星期)          
    case 0x0003:
    {
      Tx_buffer[0]=0;               // 装入本机地址
      Tx_buffer[1]=Rx_buffer[3]+48; // 装入返回的命令号1 
      Tx_buffer[2]=Rx_buffer[4];    // 装入返回的命令号2
      Tx_buffer[3]=0;               // 装入返回数据的"字节数1"
      Tx_buffer[4]=7;               // 装入返回数据的"字节数2"
      Tx_buffer[5]=WDataZone.var.SystemDate.year;      // 年
      Tx_buffer[6]=WDataZone.var.SystemDate.month;      // 月
      Tx_buffer[7]=WDataZone.var.SystemDate.day_of_month;// 日
      Tx_buffer[8]=WDataZone.var.SystemTime.hour;      // 时
      Tx_buffer[9]=WDataZone.var.SystemTime.minute;      // 分
      Tx_buffer[10]=WDataZone.var.SystemTime.second;      // 秒
      Tx_buffer[11]=WDataZone.var.SystemDate.day_of_week;// 星期
      //------------------------
      //计算发送包的校验字节             
      anao=0;
      for(i=0;i<12;i++)
      {
        anao=anao+Tx_buffer;
      }
      anao=~anao+1;    
      Tx_buffer[12]=anao;    // 装入返回数据的校验字节 
      //------------------------
      Tx_num=13;               // 返包数据中从源地址到校验数的字节总数
    }
    break;     

    //设定系统时间(格式:年|月|日|时|分|秒|星期)     
    case 0x3000:
    {
      WDataZone.var.SystemDateTimeSetData.year=Rx_buffer[7]; // 年
      WDataZone.var.SystemDateTimeSetData.month=Rx_buffer[8];// 月
      WDataZone.var.SystemDateTimeSetData.day_of_month=Rx_buffer[9];// 日
      WDataZone.var.SystemDateTimeSetData.hour=Rx_buffer[10];   // 时
      WDataZone.var.SystemDateTimeSetData.minute=Rx_buffer[11];  // 分
      WDataZone.var.SystemDateTimeSetData.second=Rx_buffer[12];  // 秒
      WDataZone.var.SystemDateTimeSetData.day_of_week=Rx_buffer[13];// 星期
      WDataZone.var.SystemDateTimeSetData.DateTimeSetFlag=1;//为1表示需要设定系统时间
      Set_SysDateTime();        // 设定PCF8563的时间      
    }
    break;     
           
    default  :break;             
  }      
  return;
}


//设置系统日期和时间
void  Set_SysDateTime(void)

  if(WDataZone.var.SystemDateTimeSetData.DateTimeSetFlag==1)
  { 
    WDataZone.var.SystemDateTimeSetData.DateTimeSetFlag=0;
    I2cmtd[0]=0; //控制字1
    I2cmtd[1]=0; //控制字2
    I2cmtd[2]=WDataZone.var.SystemDateTimeSetData.second;//秒 
    I2cmtd[3]=WDataZone.var.SystemDateTimeSetData.minute;//分钟  
    I2cmtd[4]=WDataZone.var.SystemDateTimeSetData.hour;//小时
    I2cmtd[5]=WDataZone.var.SystemDateTimeSetData.day_of_month;//日  
    I2cmtd[6]=WDataZone.var.SystemDateTimeSetData.day_of_week;//星期
    I2cmtd[7]=WDataZone.var.SystemDateTimeSetData.month;//月
    I2cmtd[8]=WDataZone.var.SystemDateTimeSetData.year;//年   
    I2C_Query_DeviceSendStr(PCF8563, 1, 0x00, I2cmtd, 9);  
  }
  return;
}


//读系统日期和时间
void  Read_SysDateTime(void)
{
  uint16 I2c_ok;                                  // I2c_ok=1表示I2C读数据操作成功  
  I2c_ok=I2C_Query_DeviceRcvStr(PCF8563, 1, 0x02, I2cmrd, 7);    
  if(I2c_ok==0) return;                         // 如果I2C总线读数据操作失败,则放弃该次操作,需读的参数保持原来的值    
  WDataZone.var.SystemTime.second=I2cmrd[0] & 0x7F;      //秒 
  WDataZone.var.SystemTime.minute=I2cmrd[1] & 0x7F;      //分钟 
  WDataZone.var.SystemTime.hour=I2cmrd[2] & 0x3F;        //小时
  WDataZone.var.SystemDate.day_of_month=I2cmrd[3] & 0x3F; //日  
  WDataZone.var.SystemDate.day_of_week=I2cmrd[4] & 0x07;//星期
  WDataZone.var.SystemDate.month=I2cmrd[5] & 0x1F;       //月
  WDataZone.var.SystemDate.year=I2cmrd[6];               //年   
  return;   
}


//-----------------向有子地址器件发送多字节数据函数--------------------------------------------- 
//原    形: uint8 I2C_Query_DeviceSendStr(uint8 sla, uint8 subatype, uint16 suba, uint8 *str, uint16 no)
//描    述: 从启动总线到发送地址,子地址,读数据,结束总线的全过程
//输入参数: sla         从器件地址,
//          subatype    子地址类型,    子地址结构    1-单字节地址    2-双字节地址
//          suba        子地址,
//          str         要写入的内容放入str指向的存储区          
//          no          读no个字节。 该参数超过缓存器的最大字节数无效 (注意!!!)       
//输出参数: 函数返回1表示操作成功,否则操作有误。
//头 文 件: "I2C_chip.h"
//库 文 件: 无
//注意事项: 需注意当给定的起始地址与欲写的N字节数据超过本页最后一个存储单元后,将转入本页的第一个单元
//          进行"滚动循环".即读取的I2C器件中数据是在本页进行的页内部循环(注意!!!!!!!)
//          24C64中的RAM缓存器为32个字节,即一页为32个字节
//---------------------------------------------------------------------------------------------- 
uint8 I2C_Query_DeviceSendStr(uint8 sla, uint8 subatype, uint16 suba, uint8 *str, uint16 no)
{
  uint16  i;
  uint8  var;
  uint8  *string;
  string=str;
  //INT_Close();                   //关闭所有使用到的中断,防止I2C操作的时候,中断发生,导致I2C出错
  
  GetBus();                       //启动总线//
  I2CONCLR=(1<<5);                      //清零STA位//
  I2CBusSendByte(sla);            //发送从器件写操作地址sla//

  if(I2STAT!=0x18)
  {
    I2CONSET = (1 << 4);                    // 置位STO,结束总线             //
    I2CONCLR = 0x28;                          // 清零SI, STA位,结束总线     //
    //INT_Open();                     //打开所有使用到的中断,恢复原样
    return(0);
  }
  
  if(subatype==1)                                        //器件地址为1个字节的地址
  {
    var = suba & 0xFF;
      I2CBusSendByte(var);            //发送器件子地址//在此之后,将进入读寄存器模式
      
      if((I2STAT!=0x28))//&&(I2STAT!=0x30)
      {
          I2CONSET = (1 << 4);                    // 置位STO,结束总线             //
        I2CONCLR = 0x28;                          // 清零SI, STA位,结束总线     //
        //INT_Open();                     //打开所有使用到的中断,恢复原样
          return(0);
      }
  }
  
  else if(subatype==2)                                //器件地址为2个字节的地址
  {
    var = suba>>8;                                        //先发高8位地址
    I2CBusSendByte(var);             //发送器件子地址高8位
       
      if((I2STAT!=0x28))//&&(I2STAT!=0x30)
      {
        I2CONSET = (1 << 4);                    // 置位STO,结束总线             //
        I2CONCLR = 0x28;                          // 清零SI, STA位,结束总线     //
        //INT_Open();                     //打开所有使用到的中断,恢复原样
          return(0);
      }
       
      var=suba & 0xFF;                                    //再发低8位地址
      I2CBusSendByte(var);            //发送器件子地址低8位//在此之后,将进入读寄存器模式
       
      if((I2STAT!=0x28))//&&(I2STAT!=0x30)
      {
        I2CONSET = (1 << 4);                    // 置位STO,结束总线             //
        I2CONCLR = 0x28;                          // 清零SI, STA位,结束总线     //
        //INT_Open();                     //打开所有使用到的中断,恢复原样
        return(0);
      }
  }
    
  for(i=0;i<no;i++)
  {   
    I2CBusSendByte(*string);           //发送数据//
    if((I2STAT!=0x28))//&&(I2STAT!=0x30)
    {
      I2CONSET = (1 << 4);                    // 置位STO,结束总线             //
      I2CONCLR = 0x28;                          // 清零SI, STA位,结束总线     //
      //INT_Open();                     //打开所有使用到的中断,恢复原样
      return(0);
    }
    string++;
  } 
  I2CONSET = (1 << 4);                    // 置位STO,结束总线             //
  I2CONCLR = 0x28;                          // 清零SI, STA位,结束总线     //
  Write24Cxx_delayNms(10);        // 延时10ms(不论写1字节还是写32字节,延时都必须大于等于10ms)
  //INT_Open();                     //打开所有使用到的中断,恢复原样
  return(1);
}

//-----------------向有子地址器件读取多字节数据函数--------------------------------------------- 
//原    形: I2C_Query_DeviceRcvStr(uint8 sla, uint8 subatype, uint16 suba, uint8 *str, uint16 no)
//描    述: 从启动总线到发送地址,子地址,读数据,结束总线的全过程
//输入参数: 从器件地址sla,
//          子地址类型subatype,    子地址结构    1-单字节地址    2-双字节地址
//          子地址suba,
//          读出的内容放入str指向的存储区          
//          需要读的字节个数在no中
//输出参数: 函数返回1表示操作成功,否则操作有误。
//头 文 件: "I2C_chip.h"
//库 文 件: 无
//注意事项: 需注意当给定的起始地址与欲读的N字节数据超过最后一页最后一个存储单元后,将转入第一页的第一个单元
//          即读取的I2C器件中数据是所有页进行的全循环
//---------------------------------------------------------------------------------------------- 
uint16 I2C_Query_DeviceRcvStr(uint8 sla, uint8 subatype, uint16 suba, uint8 *str, uint16 no)
{
  uint16  i,j;
  uint8  var;
  uint8  *string;
  string=str;
  //INT_Close();                   //关闭所有中断,防止I2C操作的时候,中断发生,导致I2C出错
  
  GetBus();                 //启动总线//
  I2CONCLR=(1<<5);                              //清零STA位//
  I2CBusSendByte(sla);            //发送从器件写操作地址sla//
  if(I2STAT!=0x18)
  {
    I2CONSET = (1 << 4);                    // 置位STO,结束总线             //
    I2CONCLR = 0x28;                          // 清零SI, STA位,结束总线     //
    //INT_Open();                     //打开所有使用到的中断,恢复原样
    return(0);
  }
  
  if(subatype==1)                                        //器件地址为1个字节的地址
  {
    var = suba & 0xFF;
  
      I2CBusSendByte(var);            //发送器件子地址//在此之后,将进入读寄存器模式
      
      if((I2STAT!=0x28))//&&(I2STAT!=0x30)
      {
        I2CONSET = (1 << 4);                    // 置位STO,结束总线             //
        I2CONCLR = 0x28;                          // 清零SI, STA位,结束总线     //
        //INT_Open();                     //打开所有使用到的中断,恢复原样
          return(0);
      }
  }
   
  else if(subatype==2)                                //器件地址为2个字节的地址
  {
    var = suba>>8;                                        //先发高8位地址
  
      I2CBusSendByte(var);             //发送器件子地址高8位
      
      if((I2STAT!=0x28))//&&(I2STAT!=0x30)
      {
        I2CONSET = (1 << 4);                    // 置位STO,结束总线             //
        I2CONCLR = 0x28;                          // 清零SI, STA位,结束总线     //
        //INT_Open();                     //打开所有使用到的中断,恢复原样
          return(0);
      }
       
      var=suba & 0xFF;                                    //再发低8位地址
      I2CBusSendByte(var);            //发送器件子地址低8位//在此之后,将进入读寄存器模式
      
      if((I2STAT!=0x28))//&&(I2STAT!=0x30)
      {
          I2CONSET = (1 << 4);                    // 置位STO,结束总线             //
        I2CONCLR = 0x28;                          // 清零SI, STA位,结束总线     //
        //INT_Open();                     //打开所有使用到的中断,恢复原样
          return(0);
      }
  }
   
   
  //I2CONSET = (1 << 4);                    // 置位STO,结束总线             //
  //I2CONCLR = 0x28;                          // 清零SI, STA位,结束总线     //
  I2CONCLR = (1 << 3);                        // 清零SI
  I2CONSET = (1 << 5);              //置位STA, 重新启动总线//
  
  
  for(j=0;j<20000;j++)
    {
    if((I2CONSET & 0x08)!=0) break;
  } 
  
  I2CONCLR = (1 << 5);                          // 清零STA
  I2CBusSendByte(sla+1);
  
  if(I2STAT!=0x40)
  {
      I2CONSET = (1 << 4);                    // 置位STO,结束总线             //
    I2CONCLR = 0x28;                          // 清零SI, STA位,结束总线     //
    //INT_Open();                     //打开所有使用到的中断,恢复原样
      return(0);
  } 
  
  for(i=0;i<no-1;i++)
  {  
    I2CONSET = (1 << 2);               //接收一字节数据并发送应答位//
    I2CONCLR = (1 << 3);                         //清零SI
    
      for(j=0;j<20000;j++)
        {
        if((I2CONSET & 0x08)!=0) break; //等待接收数据//
      }
    
    if(I2STAT!=0x50)
    {
        I2CONSET = (1 << 4);                    // 置位STO,结束总线             //
      I2CONCLR = 0x28;                          // 清零SI, STA位,结束总线     //
      //INT_Open();                     //打开所有使用到的中断,恢复原样
        return(0);
    }
    
    *string=I2DAT;                  //读取数据// 
    string++;
  } 
  I2CONCLR = (1<<2);                 //接收最后一字节数据并发送非应答位//
  I2CONCLR = (1 << 3);                            //清零SI
  
  for(j=0;j<20000;j++)
    {
    if((I2CONSET & 0x08)!=0) break;
  }

  *string=I2DAT;
  I2CONSET = (1 << 4);                    // 置位STO,结束总线             //
  I2CONCLR = 0x28;                          // 清零SI, STA位,结束总线     //
  //INT_Open();                     //打开所有使用到的中断,恢复原样
  return(1);
}


使用特权

评论回复
9
hmlxy|  楼主 | 2007-8-5 13:54 | 只看该作者

接上页

//---------------------------------------------------------------------------------------------- 
//原    形: void   __irq myIRQ_UART1(void)  (__irq关键字表示该程序是中断服务程序)
//描    述: 串口UART1接收中断
//输入参数: 无
//输出参数: Rx_flag  (若收到一个完整且正确的数据包,则置位该标志为1)(全局变量)
//          Rx_buffer(接收到的数据在接收缓冲区中)(全局变量)
//头 文 件: MCNP_V20_dataParse.h 
//库 文 件: 无
//注意事项:  
//---------------------------------------------------------------------------------------------- 
void   __irq myIRQ_UART1(void)
{ uint8  temp;
  uint16 i,j;
  
  temp=U1LSR;                     // 读取UART0线状态寄存器
  if((temp & 0x8E)!=0)            // 判断是否有接收出错
  { //注意:下面这段顺序不能交换,这是清除错误的顺序(书226页)
    //下面这一段主要是为了解决在下面的问题:
    //由于外部硬件的485控制芯片的输入与输出的控制端采用了互斥的电路设计,这就会使本CPU在发送数据
    //操作DISOUT1_SET0时,他的串口接收线出现一个由高到低的跳变,然后一直保持低电平直到发送结束后
    //操作DISOUT1_SET0时,再跳变回高电平,这就必然会引起串口输入的某一种错误(帧错误/奇偶错误/间隔中断)
    //导致在串口发送数据结束后马上进串口接收中断myIRQ_UART1,下面的操作就是为了对该错误进行处理,
    //以保证正常的通讯    
    i=U1RBR;                      // 虚读,得到的数据没有作用,只是为了清除错误 
    temp=U1LSR;                   // 虚读,得到的数据没有作用,只是为了清除错误   
  } 
  else if(Rx_flag==1) 
  {     
    //U1FCR=RXFL_Sel | 0x07;      // 该句不能要,若用该句,则在用MNCP初始化显示屏时会出现CPU复位死机现象
    Rx_num=0;    
        
    switch(U1IIR & 0xCF)          // 判断中断标识寄存器
    {
      case 0xC1:    break;          // 没有挂起的中断
      
      // RLS(接收线出错)中断        
      case 0xC6:                        
      {
        temp=U1LSR;               // 读取UART1线状态寄存器(U1LSR),并清除RLS中断,并清零U1LSR中的相关错误位
        if((temp & 0x9E)!=0) 
        {
          //U1FCR=U1FCR | 0x02;   // 由于U1FCR寄存器为只写寄存器,故不能采用先读后写的操作
          U1FCR=RXFL_Sel | 0x07;  // 当接收线出错,则复位RX FIFO,清零接收缓存队列
        }        
      }
      break; 
            
      // RDA(接收数据可用)中断, 由于采用的是FIFO模式,则发生此中断说明FIFO到达触发点
      case 0xC4:           
      {
        temp=U1LSR;                        // 读取UART1线状态寄存器(U1LSR)
        if((temp & 0x01)!=0 )          // 如果U1RBR中包含未读取的有效数据,则读取这些数据
        {
          for(i=0; i<FIFOLengthDeep-1; i++)
          {
            if((U1LSR & 0x01)!=0 )
            {
              j=U1RBR;            // 取出队列缓存FIFO中接收到的字节数据
                                  // 无需加入检验奇偶校验位的子程序,因为硬件自带了
            }                
          }
        }
      }  
      break;
        
      // CTI(字符超时指示)中断  
      case 0xCC:           
      //在FIFO模式下,发生该中断则认为此次数据报发送完毕,剩余的数据字节在FIFO中,但不到触发深度
      for(i=0; i<FIFOLengthDeep; i++)
      {
        temp=U1LSR;                        // 读取UART1线状态寄存器(U1LSR)
        if((temp & 0x01)!=0 )          // 如果U1RBR中包含未读取的有效数据,则读取这些数据
        {
          j=U1RBR;// 取出队列缓存FIFO中接收到的字节数据
                                  // 无需加入检验奇偶校验位的子程序,因为硬件自带了
        }
        else                                   // U1RBR中没有未读取的有效数据,则停止数据的读取,并置位数据报接收完毕标志
        {
          break;
        }
      }
      break;         
      // THRE中断
      case 0xC2:  break;          
      default:    break;
    }    
  }
  else
  {    
    switch(U1IIR & 0xCF)          // 判断中断标识寄存器
    {
      case 0xC1:    break;          // 没有挂起的中断
      
      // RLS(接收线出错)中断        
      case 0xC6:                        
      {
        temp=U1LSR;               // 读取UART1线状态寄存器(U1LSR),并清除RLS中断,并清零U1LSR中的相关错误位
        if((temp & 0x9E)!=0) 
        {
          //U1FCR=U1FCR | 0x02;   //由于U1FCR寄存器为只写寄存器,故不能采用先读后写的操作
          U1FCR=RXFL_Sel | 0x07;  // 当接收线出错,则复位RX FIFO,清零接收缓存队列
        }
        Rx_flag=0;                          // 串口未收到数据报
        Rx_num=0;                          // 接收到的报文字节标记号归零
      }
      break; 
            
      // RDA(接收数据可用)中断, 由于采用的是FIFO模式,则发生此中断说明FIFO到达触发点
      case 0xC4:           
      {
        temp=U1LSR;                        // 读取UART1线状态寄存器(U1LSR)
        if((temp & 0x01)!=0 )          // 如果U1RBR中包含未读取的有效数据,则读取这些数据
        {
          for(i=0; i<FIFOLengthDeep-1; i++)
          {
            if((U1LSR & 0x01)!=0 )
            {
              Rx_buffer[Rx_num]=U1RBR; // 取出队列缓存FIFO中接收到的字节数据
                                       // 无需加入检验奇偶校验位的子程序,因为硬件自带了
              Rx_num++;
              if(Rx_num>=150) 
              {
                Rx_num=0;
              }
            }                
          }
        }
      }  
      break;
        
      // CTI(字符超时指示)中断  
      case 0xCC:           
      //在FIFO模式下,发生该中断则认为此次数据报发送完毕,剩余的数据字节在FIFO中,但不到触发深度
      for(i=0; i<FIFOLengthDeep; i++)
      {
        temp=U1LSR;                        // 读取UART1线状态寄存器(U1LSR)
        if((temp & 0x01)!=0 )          // 如果U1RBR中包含未读取的有效数据,则读取这些数据
        {
          Rx_buffer[Rx_num]=U1RBR;// 取出队列缓存FIFO中接收到的字节数据
                                  // 无需加入检验奇偶校验位的子程序,因为硬件自带了
          Rx_num++;
        }
        else                                   // U1RBR中没有未读取的有效数据,则停止数据的读取,并置位数据报接收完毕标志
        {
          Rx_flag=1;                    // 置位"串口收到完整数据报标志"
          Rx_num=0;        
          break;
        }
      }
      break;
         
      // THRE中断
      case 0xC2:  break;          
      default:    break;
    }   
  }     
  VICVectAddr = 0x00;             // 中断处理结束,清除相关寄存器
}         

//---------------------------------------------------------------------------------------------- 
//原    形: void  UART1_SendByteStream(void)
//描    述: 向串口发送数据流
//输入参数: Tx_num          返包数据中从源地址到校验数的字节总数(等于数据部分字节数+6)
//          Tx_buffer[] 串行发送缓冲区(缓冲区中是从源地址----校验数的数据)    
//          start       起始字节
//          TargetAddr  目标地址
//输出参数: 
//头 文 件: MCNP_V20_dataParse.h 
//库 文 件: 无
//注意事项:  
//---------------------------------------------------------------------------------------------- 
void  UART1_SendByteStream(uint8 Start,uint8 TargetAddr)
{
  uint16 i;
  uint16 j;
  if(Tx_num==0)
  {
    return;                                   // 若没有要发送的数据包,则退出
  }
  VICIntEnClr = 0x00000080;    // 禁止UART1中断  VICIntEnClr[bit7]=1
  DISOUT1_SET0();                         // DISOUT1脚置0表允许发送数据 
  //delayNus(10); 
     
  U1THR = Start;                          // 发送MCNPV2.0协议的数据包起始字节
  for(j=0;j<30000;j++)                 // 之所以使用循环而不用While语句,是为了防止while语句可能出现死锁
  {
    if((U1LSR&0x40)!=0) break; // 等待数据发送完毕
  }

  U1THR = TargetAddr;                 // 发送目的地址(即主机地址)
  for(j=0;j<30000;j++)                 // 之所以使用循环而不用While语句,是为了防止while语句可能出现死锁
  {
    if((U1LSR&0x40)!=0) break;     // 等待数据发送完毕
  }  

  for(i=0;i<Tx_num;i++)  
  {
    U1THR = Tx_buffer;             // 发送从源地址到校验数的字节    
    for(j=0;j<30000;j++)             // 之所以使用循环而不用While语句,是为了防止while语句可能出现死锁
    {
      if((U1LSR&0x40)!=0) break;     // 等待数据发送完毕
    }   
  }
  
  U1THR = Tx_stop;                      // 发送MCNPV2.0协议的数据包结束字节
  for(j=0;j<30000;j++)                 // 之所以使用循环而不用While语句,是为了防止while语句可能出现死锁
  {
    if((U1LSR&0x40)!=0) break;     // 等待数据发送完毕
  }
  //delayNus(10); 
  DISOUT1_SET1();                     // DISOUT1脚置1表允许接收数据 
  VICIntEnable = 0x00000080;         // 使能UART1中断  VICIntEnable[bit7]=1 
  return;
}

使用特权

评论回复
10
zlgarm| | 2007-8-5 16:06 | 只看该作者

Re

大致看了一下您的程序,有几个方面感觉有点不清晰:
1、您的程序是前后台的还是基于uc/OS-II的?
2、由于I2C操作很多情况下都是使用中断方式,所以就要求合理处理系统中的中断。
您可以将工程文件发送到邮箱:ARM.Support@zlgmcu.com

使用特权

评论回复
11
LPC900| | 2007-8-5 16:46 | 只看该作者

注意:PCF8563和24C64在I2C从机地址上可能存在冲突!

使用特权

评论回复
12
火光| | 2007-8-5 17:12 | 只看该作者

楼主啊,你为什么不是全部用中断方式呢?


hmlxy:
--------------------------------------------------------------------
我的I2C上挂有PCF8563时钟芯片和24C64存储芯片,我的I2C使用的是查询方式,但是我的程序中还用到了两个串口,两个串口的接收是中断方式,发送是查询方式
--------------------------------------------------------------------
你为什么不全部使用中断方式呢?
应该养成用中断的习惯,,,器件本来就是有这个能力的,为什么不用呢?用查询的话,顾了这边顾不了那边的,工作效率太低!

使用特权

评论回复
13
hmlxy|  楼主 | 2007-8-5 19:50 | 只看该作者

谢谢各位的跟帖!

  周工(zlgARM):
      您好!
      我已把整个工程文件发到了您的邮箱,辛苦您了,谢谢!!

  LPC900:
      您好!
      非常谢谢您的回贴!“PCF8563和24C64在I2C从机地址上可能存在冲突!”
      我觉得不象是这个问题,因为我的地址定义为
       #define At24cxx                     0x0A0 // 定义器件I2C的地址为0xA0
       #define PCF8563                      0xA2 // 定义器件I2C的地址为0xA2
   

  火光:
      您好!
      很感谢您的建议,原来为了偷懒,就用查询方式了,我现在已经将我的I2C改为了中断方式,且一切正常,但是我不明白查询方式时为什么会出错,所以还得在这里请教各位,呵呵!!是不是有点执着了哦~~

使用特权

评论回复
14
汽车电子| | 2007-8-6 21:45 | 只看该作者

这里有有UART和IIC的代码下载

  IIC读写EEPROM,无字节长度限制,
  http://www.shawyoo.com下载中心

使用特权

评论回复
15
hmlxy|  楼主 | 2007-8-7 11:01 | 只看该作者

汽车电子

谢谢这位兄弟

使用特权

评论回复
16
hmlxy|  楼主 | 2007-8-7 11:05 | 只看该作者

zlgARM

 周工:
    您好!
  不知道我的那个I2C得问题怎么样了,是程序问题还是我得处理逻辑有问题?
  期待中.....

使用特权

评论回复
17
hmlxy|  楼主 | 2007-8-10 09:31 | 只看该作者

咋没音讯了

使用特权

评论回复
18
hmlxy|  楼主 | 2007-8-12 14:29 | 只看该作者

仍然期待中~~~~~~

使用特权

评论回复
19
hotpower| | 2007-8-12 14:34 | 只看该作者

I2C都用中断简单明了~~~

使用特权

评论回复
20
wlsui| | 2007-8-12 20:11 | 只看该作者

T1

定时器T1中间的时间10us太快了,改长些试试看
比如改为2s,此时没问题,则说明是T1中断的问题

使用特权

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

本版积分规则

4

主题

22

帖子

1

粉丝