打印

哪位大神能帮我看看模拟IIC总线的问题

[复制链接]
9070|19
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
zdp1214|  楼主 | 2010-7-9 10:36 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
//******************************************************//
本程序想在飞思卡尔单片机上实现IIC总线传输 从机是AT24C02
原本是一个51的程序,我将他移植到飞思卡尔上可是总是不行(改了有一周了) 我水平有限
其中https://bbs.21ic.com/icview-112527-1-1.html我参照13楼张明峰的例子又做了改动,我延时程序为Delay_us为1us(示波器检验过)//我用PORTA_PA1来模拟SDA口,我用PORTA_PA2来模拟SCL口,两口均加有10Ω的上拉电阻,显示部分使用串口调试
我又特别在两次启动总线前,增加了个3ms左右的延时,该做的都做了到底哪里出现问题了,从机有时候都没有反应(ack==0)
//******************************************************//
听说21IC有好多单片机的大神,能帮我一下么?到底是什么错误?怎么改?我只能给到50分我都给了,就盼望出现大神

指南针1.rar

245.27 KB

相关帖子

沙发
zdp1214|  楼主 | 2010-7-9 10:38 | 只看该作者
给大神们贴出我的程序(也可以下载)
/**********************************************************/

/*******************************************************************
                     起动总线函数
函数原型: void  Start_I2c();
功能:       启动I2C总线,即发送I2C起始条件.
********************************************************************/
void Start_I2c()
{
    SCL_in;
    SDA_in;
    Delay_us();
    Delay_us();
    Delay_us();
    Delay_us();
    Delay_us();
    SDA_out;
    PORTA_PA1=0;
    Delay_us();
    Delay_us();
    Delay_us();
    Delay_us();
    Delay_us();/*起始条件建立时间大于4.7us,延时*/
    SCL_out;
    PORTA_PA2=0;      /*发送起始信号*/
    Delay_us();
    Delay_us();/* 起始条件锁定时间大于4μs*/
}
/*******************************************************************
                      结束总线函数
函数原型: void  Stop_I2c();
功能:       结束I2C总线,即发送I2C结束条件.
********************************************************************/
void Stop_I2c()
{
    SDA_out;
    Delay_us();    /*发送结束条件的时钟信号*/
    SCL_in;
    Delay_us();
    Delay_us();
    Delay_us();
    Delay_us();
    Delay_us();    /*结束条件建立时间大于4μs*/
    SDA_in;
    Delay_us();
    Delay_us();
    Delay_us();
    Delay_us();
}
/*******************************************************************
                 字节数据传送函数
函数原型: void  SendByte(uchar c);
功能:  将数据c发送出去,可以是地址,也可以是数据,发完后等待应答,并对
     此状态位进行操作.(不应答或非应答都使ack=0 假)
     发送数据正常,ack=1; ack=0表示被控器无应答或损坏。
********************************************************************/
void  SendByte(uchar c)
{
    uchar BitCnt;
    for(BitCnt=0;BitCnt<8;BitCnt++)  //要传送的数据长度为8位
    {
        if((c<<BitCnt)&0x80)
        {
            SDA_in;
        }
        else
        {
            SDA_out;
        }
        Delay_us();
        SCL_in;
        Delay_us();
        Delay_us();
        Delay_us();
        Delay_us();
        Delay_us();         //保证时钟高电平周期大于4μs
        SCL_out;
    }
    Delay_us();
    Delay_us();
    SDA_in;
    Delay_us();
    Delay_us() ;
    SCL_in;
    Delay_us();
    Delay_us();
    Delay_us();
    if(PORTA_PA1==1)
        ack=0;
    else
        ack=1;        /*判断是否接收到应答信号*/
    SCL_out;
    Delay_us();
    Delay_us();
}
void Ack_I2c(byte a)
{
  if(a==0){
    //要规范 要加括号!!!
    SDA_out;//在此发出应答或非应答信号
  }
  else{
    SDA_in;
  }
  Delay_us();
  Delay_us();  
  Delay_us();      
  SCL_in;
  Delay_us();  
  Delay_us();                      //时钟低电平周期大于4μs
  Delay_us();  
  Delay_us();  
  Delay_us();   
  SCL_out;                     //清时钟线,钳住I2C总线以便继续接收
  Delay_us();  
  Delay_us();      
}
uchar  RcvByte()
{
  uchar retc;
  uchar BitCnt;
  
  retc=0;
  SDA_in;                  
  for(BitCnt=0;BitCnt<8;BitCnt++)
      {
        Delay_us();         
        SCL_out;                  
        Delay_us();
        Delay_us();   
        Delay_us();
        Delay_us();
        Delay_us();
        SCL_in;                  
        Delay_us();
        Delay_us();
        retc=retc<<1;
        Delay_us();
        if(PORTA_PA1==1)retc=retc+1;  //读数据位,接收的数据位放入retc中
        Delay_us();
        Delay_us();
      }
  //SCL_out;   
  Delay_us();
  Delay_us();
  return(retc);
}
/*====================================================================================
功能: I2C读出多个数据
输入参数:
      sla  : I2C地址
   suba : 数据的地址
   *s   : 指向读出的内容
   no   : 读出数据的个数
         如果返回1表示操作成功,否则操作有误。
注意:   使用前必须已结束总线。
========================================================================================*/
uchar  I2C_Read(uchar sla,uchar suba,uchar *s,uchar no)
{
   uchar i;
   Start_I2c();                  //启动总线
   SendByte(sla);                //发送器件地址
   if(ack==0)return(2);
   SendByte(suba);               
   if(ack==0)return(3);
  Delay_ms();
    Delay_ms();
   Start_I2c();            //重新启动总线
   SendByte(sla+1);
   if(ack==0)return(4);
    for(i=0;i<no-1;i++)
   {   
     *s=RcvByte();               //保存 读出数据
      Ack_I2c(0);                //发送应答位
     s++;
   }
   *s=RcvByte();  
   Ack_I2c(1);                  //发送非应位
   Stop_I2c();                   //结束总线
   return(1);
}
//*******************************************************

使用特权

评论回复
板凳
zdp1214|  楼主 | 2010-7-9 10:41 | 只看该作者
其中宏定义是这样子的
#define SDA_in  DDRA_DDRA1=0//输入
#define SDA_out DDRA_DDRA1=1//输出
#define SCL_in  DDRA_DDRA2=0
#define SCL_out DDRA_DDRA2=1



80M总线频率
//********************主函数是这样子的******************  
while(1){
   Delay_ms();
   Delay_ms();
   Delay_ms();
   debug=I2C_Read(CompassI2C_Addr,0x00,nIIC_RD,8);   //读出8个
   Delay_ms();
   Delay_ms();
   Delay_ms();
   put_norm_int(debug);//串口输出模块函数,输出debug的值,居然没有一次得"1"的,也就是没有一次IIC函数执行完毕的,总是没有响应
   }

使用特权

评论回复
地板
ayb_ice| | 2010-7-9 10:53 | 只看该作者
因为FS的MCU IO和51的有很大不同
所以模拟是有点区别的,我以前也搞了很久

记得那时是切换IO前先初始化一下IO数据,切换后再发数据

...

使用特权

评论回复
5
chyb2002| | 2010-7-9 10:55 | 只看该作者
1# zdp1214
呵呵,拿上示波器看波形不就知道了。我当初就是这样做的,可能是IO方向需要切换下的。

使用特权

评论回复
6
zdp1214|  楼主 | 2010-7-9 11:45 | 只看该作者
有能再帮助我一下的么 我都快疯掉了

使用特权

评论回复
7
hxlwjn| | 2010-7-9 13:10 | 只看该作者
作为IIC主机,scl应该一直配置为输出,我看LZ一会把SCL设为输出,一会又把它作为输入,完全没有必要。
有些地方时序也不对,例如,Stop_I2c的正确时序应该是这样的:
   SDA_OUT;
    SCL_OUT;
    Delay_us();    /*发送结束条件的时钟信号*/
    SCL_HIGHT;
    SDA_LOW;
    Delay_us();
    Delay_us();
    Delay_us();
    Delay_us();
    Delay_us();    /*结束条件建立时间大于4μs*/
    SDA_HIGHT;
    Delay_us();
    Delay_us();
    Delay_us();
    Delay_us();

使用特权

评论回复
8
hxlwjn| | 2010-7-9 13:13 | 只看该作者
又看了下LZ的程序,IIC开始和结束时序都不对,建议你先看看IIC总线规范。

使用特权

评论回复
9
hxlwjn| | 2010-7-9 13:17 | 只看该作者
另外,我是第一次听说IIC的上拉电阻用10欧的。

使用特权

评论回复
10
mon200| | 2010-7-9 13:25 | 只看该作者
我想,对单片机而言,软件和硬件的有机统一很重要,可以考虑修改一下程序,我感觉10欧做上拉电阻有些小。

使用特权

评论回复
11
wzl-xx@163.com| | 2010-7-9 13:37 | 只看该作者
看看I2C资料,I2C总线延时是否准确。

使用特权

评论回复
12
sxdxy| | 2010-7-9 13:42 | 只看该作者
I2C在5V标准下上拉电阻是10Kohm,这10ohm也太夸张了

使用特权

评论回复
13
ayb_ice| | 2010-7-9 14:08 | 只看该作者
只怕10OHM电阻会把IO烧坏

使用特权

评论回复
14
Macro_Yuan| | 2010-7-9 20:13 | 只看该作者
上拉电阻最小也不能低于5Kohm吧

使用特权

评论回复
15
linqing171| | 2010-7-10 00:57 | 只看该作者
8楼说的说法完全错误,楼主是对的。
对于输出1就是变成输入,对于输出0,就是输出。 这样才能组成i2c “总线”。
不懂i2c规范就别忽悠。

把你的delay_us 贴出来看看。怀疑速度太快,你用示波器看看你的上拉电阻把总线拉高的波形可以么。
看你的速度也是比较快的,电路上在一个板子上么?有没有共地?

如果低电平驱动能力强,上拉电阻可以小到1k,当然能力越强可以越小,上升沿也会越好。
因为按照 i2c 规范,高电平是上拉电阻拉起来的。

实际使用中,如果速度临界,多板子共地不好的话,有个地方也会出现误stop,就是写ee的时候,ee的应答后的那个时钟会和ee释放应答同时出现。建议在 ack=1; 这句前你把SDA输出0,等你的时钟释放了后,把SDA再释放。

使用特权

评论回复
16
zdp1214|  楼主 | 2010-7-10 09:59 | 只看该作者
能详细说下么?我的QQ:906116829 我是楼主,加我一下

使用特权

评论回复
17
wdzzq| | 2010-7-10 10:45 | 只看该作者
不懂,过来学习的。

使用特权

评论回复
18
zdp1214|  楼主 | 2010-7-10 11:37 | 只看该作者
我要感谢大家 我调出来了,我的延时小的有点到延时极限了,所以不行,尤其感谢最后一个回复给了我启发

使用特权

评论回复
19
戒指320| | 2010-7-11 17:20 | 只看该作者
本帖最后由 戒指320 于 2010-7-11 17:27 编辑

ok  ok

使用特权

评论回复
20
cecwxf| | 2012-3-18 17:37 | 只看该作者
right

使用特权

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

本版积分规则

3

主题

8

帖子

1

粉丝