搜索
bottom↓
回复: 14

烦请帮我看看I2C是哪里出错了!谢谢

[复制链接]

出0入0汤圆

发表于 2009-9-15 00:10:09 | 显示全部楼层 |阅读模式
void delay_nop(unsigned int i)
{           
  unsigned int count;
  for(count=0; count<i; count++)
    #asm("nop");
}
// SCL线为高电平SDA从高到低的跳变是I2C总线的开始信号   
int I2C_start()
{
    SDA_DDR=1;          //Set SDA port is out
    SDA_PORT=1;         //Make sure SDA is high
    SCL_PORT=1;
    #asm("nop");
    #asm("nop");
    #asm("nop");   
    if(!SCL_PIN)
        return 0;     //SCL locked low by device
    delay_nop(5);
    SDA_PORT=0;   
    if(SDA_PIN)
        return 0;
    SCL_PORT=0;  
    return 1;
}   
//SCL线为高电平SDA从低到高的跳变是I2C总线的停止信号
void I2C_stop()
{              
    SDA_DDR=1;         //set SDA port is out
    SDA_PORT=0;
    SCL_PORT=1;  
    delay_nop(5);
    SDA_PORT=1;
    delay_nop(5);
    SCL_PORT=0;   
      
}            
   
/***********************************************************************************
***     FUNCTION:I2C 送一个字节的数据
***     INPUT:send_data
***     OUTPUT:nop
***     RETURN:nop
************************************************************************************/
void I2C_send_byte(unsigned char send_data)
{
    unsigned char i;
    SDA_DDR=1;                          //SDA port is out
    for(i = 0;i < 8;i++)
    {
        SCL_PORT=0;
        delay_nop(10);
        if(send_data&0x80)
            SDA_PORT=1;                  //最高位是否为1,为则SDA= 1
        else
            SDA_PORT=0;                  //否则 SDA=0
        delay_nop(5);
        SCL_PORT=1;
        delay_nop(5);
        send_data<<= 1;                 //数据左移一位,进入下一轮送数
    }
    //SCL_PORT=0;                 //
    //SDA_PORT=1;              //等待ack
    delay_nop(5);
}                     

/***********************************************************************************
**  FUNCTION:等待接收ACK 信号,完成一次操作
**  MODIFY DATE:
**  INPUT:nop
**  OUTPUT:nop
**  RETURN:nop
************************************************************************************/
void I2C_receive_ack()
{
    SCL_PORT=0;
    delay_nop(5);
    SDA_DDR=0;              //SDA line is input     
    SDA_PORT=1;         
    delay_nop(5);
    SCL_PORT=1;            //SDA line is pull up
    delay_nop(50);
    while(SDA_PIN);
    SDA_DDR=1;
    SCL_PORT=0;
    delay_nop(5);
}      

/************************************************************************************
**  FUNCTION:接收一个字节的数据
**  MODIFY DATE:
**  INPUT:nop
**  OUTPUT:receive_data
**  RETURN:receive_data
*************************************************************************************/
unsigned char I2C_receive_byte()
{
    unsigned char i;
    unsigned char receive_data = 0;     //返回值
    unsigned char receive_bit = 0;      //每一个clk 接受到的数据
    SCL_PORT=0;
    delay_nop(5);
    SDA_PORT=1;
    SDA_DDR=0;          //SDA line is input
    for(i = 0;i < 8; i++)
    {
        SCL_PORT=1;
        delay_nop(5);
        receive_bit = SDA_PIN;
        delay_nop(5);
        receive_data = ((receive_data << 1) | receive_bit);//将数据依次存入receive_data
        SCL_PORT=0;
        delay_nop(5);
    }   
    return receive_data;
}

/************************************************************************************
*** FUNCTION:接受数据后发送一个ACK 信号
*** MODIFY DATE:
*** INPUT:nop
*** OUTPUT:nop
*** RETURN:nop
************************************************************************************/
void I2C_send_ack()
{
    SCL_PORT=0;
    SDA_DDR=1;      //SDA line is out        
    SDA_PORT=0;
    delay_nop(5);
    SCL_PORT=1;     
    delay_nop(5);
    SCL_PORT=0;
}         

/************************************************************************************
***  FUNCTION: 向I2C写一个小于256的数据
***  MODIFY DATE:
***  INPUT:address and data
***  OUTPUT:nop
***  RETURN:nop
************************************************************************************/
void I2C_write_byte(unsigned char address, unsigned char data)
{                                                            
    if(I2C_start());
    {
        I2C_send_byte(0xa0);    //slave address
        I2C_receive_ack();
        I2C_send_byte(address);
        I2C_receive_ack();  
        I2C_send_byte(data);
        I2C_receive_ack();
        I2C_stop();
   // delay_nop(8000);
   //delay_ms(10);
   }
}

/************************************************************************************
***  FUNCTION: 向I2C读一个字节的数据
***  MODIFY DATE:
***  INPUT:address and data
***  OUTPUT:nop
***  RETURN:nop
************************************************************************************/
unsigned char  I2C_read_byte(unsigned char read_address)
{  
    unsigned char read_data;                                                           
    //启动 送地址
    if(I2C_start());
    {
    I2C_send_byte(0xa0);       //DEVICE DATA :1010_000_0_WRITE
    I2C_receive_ack();
    I2C_send_byte(read_address);
    I2C_receive_ack();
    //启动 改为读操作
    I2C_start();
    I2C_send_byte(0xa1);     //DEVICE DATA:1010_000_0_READ
    I2C_receive_ack();   
   
    //开始读取数据,先低后高,存入int 型
    read_data = I2C_receive_byte();
    //结束时没有ACK
    I2C_stop();
    return read_data;
  // delay_nop(8000);
  //  delay_ms(10);
  }
}

出1000入0汤圆

发表于 2009-9-15 09:06:43 | 显示全部楼层
原则上,在程序初始化时将port赋为0,正常操作时,只改变DDR位,来仿真OC输出。
DDR=0(输入),口线被上拉为1;
DDR=1(输出),口线输出0,
这样才能满足i2c口线OC输出标准

经你的操作:
    SDA_DDR=1;          //Set SDA port is out
    SDA_PORT=1;         //Make sure SDA is high

SDA已经不是OC输出,当然i2c就不对了。

出0入0汤圆

 楼主| 发表于 2009-9-15 12:27:32 | 显示全部楼层
我是用内部的上拉电阻

出0入0汤圆

 楼主| 发表于 2009-9-15 17:18:01 | 显示全部楼层
我按照1楼所讲的改了还是不行,烦请那位高手帮我看看,老板在逼我了,谢谢!

出1000入0汤圆

发表于 2009-9-16 08:36:03 | 显示全部楼层
是AVR单片机吗?是用IO仿真i2c吗?
若是,按1楼“在程序初始化时将port赋为0”,如何使用内部上拉?
必须在外部接4.7K上拉电阻。

出0入0汤圆

发表于 2009-9-16 12:59:21 | 显示全部楼层
你老板一定要求你用模拟吗?为何不用硬件twi?用硬件的比较简单,容易搞好

出0入0汤圆

 楼主| 发表于 2009-9-16 18:49:12 | 显示全部楼层
硬件的IO已经用了,我要两个I2C,所以只能用IO口模拟

出1000入0汤圆

发表于 2009-9-16 19:20:36 | 显示全部楼层
这是我用io模拟i2c master程序,肯定能用,是汇编写的。
点击此处下载 ourdev_481568.doc(文件大小:6K) (原文件名:i2c.doc)

;

出0入0汤圆

 楼主| 发表于 2009-9-16 20:27:20 | 显示全部楼层
谢谢!

出0入0汤圆

 楼主| 发表于 2009-9-16 20:33:01 | 显示全部楼层
DDRB,SDIN                ; force SDA low
rcall        i2c_qp_delay                ; quarter period delay

DDRB 是设置方向的呀

出0入0汤圆

发表于 2009-9-16 20:34:13 | 显示全部楼层
LZ,你在这里问了不少的问题。如果你是靠AVR吃饭的,还是建议你买本我编写的《AVR单片机嵌入式系统原理与应用实践》。里面的例子有2个采用I/O口模拟I2C的,一个低层全部自己写的,一个使用CVAVR内部的I2C函数,还有使用I2C硬件接口的。

另外,不管使用I/O模拟还是硬件的I2C,至少在DATA线上外部加一个5k左右的上拉,可以减少软件设计上的好多麻烦,稳定性也好。这个电阻的成本不能省。

本书中其它部分的东西,也足够你好好琢磨一阵的。

抱歉我的不礼貌和不客气,不过良药苦口。

出20入0汤圆

发表于 2009-9-16 21:16:01 | 显示全部楼层
光是这个IIC总线的问题  他就发了好多重复帖子。 这么久了也不来结帖。


对于这种人  我只能说:  唉。。。。。。。。。。。。。。。。


不知道他为什么比较喜欢把帖子发到马老师专栏呢?

出0入0汤圆

 楼主| 发表于 2009-9-16 22:36:27 | 显示全部楼层
论坛本来就是广开言论,看到11楼的就知道你是哪种最讨厌的,我仔细看了你发帖和回帖也不见得有多少有价值的.鄙视你!!!!!

出20入0汤圆

发表于 2009-9-17 11:51:04 | 显示全部楼层
我也是新手,但我我提问不重复发帖子。问题解决了我会结帖的。

你应该遵守论坛的规定,同一个问题不要重复发帖,发帖子之前先搜索下论坛里有没有相关的帖子,说不定搜一搜你的问题就解决了。



最后说一下你别动不动就鄙视人家。

出0入0汤圆

发表于 2009-9-17 11:53:49 | 显示全部楼层
你们不要争论这些,有气发到我这里。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-2 15:32

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表