⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 i2c_bus.c

📁 用quartusII编写的
💻 C
字号:
/*****************************************************************************
                    用51单片机模拟I2C总线主器件的程序
     
     注意:
            本程序是采用软件延迟的方法产生SCL脉冲,所以对高晶振频率要作 
     一定的修改(本程序是1us机器周期,即晶振频率要小于12MHz)
     
     
     开发过程:
            2004-3-24 16:41   
                  I2C总线的驱动程序和读写24CXX模块的程序在AT24C02,AT24C16上调试通过
            
            2005-1-11 10:55   
                  将I2C总线的驱动程序和读写24CXX模块的代码分离,I2C总线的驱动程序
            在文件I2C_bus.c中,读写24CXX模块的程序在文件I2C_24CXX.c中。

******************************************************************************/

#include "..\..\includes.h"


#if CFG_I2C_BUS_EN > 0

//---------------------------------------------------------
// 启动信号
// 在SCL线为高电平的时候,让SDA从1变到0,就可以产生启动信号
//---------------------------------------------------------
extern void I2C_Start( void )
{
      SDA = 1;
      _nop_();
      
      SCL = 1;
      
      _nop_();    // 在标准模式下,起始条件的建立时间的最小值为4.7us
      _nop_();    // 可以参见《I2C协议标准》第27页
      _nop_();
      _nop_();
      _nop_();
  
      SDA = 0;    // 发送起始信号 
      
      _nop_();    // 在标准模式下,起始条件的保持时间的最小值为4us
      _nop_();    // 可以参见《I2C协议标准》第27页
      _nop_();
      _nop_();
      _nop_();  
      
      SCL=0;      // 钳住I2C总线,准备发送或接收数据
      _nop_();
      _nop_();
}




//----------------------------------------------------------
// 结束信号
// 在SCL线为高电平的时候,让SDA从0变到1,就可以产生结束信号
//----------------------------------------------------------
extern void I2C_Stop( void )
{
      SDA = 0;
      _nop_();
      
      SCL = 1;
      _nop_();    // 在标准模式下,结束条件的建立时间的最小值为4us
      _nop_();    // 可以参见《I2C协议标准》第27页
      _nop_();
      _nop_();
      _nop_();    
  
      SDA = 1;    // 发送I2C总线结束信号
      _nop_();   
      _nop_();
      _nop_();
      _nop_(); 
      
      SCL = 0;
      _nop_();
      _nop_();
}




//--------------------------------------------------------
// 发ACK应答信号
//--------------------------------------------------------
extern void I2C_ACK( void )
{
      SDA = 0;
      
      _nop_();
      _nop_();
      _nop_();
      
      SCL = 1;
      _nop_();
      _nop_();
      _nop_();
      _nop_();
      _nop_();
      
      SCL = 0;    // 让I2C总线处于等待状态
      _nop_();
      _nop_();
}





//--------------------------------------------------------
// 发出非ACK应答信号
//--------------------------------------------------------
extern void I2C_UnACK( void )
{
      SDA = 1;
      
      _nop_();
      _nop_();
      _nop_();
      
      SCL = 1;
      _nop_();
      _nop_();
      _nop_();
      _nop_();
      _nop_();
      
      SCL = 0;    // 让I2C总线处于等待状态
      _nop_();
      _nop_();
}



//----------------------------------------------------------------
// 判断接收器在接收完一个字节的数据以后,是否返回应答信号
//
// 如果返回应答信号,    函数返回TRUE
// 如果没有返回应答信号,函数返回FALSE
//----------------------------------------------------------------
extern BOOLEAN I2C_IsACK( void )
{
      BOOLEAN isACK;
      
      _nop_();
      _nop_();
      
      SDA = 1;    // 8位数据发送完以后,发送器件释放数据线,准备接收应答
      _nop_();
      _nop_();
      
      SCL = 1;
      _nop_();
      _nop_();
      _nop_();
      
      if( SDA==0 )      // 判断接收器是否返回应答信号
      {
            isACK = TRUE;
      }
      else
      {
            isACK = FALSE;
      }
      
      SCL = 0;
      _nop_();
      _nop_();
      
      return isACK;
}

      






//--------------------------------------------------------------------
// 接收发送器件传来的数据
//
// 返回值:函数返回接收到的数据
//
// 注意事项:
//     在本函数中,并不负责返回ACK应答信号给发送器件,所以,在调用完
// 本函数以后,需要调用发ACK应答信号函数(或者发非ACK应答信号函数)
//--------------------------------------------------------------------
extern INT8U I2C_ReceiveByte( void )
{
      INT8U i, receive;
      
      receive = 0;
      
      SDA = 1;          // 置数据线为输入方式
      
      for( i=0; i<8; i++ )
      {
            _nop_();
            
            SCL = 0;    // 置时钟线为低,准备接收数据位
            _nop_();
            _nop_();
            _nop_();
            _nop_();
            _nop_();
            
            SCL = 1;    // 置时钟线为高,让SDA数据线上数据有效
            _nop_();
            _nop_();
            
            receive <<= 1;
            
            if( SDA==1 )  // 读取一位数据位
            {
                  receive |= 0x01;
            }
            
            _nop_();
            _nop_();
      }
      
      SCL = 0;
      _nop_();
      _nop_();
      
      return receive;
}









//-------------------------------------------------------------------------
// 发送一个字节
//
// 参数:  ch是将要发送的一个字节数据
//
// 返回值:
//         如果发送器收到接收器返回的ACK应答信号,    函数返回TRUE
//         如果发送器没有收到接收器返回的ACK应答信号,函数返回FALSE
//
// 注意事项:
//     在本函数中,已经完成了释放数据线,等待接收器件返回应答信号这些操作,
// 所以,在调用本函数以后,不要再去重复这些功能。
//------------------------------------------------------------------------- 
extern BOOLEAN I2C_SendByte( INT8U ch )
{
      INT8U i;
  
      for( i=0; i<8; i++ )    // 从字节的高位开始逐位发送,一个字节有8位,所以重复8次
      {
            if( ( (ch<<i)&0x80 ) != 0 )
                  SDA = 1;
            else
                  SDA = 0;
                  
            _nop_();
            
            SCL = 1;          // 置时钟线为高,让SDA线上的数据位有效
            
            _nop_();
            _nop_();
            _nop_();
            _nop_();
            
            SCL = 0;
      }

      return I2C_IsACK();
}

#endif

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -