发新帖我要提问
12
返回列表
打印

问题解决!谢谢各位大虾!感谢自己的**!

[复制链接]
楼主: cumtgirl
手机看帖
扫描二维码
随时随地手机跟帖
21
cumtgirl|  楼主 | 2008-3-22 16:39 | 只看该作者 回帖奖励 |倒序浏览

现在又不工作了

早上来了工作好好的,到了中午又不行了!貌似这个程序或者传感器只工作半天!

使用特权

评论回复
22
hotpower| | 2008-3-22 17:59 | 只看该作者

估计楼主真没搞清楚I2C协议及串行通讯主从机的关系

实际我给的例程是PC的并口模拟I2C协议,用什么语言并不重要.

楼主的类似以下的程序全部有问题~~~
while(i--)

   I2CStart();
   I2CSendByte(ControlByte&0xfe);//指定芯片,此次必定为写
   if(!WaitAck())              //涵数返回一个1为成功
     continue;                      //结束写操作,并i-1后,再来一次
//...
     if(errorflag==error) //经过写完后,如果最后errorflag标志为1,则表示有错误
           continue;                  //结束写操作,并i-1后,再来一次

等等都有问题.
I2C的通讯状态很规矩,每个状态都有详细的定义.
gccavr中的定义很规范(atmel称I2C为TWI)
enum enum_TWIState
{
/* Master */
    TW_START =                0x08,
    TW_REP_START=        0x10,
/* Master Transmitter */
    TW_MT_SLA_ACK=        0x18,
    TW_MT_SLA_NACK=        0x20,
    TW_MT_DATA_ACK=        0x28,
    TW_MT_DATA_NACK=        0x30,
    TW_MT_ARB_LOST=        0x38,
/* Master Receiver */
    TW_MR_ARB_LOST=        0x38,
    TW_MR_SLA_ACK=        0x40,
    TW_MR_SLA_NACK=        0x48,
    TW_MR_DATA_ACK=        0x50,
    TW_MR_DATA_NACK=        0x58,
/* Slave Transmitter */
    TW_ST_SLA_ACK=        0xA8,
    TW_ST_ARB_LOST_SLA_ACK=    0xB0,
    TW_ST_DATA_ACK=        0xB8,
    TW_ST_DATA_NACK=        0xC0,
    TW_ST_LAST_DATA=        0xC8,
/* Slave Receiver */
    TW_SR_SLA_ACK=        0x60,
    TW_SR_ARB_LOST_SLA_ACK=    0x68,
    TW_SR_GCALL_ACK=        0x70,
    TW_SR_ARB_LOST_GCALL_ACK=   0x78,
    TW_SR_DATA_ACK=        0x80,
    TW_SR_DATA_NACK=        0x88,
    TW_SR_GCALL_DATA_ACK=    0x90,
    TW_SR_GCALL_DATA_NACK=    0x98,
    TW_SR_STOP=                0xA0,
/* Misc */
    TW_NO_INFO=                0xF8,
    TW_BUS_ERROR=        0x00,
    TW_READ=                1,
    TW_WRITE=                    0
};

不管I2C出现的任何错误,主机都应该发送I2CStop(),而不应该像楼主用continue重试.

因为从机是根据主机的节拍即时钟进行工作即状态转移的,主机发现的错误从机并不知晓.

所以正确地容错应该是主机发送I2CStop()停止从机的工作后,使从机的状态归零.
然后再I2CStart()重新通讯.


再者I2C的调试实际很简单,应该在发送I2CStart()和从地址后,在接收应答处
设置个断点.
若裸奔应该在此处加个LedOn()或LedOff()看看到底收到从机的应答信号ACK否.

若收不到就应该检查时序,否则一切都白搭~~~

建议I2C用状态机,虽然在模拟I2C上很少使用,但它能使通讯更可靠~~~
相关链接:https://bbs.21ic.com/club/bbs/showEssence.asp?id=9000&page=1

使用特权

评论回复
23
zhang123| | 2008-3-22 18:46 | 只看该作者

我也奉上 i2c:写入按键次数到24c02,并读出显示在4个led上。

写入按键次数到24c02,并读出显示在4个led上。
//写入按键次数到24c02,并读出显示在4个led上。
#define uchar unsigned char //定义一下方便使用
#define uint  unsigned int
#define ulong unsigned long
#include <reg52.h>     //包括一个52标准内核的头文件

char code dx516[3] _at_ 0x003b;//这是为了仿真设置的

#define    WriteDeviceAddress 0xa0      //定义器件在IIC总线中的地址
#define    ReadDviceAddress 0xa1
sbit    SCL=P2^7;
sbit    SDA=P2^6;

sbit     P10=P1^0;
sbit    K1=P3^2;

//定时函数
void DelayMs(uint number) 
{
    uchar temp;
//    for(;number!=0;number--) 
    //{
     ;
//    }    
    while(number--)
        for(temp=112;temp!=0;temp--);
}

//开始总线
void Start() 
{
    SDA=1;
    SCL=1;
    SDA=0;
    SCL=0;
}

//结束总线
void Stop() 
{
    SCL=0;
    SDA=0;
    SCL=1;
    SDA=1;
}


//发ACK0
void NoAck() 
{
    SDA=1;
    SCL=1;
    SCL=0;
}

//测试ACK
bit TestAck() 
{
    bit ErrorBit;
    SDA=1;
    SCL=1;
    ErrorBit=SDA;
    SCL=0;
    return(ErrorBit);
}

//写入8个bit到24c02
Write8Bit(uchar input) 
{
    uchar temp;
    for(temp=8;temp!=0;temp--) 
    {
        SDA=(bit)(input&0x80);       //
        SCL=1;
        SCL=0;
        input=input<<1;
    }
}

//写入一个字节到24c02中
void Write24c02(uchar ch,uchar address) 
{
    Start();
    Write8Bit(WriteDeviceAddress);
    TestAck();
    Write8Bit(address);
    while (!TestAck());

    Write8Bit(ch);
    TestAck();
    
    Stop();
    DelayMs(10);
}

//从24c02中读出8个bit
uchar Read8Bit() 
{
    uchar temp,rbyte=0;
    for(temp=8;temp!=0;temp--) 
    {
        SCL=1;
        rbyte=rbyte<<1;
        rbyte=rbyte|((unsigned char)(SDA));
        SCL=0;
    }
    return(rbyte);
}

//从24c02中读出1个字节
uchar Read24c02(uchar address) 
{
    uchar ch;

    Start();
    Write8Bit(WriteDeviceAddress);
    TestAck();
    Write8Bit(address);
    TestAck();
    Start();
    Write8Bit(ReadDviceAddress);
    TestAck();
    ch=Read8Bit();
    NoAck();
    Stop();
    return(ch);
}

 //写入按键次数到24c02,并读出来显示在4个LED上

void main(void)    // 主程序
{
    uchar c1,c2;

    while(1)
    {
        c1=Read24c02(0x01);     //读出24c02第一个地址数据
        P1=c1;                //显示在P1口的4个LED上

        if(!K1)      //按键处理
        {
            c1++;        //值加1
            Write24c02(c1,0x01);    //重新写入24c02

            while(!K1);             //等待按键松开
            for(c2=0;c2<250;c2++);    //松开按键去抖
        }        
    }
}

使用特权

评论回复
24
一从陶令| | 2008-3-22 22:22 | 只看该作者

不会你的I2C从机忘接电源了吧

哈哈,不会你的I2C从机忘接电源了吧.I2C器件功率很小,SCL/SDA上的高电平信号通过钳位二极管给VCC供电,往往能支持一两个字节的读写,多字节连续读就不行了.以前一哥们曾犯过这个错.

如果不是的话一定是时序有问题,不知道为什么LZ一直不肯用示波器调试一下,就那么难吗?

使用特权

评论回复
25
cumtgirl|  楼主 | 2008-3-23 10:07 | 只看该作者

re

我的这个传感器里面是集成了一个24C02,它里面存的是校准参数。运行时应该先读出这11个校准参数,然后再读出AD数字值(是个数字传感器)。顺便说一下:我的读AD值代码部分一直都是好好运行的。而读常数部分却不正常!

使用特权

评论回复
26
cumtgirl|  楼主 | 2008-3-24 11:46 | 只看该作者

发现问题了:

有时能收到从机的ack信号,有时不能!

使用特权

评论回复
27
mikesullen| | 2008-3-25 11:51 | 只看该作者

还是建议你们公司买一个示波器吧

虽然我不是卖示波器的。。。。

使用特权

评论回复
28
cumtgirl|  楼主 | 2008-3-25 18:09 | 只看该作者

问题解决!谢谢各位大虾!感谢自己的**!

公司的器件有问题,但是总算还是被容错能力较强的软件克服了!

使用特权

评论回复
29
cumtgirl|  楼主 | 2008-3-25 22:17 | 只看该作者

贴代码:希望有助后来人!

在发完0xa0,片内adddress,0xa1之后,因为我的函数在发完这三个字节后,收不到ack信号,因此,我分别增加了
if(!WaitAck())                                    //涵数返回一个1为成功
   {
     I2CStop();                                      //重建启动信号,恢复正常时序!!!
     delay(200);
     I2CStart();
     I2CSendByte(0xa0);      
   } 见下面:             
unsigned long RIIC(signed long *DataBuff,char ByteQuantity,unsigned int Address,unsigned char ControlByte)
{
 unsigned char errorflag=error;                      //错误标志位,1为错误,0为正确
 unsigned char i;                                    //i为允许本次操作的最大次数
  i=10;
 SCLOUT;                                             //时钟口长设为输出
 while(i--)
 { 
   I2CStart();
   nop_();
   
   I2CSendByte(0xa0);                                //指定芯片,此次必定为写
   if(!WaitAck())                                    //涵数返回一个1为成功
   {
     I2CStop();                                      //重建启动信号,恢复正常时序!!!
     delay(200);
     I2CStart();
     I2CSendByte(0xa0);      
   }                                                 //结束写操作,并i-1后,再来一次
   
   I2CSendByte((unsigned char)Address);              //发送片内地址
   if(!WaitAck())                                    //数返回一个1为成功                            
   {
          I2CStop(); 
          delay(200);
          I2CStart();
          I2CSendByte(Address);    
   }                                     
 //----------------------------------------------------已经选定好IC   
        /*I2CStart();*/                             //开始       
        I2CSendByte(ControlByte/*0xa1*/);
        delay(200);
        if(!WaitAck())                              //涵数返回一个1为成功
        {
          I2CStop(); 
          delay(200);
          I2CStart();
          I2CSendByte(ControlByte/*0xa1*/);          
        }                                             
        
     while(--ByteQuantity)                          //读入ByteQuantity个数字节
           {
             *DataBuff++=I2CReceiveByte();          //连续读入ByteQuantity个数据
              SendAck();
           }                                        //主机向从机发出应答,表示主机已接收            
        *DataBuff=I2CReceiveByte();                 //读入最后个数据
     SendNotAck();                                  //最后发出不应答信号(位),表示主机不再读了.
     errorflag=right;                               //向错误标志位写0(right),表示读数据正确.
     break;                                         //读操作完成
     }
 I2CStop();                                         //停止,结束IIC总线
 return(errorflag);                                 //返回操作成败标志
}

使用特权

评论回复
30
gxs64| | 2008-3-26 10:30 | 只看该作者

公司的器件有问题?

公司的器件有问题----你是如何证明的?

使用特权

评论回复
31
cumtgirl|  楼主 | 2008-3-26 17:55 | 只看该作者

我单步跟踪的时候发现的

有的器件能顺利执行RIIC,再换一个就不行了。

使用特权

评论回复
32
cumtgirl|  楼主 | 2008-3-28 08:55 | 只看该作者

我的解决方法基本意思就是:

我的解决方法基本意思就是:在可能收不到ack的地方,(I2Cstop())stopIIC总线,再重新启动IIC(I2Cstart()),再执行写操作。不知道对大家是否有帮助

使用特权

评论回复
33
cumtgirl|  楼主 | 2008-4-2 08:45 | 只看该作者

发现一个问题:程序运行很稳定,但是读出来的数都是少了

原来255的地方,读出来是127。原来是6的地方,读出是3...如何办?

使用特权

评论回复
34
fengsz| | 2012-6-28 15:41 | 只看该作者
没延时吧

使用特权

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

本版积分规则