搜索
bottom↓
回复: 13

刚刚调试通过的ATmega128 I2C软件包

[复制链接]

出0入0汤圆

发表于 2008-4-26 15:15:50 | 显示全部楼层 |阅读模式
程序是在51 I2C软件包基础上修改的,直接调用#include <mega128IIC.h>再修改一下端口定义即可。
ATmega128 外部8MHz 编译器ICCAVR
有几个问题请教各位大侠:
1、读写过程中一直没有对PE7(SDA)进行操作,如果在PE7为输出状态下,再加一条指令将PE7=0是不是能更好一些?
2、程序中的延时函数觉得写的不算好,用示波器观察最后只能是现在的这个延时函数精确到2us,请各位大侠对整个程序补充一下,谢谢。
3、怕8MHZ太快,在对端口操作后都加了asm("nop");这样有必要吗?


/********************************************************************
                  ATmega128模拟I2C软件包
    文件名:mega128IIC.h
    相关文件:mega128IIC.h
    功能说明:本模拟I2C软件包包含了I2C操作的底层函数,如发送数据及接收
数据,应答位发送,并提供了几个直接面对器件的操作函数,它很方便的与用户程
序连接并扩展.....  
********************************************************************/
#ifndef  _mega128IIC_
#define  _mega128IIC_

#define  uchar     unsigned char
#define  uint      unsigned int   

/*AVR单片机I/O口模拟I2C总线时必须在外部连接上拉电阻
这样可通过改变I/O口输入输出方向的方式来设置高低电平
输出口保持不变(0)
此时如DDRX寄存器为1则变成输出0
若DDRX为0,则I/O口呈高阻态,但因外部的上拉电阻,总线相
当于设置高,即通过设置DDRX的方式控制总线的高低*/
#define  SCL       PE6              //模拟I2C时钟控制位
#define  SDA       PE7              //模拟I2C数据传送位
#define  SET_SCL   DDRE&=~(1<<SCL)
#define  CLR_SCL   DDRE|=1<<SCL
#define  SET_SDA   DDRE&=~(1<<SDA)   //PE7输入状态下,由外部上拉电阻置1,故SDA=1
#define  CLR_SDA   DDRE|=1<<SDA      //初始化PE7=0;PE7输出状态下保持为0
#define  SDA_PIN   (PINE&(1<<SDA))   //SDA应答信号输入
uchar    ack;                             /*应答标志位*/

/*******************************************************************
名    称:IIC_delay2us()              
调    用: void  IIC_delay2us();  
功    能: 调用一次延时2us
********************************************************************/
void IIC_delay2us(void)//示波器测得此函数被调用一次用时2us
{
  asm("nop");
  asm("nop");
  asm("nop");
  asm("nop");
  asm("nop");
  asm("nop");
}
/*******************************************************************
名    称:Start_I2c()              
调    用: void  Start_I2c();  
功    能: 启动I2C总线,即发送I2C起始条件.  
********************************************************************/
void Start_I2c()
{
  SET_SDA;           /*发送起始条件的数据信号*/
  asm("nop");
  asm("nop");
  SET_SCL;
  IIC_delay2us();            /*起始条件建立时间大于4.7us,延时*/
  IIC_delay2us();
  IIC_delay2us();
  CLR_SDA;                   /*发送起始信号*/
  IIC_delay2us();           /* 起始条件锁定时间大于4us*/
  IIC_delay2us();
  asm("nop");
         
  CLR_SCL;                   /*钳住I2C总线,准备发送或接收数据 */
  IIC_delay2us();
}
/*******************************************************************
                      结束总线函数               
函数原型: void  Stop_I2c();  
功能:     结束I2C总线,即发送I2C结束条件.  
********************************************************************/
void Stop_I2c()
{
  CLR_SDA;                  /*发送结束条件的数据信号*/
  IIC_delay2us();           /*发送结束条件的时钟信号*/
  SET_SCL;                  /*结束条件建立时间大于4μs*/
  IIC_delay2us();
  IIC_delay2us();
  asm("nop");
  SET_SDA;                  /*发送I2C总线结束信号*/
  IIC_delay2us();
  IIC_delay2us();
}
/*******************************************************************
                 字节数据发送函数               
函数原型: void  SendByte(uchar c);
功能:     将数据c发送出去,可以是地址,也可以是数据,发完后等待应答,并对
          此状态位进行操作.(不应答或非应答都使ack=0)     
               发送数据正常,ack=1; ack=0表示被控器无应答或损坏。
********************************************************************/
void  SendByte(uchar c)               //c为要发送的数据
{  
        uchar BitCnt;
    for(BitCnt=0;BitCnt<8;BitCnt++)  /*要传送的数据长度为8位*/
    {
       if((c<<BitCnt)&0x80)
           {   
               SET_SDA;           /*判断发送位*/
                   asm("nop");
       }
           else
       {          
               CLR_SDA;
           asm("nop");
           }                  
       IIC_delay2us();
       SET_SCL;               /*置时钟线为高,通知被控器开始接收数据位*/
       IIC_delay2us();
       IIC_delay2us();              /*保证时钟高电平周期大于4μs*/
       asm("nop");          
       CLR_SCL;
           asm("nop");
    }  
    IIC_delay2us();
    SET_SDA;                  /*8位发送完后释放数据线,准备接收应答位*/
    IIC_delay2us();  
    SET_SCL;                  //时钟线置1为接收应答位做准备
    IIC_delay2us();
    IIC_delay2us();
    if(SDA_PIN)
        {
        ack=0;   //应答失败     
        asm("nop");
    }
        else
        {
        ack=1;   //应答成功           /*判断是否接收到应答信号*/
        asm("nop");
        }
        CLR_SCL;
    IIC_delay2us();
}
/*******************************************************************
                 字节数据接收函数               
函数原型: uchar  RcvByte();
功能:            用来接收从器件传来的数据,并判断总线错误(不发应答信号),
          发完后请用应答函数应答从机。  
********************************************************************/       
uchar  RcvByte()                 //其后紧跟应答函数Ack_I2c()
{  
          uchar retc;
      uchar BitCnt;
          retc=0;
          //DDRE|=0x40;               //设置时钟线SCL为输出
      //DDRE&=0x7f;               //设置数据线SDA为输入
      SET_SDA;                             /*置数据线为输入方式*/
          asm("nop");
      for(BitCnt=0;BitCnt<8;BitCnt++)
      {          
                  IIC_delay2us();           
          CLR_SCL;                  /*置时钟线为低,准备接收数据位*/
          IIC_delay2us();
          IIC_delay2us();                 /*时钟低电平周期大于4.7μs*/
          IIC_delay2us();
          SET_SCL;                  /*置时钟线为高使数据线上数据有效*/
          IIC_delay2us();
                            
          retc=retc<<1;
          if(SDA_PIN)
                      retc=retc+1;  /*读数据位,接收的数据位放入retc中 */
          IIC_delay2us();
      }  
      CLR_SCL;   
      IIC_delay2us();
      return(retc);
}
/********************************************************************
                     应答子函数
函数原型:  void Ack_I2c(uchar a);
功能:      主控器进行应答信号(可以是应答或非应答信号,由位参数a决定)
********************************************************************/
void Ack_I2c(uchar a)
{       
        if(a==0)
         CLR_SDA;//应答信号                 /*在此发出应答或非应答信号 */
    else
        SET_SDA; //非应答信号
    IIC_delay2us();
    IIC_delay2us();      
    SET_SCL;
    IIC_delay2us();
    IIC_delay2us();                   /*时钟低电平周期大于4μs*/
    IIC_delay2us();
     
    CLR_SCL;                     /*清时钟线,钳住I2C总线以便继续接收*/
    IIC_delay2us();   
}
/*******************************************************************
                 向无子地址器件发送字节数据函数               
函数原型: bit  ISendByte(uchar sla,uchar c);  
功能:     从启动总线到发送地址,数据,结束总线的全过程,从器件地址sla.
          如果返回1表示操作成功,否则操作有误。
注意:    使用前必须已结束总线。
********************************************************************/
uchar ISendByte(uchar sla,uchar c)
{
   Start_I2c();               /*启动总线*/
   SendByte(sla);             /*发送器件地址*/
   if(ack==0)return(0);
   SendByte(c);               /*发送数据*/
   if(ack==0)return(0);
   Stop_I2c();                /*结束总线*/
   return(1);
}
/*********************************************************************************************************************
/*******************************************************************
                    向有子地址器件发送多字节数据函数               
函数原型: bit  ISendStr(uchar sla,uchar suba,ucahr *s,uchar no);  
功能:     从启动总线到发送地址,子地址,数据,结束总线的全过程,从器件
          地址sla,子地址suba,发送内容是s指向的内容,发送no个字节。
          如果返回1表示操作成功,否则操作有误。
注意:    使用前必须已结束总线。
********************************************************************
*********************************************************************************************************************/
uchar ISendStr(uchar sla,uchar suba,uchar *s,uchar no)
{
   uchar i;
   Start_I2c();               /*启动总线*/
   SendByte(sla);             /*发送器件地址*/
   if(ack==0)
       return(0);
   SendByte(suba);            /*发送器件子地址*/
   if(ack==0)
       return(0);

   for(i=0;i<no;i++)
   {   
       SendByte(*s);          /*发送数据*/
       if(ack==0)
               return(0);
       s++;
   }
   Stop_I2c();                /*结束总线*/
   return(1);
}
/*******************************************************************
                    向无子地址器件发送多字节数据函数               
函数原型: bit  ISendStr(uchar sla,ucahr *s,uchar no);  
功能:     从启动总线到发送地址,子地址,数据,结束总线的全过程,从器件
          地址sla,发送内容是s指向的内容,发送no个字节。
          如果返回1表示操作成功,否则操作有误。
注意:    使用前必须已结束总线。
********************************************************************/
uchar ISendStrExt(uchar sla,uchar *s,uchar no)
{
   uchar i;

   Start_I2c();               /*启动总线*/
   SendByte(sla);             /*发送器件地址*/
   if(ack==0)return(0);

   for(i=0;i<no;i++)
   {   
     SendByte(*s);            /*发送数据*/
     if(ack==0)return(0);
     s++;
   }
   Stop_I2c();                /*结束总线*/
   return(1);
}
/*******************************************************************
                    向无子地址器件读字节数据函数               
函数原型: bit  IRcvByte(uchar sla,ucahr *c);  
功能:     从启动总线到发送地址,读数据,结束总线的全过程,从器件地
          址sla,返回值在c.
           如果返回1表示操作成功,否则操作有误。
注意:    使用前必须已结束总线。
********************************************************************/
uchar IRcvByte(uchar sla,uchar *c)
{
   Start_I2c();                /*启动总线*/
   SendByte(sla+1);            /*发送器件地址*/
   if(ack==0)return(0);
   *c=RcvByte();               /*读取数据*/
   Ack_I2c(1);                 /*发送非就答位*/
   Stop_I2c();                 /*结束总线*/
   return(1);
}
/*********************************************************************************************************************
*******************************************************************
                    向有子地址器件读取多字节数据函数               
函数原型: bit  ISendStr(uchar sla,uchar suba,ucahr *s,uchar no);  
功能:     从启动总线到发送地址,子地址,读数据,结束总线的全过程,从器件
          地址sla,子地址suba,读出的内容放入s指向的存储区,读no个字节。
           如果返回1表示操作成功,否则操作有误。
注意:    使用前必须已结束总线。
********************************************************************
*********************************************************************************************************************/
uchar IRcvStr(uchar sla,uchar suba,uchar *s,uchar no)
{
     uchar i;
     Start_I2c();                  /*启动总线*/
     SendByte(sla);                /*发送器件地址*/
     if(ack==0)
         return(0);
     SendByte(suba);               /*发送器件子地址*/
     if(ack==0)
         return(0);

     Start_I2c();                                 /*重新启动总线*/
     SendByte(sla+1);              //sla+1=0xA3,读地址
     if(ack==0)
         return(0);
     for(i=0;i<no-1;i++)
     {   
        *s=RcvByte();               /*发送数据*/
        Ack_I2c(0);                 /*发送应答位*/  
        s++;
     }
     *s=RcvByte();
     Ack_I2c(1);                   /*发送非应答位*/
     Stop_I2c();                   /*结束总线*/
     return(1);
}
/*******************************************************************
                    向无子地址器件读取多字节数据函数               
函数原型: bit  ISendStrExt(uchar sla,ucahr *s,uchar no);  
功能:     从启动总线到发送地址,读数据,结束总线的全过程.
          从器件地址sla,读出的内容放入s指向的存储区,
          读no个字节。如果返回1表示操作成功,否则操作有误。
注意:    使用前必须已结束总线。
********************************************************************/
uchar IRcvStrExt(uchar sla,uchar *s,uchar no)
{
   uchar i;
   Start_I2c();
   SendByte(sla+1);
   if(ack==0)return(0);

   for(i=0;i<no-1;i++)
   {   
      *s=RcvByte();               /*发送数据*/
      Ack_I2c(0);                 /*发送就答位*/  
      s++;
   }
   *s=RcvByte();
   Ack_I2c(1);                    /*发送非应位*/
   Stop_I2c();                    /*结束总线*/
   return(1);
}
#endif

阿莫论坛20周年了!感谢大家的支持与爱护!!

你熬了10碗粥,别人一桶水倒进去,淘走90碗,剩下10碗给你,你看似没亏,其实你那10碗已经没有之前的裹腹了,人家的一桶水换90碗,继续卖。说白了,通货膨胀就是,你的钱是挣来的,他的钱是印来的,掺和在一起,你的钱就贬值了。

出0入0汤圆

发表于 2008-6-11 22:21:52 | 显示全部楼层
谢谢楼主分享,注释很详细,可以更好的理解一下具体编写过程

出0入0汤圆

发表于 2008-6-11 22:26:11 | 显示全部楼层
做个记号

出0入0汤圆

发表于 2008-6-12 12:25:32 | 显示全部楼层
谢谢楼主额,喜欢。。。注释很详细

出0入0汤圆

发表于 2008-6-12 14:01:30 | 显示全部楼层
支持!!

出0入0汤圆

发表于 2008-6-13 14:59:30 | 显示全部楼层
我看看

出0入0汤圆

发表于 2010-6-4 15:24:31 | 显示全部楼层
楼主 您的程序 我移植怎么时序不对啊  ,  我不知道为什么, 但是我觉得你得程序很详细也很容易明白 。

出0入0汤圆

发表于 2010-6-11 00:09:24 | 显示全部楼层
顶顶,正是需要

出0入0汤圆

发表于 2012-3-1 16:25:00 | 显示全部楼层
什么乱七八糟的

出0入0汤圆

发表于 2013-9-3 19:42:55 | 显示全部楼层
受用了,正需要,真是雪中送炭,程序没有问题,验证过了,谢谢分享!

出0入0汤圆

发表于 2013-9-3 21:00:53 | 显示全部楼层
谢谢楼主额,喜欢。。。

出0入0汤圆

发表于 2013-9-3 21:12:36 | 显示全部楼层
顶一个楼主!

出0入0汤圆

发表于 2013-9-5 13:27:07 | 显示全部楼层
很详细的I2C资料,收了@

出0入0汤圆

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

本版积分规则

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

GMT+8, 2024-10-3 09:20

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

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