原创 一个很不错的I2C读写程序(基于KeilC51),运行稳定,可靠性高

2008-3-19 20:00 6164 8 9 分类: MCU/ 嵌入式

点击下载


#include "C8051F310.H"
#include "common.h"
#include "i2c.h"


/* Ports */
sbit SCL  = P0 ^ 7;
sbit SDA  = P0 ^ 6;
sbit CHECK  = P1 ^ 0;


/* ------------ DEFINES --------------- */
/* I2c read/write flags */
#define I2C_WRITE_FLAG 0x00 /* bit 0 of slave-addres byte */
#define I2C_READ_FLAG 0x01


/* bus logic levels */
#define LO  0
#define HI 1


/* Delay constants */
#define _5US 8


/* Retry times on NACK */
#define NACK_RETRY_MAX 5


/* ------------ LOCAL DATA ------------ */
xdata UINT8 I2cStatus;
xdata UINT8 RxBit;
xdata UINT8 RxByte;


/* ---------- MODULE FUNCTIONS  ------- */
void Delay ( UINT8 Time );
UINT8 SetScl( UINT8 State );
UINT8 SetSda( UINT8 State );
void FloatSda( void );
UINT8 I2cStart();
UINT8 I2cStop();
UINT8 I2cTxBit( UINT8 BitVal );
UINT8 I2cRxBit( void );
UINT8 I2cTxByte( UINT8 TxData);
UINT8 I2cRxByte( UINT8 AckState );



/*---------------- Function Header -------------------------------------------


 FUNCTION InitI2c
 PURPOSE  Initialises I2c driver
 INPUT  None
 OUTPUT  I2c status byte indicating the idle-state of the bus
 
----------------------------------------------------------------------------*/
UINT8 InitI2c ( void )
{


 /* configure C8051F310 ports for I2C operation:
  SDA is connected to Port0, bit6
  SCL is connected to Port0, bit7
  both pins function in open-drain mode
 */
 P0SKIP = 0xc0;
 P0MDOUT &= ~0x30; /* set SDA and SCL = open-drain */
 
 I2cStatus = 0;  /* initialise driver status */
 
 /* set initial idle state for bus (SDA and SCL = 1) */
 return ( SetSda( HI ) || SetScl( HI ) );


}


/*---------------- Function Header -------------------------------------------


 FUNCTION Delay
 PURPOSE  Programme delay in the microsecond range -
    Called to meet I2C bus timing requirements


----------------------------------------------------------------------------*/
void Delay ( UINT8 Time )
{
 UINT8 i;


 EA = 0;      /* interrupts disabled during delay */
 for (i = 0; i < Time; i++);
 EA = 1;
}


/*---------------- Function Header -------------------------------------------


 FUNCTION SetScl
 PURPOSE  Sets I2C SCL line to the required level. Because the bus is a
    wire-OR configuration, it may take some time to establish a
    logic '1' due to slow risetime, clock stretching etc.
    An arbitrary timeout of 250us is allowed.
 INPUT  Required bus state
 OUTPUT  Flag indicating result: 1 = OK, 0 = bus line stuck.
 MODIFIES I2cStatus
    
----------------------------------------------------------------------------*/
UINT8 SetScl( UINT8 State )
{
// UINT16 Timeout = 450; /* approx 250us */
 UINT16 Timeout = 10000; /* approx 250us */


 SCL = State;
 while ( (SCL != State) && --Timeout);


 if ( Timeout )
  return true;
 else
 {
  I2cStatus |= I2C_ERROR_SCL_STUCK;
  return false;
 }
}


/*---------------- Function Header -------------------------------------------


 FUNCTION SetSda
 PURPOSE  Sets I2C SDA line to the required level. Because the bus is a
    wire-OR configuration, it may take some time to establish a
    logic '1' due to slow risetime, clock stretching etc.
    An arbitrary timeout of 250us is allowed.
 INPUT  Required bus state
 OUTPUT  Flag indicating result: 1 = OK, 0 = bus line stuck.
 MODIFIES I2cStatus
    
----------------------------------------------------------------------------*/
UINT8 SetSda( UINT8 State )
{
// UINT16 Timeout = 450; /* approx 250us */
 UINT16 Timeout = 10000; /* approx 250us */


 SDA = State;
 while ( (SDA != State) && --Timeout);


 if ( Timeout )
  return true;
 else
 {
  I2cStatus |= I2C_ERROR_SDA_STUCK;
  return false;
 }
}


/*---------------- Function Header -------------------------------------------


 FUNCTION FloatSda
 PURPOSE  Sets I2C SDA line to 'input mode'.
    Note: this function does not check the line is high because
    a slave may be legitimately driving SDA low.
    
----------------------------------------------------------------------------*/
void FloatSda( void )
{
 SDA = HI;
}


/*---------------- Function Header -------------------------------------------


 FUNCTION I2cStart
 PURPOSE  Applies an appropriately timed START condition to the I2c bus.
 OUTPUT  Flag indicating result: 1 = OK, 0 = bus line stuck.
 MODIFIES I2cStatus
    
----------------------------------------------------------------------------*/
UINT8 I2cStart()
{
 if ( !SDA )  /* ensure SDA is high */
 {
  if ( !SetSda(HI) )
   return false;
 }


 if ( !SCL )  /* ensure SCL is high */
 {
  if ( !SetScl(HI) )
   return false;
 }


 Delay( _5US );    /* Philips tSU:STA > 4.7us */


 SetSda(LO);
 Delay( _5US );    /* Philips tHD:SDA > 4us */
 
 return ( SetScl(LO) );
}


/*---------------- Function Header -------------------------------------------


 FUNCTION I2cStop
 PURPOSE  Applies an appropriately timed STOP condition to the I2c bus.
 OUTPUT  Flag indicating result: 1 = OK, 0 = bus line stuck.
 MODIFIES I2cStatus
    
----------------------------------------------------------------------------*/
UINT8 I2cStop()
{
 SetSda(LO); /* ensure SDA is low */


 if ( !SetScl(HI) )
  return false;
 Delay( _5US );    /* Philips tSU:STO > 4us */
 
 return ( SetSda(HI) );
}


/*---------------- Function Header -------------------------------------------


 FUNCTION I2cTxBit
 PURPOSE  Drives the specified data bit to the I2c bus.
 OUTPUT  Flag indicating result: 1 = OK, 0 = bus line stuck.
 MODIFIES I2cStatus
    
----------------------------------------------------------------------------*/
UINT8 I2cTxBit( UINT8 BitVal )
{
 if ( !SetSda(BitVal) )
  return false;
 Delay( _5US );    /* Philips tLOW > 4.7us */


 if ( !SetScl(HI) )
  return false;
 Delay( _5US );    /* Philips tHIGH > 4us */
 
 return ( SetScl(LO) );
}


/*---------------- Function Header -------------------------------------------


 FUNCTION I2cRxBit
 PURPOSE  Receives a data bit from the I2c bus.
 OUTPUT  Flag indicating result: 1 = OK, 0 = bus line stuck.
    Data bit is saved to RxBit
 MODIFIES I2cStatus
    
----------------------------------------------------------------------------*/
UINT8 I2cRxBit( void )
{
 FloatSda(); /* float SDA - can't check state as slave maybe driving SDA */
 Delay( _5US );    /* Philips tLOW > 4.7us */


 if ( !SetScl(HI) )
  return false;
 Delay( _5US );    /* Philips tHIGH > 4us */
 RxBit = SDA;
 return ( SetScl(LO) );
}


/*---------------- Function Header -------------------------------------------


 FUNCTION I2cTxByte
 PURPOSE  Sequences transmission of a data byte to the I2c bus.
 OUTPUT  Flag indicating result: 1 = slave acknowledged, 0 = no ack/fail.
    Data bit is saved to RxBit
 MODIFIES I2cStatus: State of ACK bit and error flags
    
----------------------------------------------------------------------------*/
UINT8 I2cTxByte( UINT8 TxData)
{
 UINT8 i;
 UINT8 t = TxData;


 for (i= 0;i < 8;i++)
 {
  if ( !I2cTxBit( (t & 0x80) ? 1 : 0 ) )
   return false;
  t <<= 1;
 }


 if ( I2cRxBit() )
 {
  if (RxBit)
   I2cStatus |= I2C_ERROR_NO_ACK;
  return ( !RxBit ); /* returns '1' if ACK recieved */
 }
 else
  return false;


}


/*---------------- Function Header -------------------------------------------


 FUNCTION I2cTxByte
 PURPOSE  Sequences reception of a data byte from the I2c bus.
 INPUT  Flag indicating state of ACK bit to be sent to the slave
 OUTPUT  Flag indicating result: 1 = OK, 0 = fail.
    Data byte is saved to RxByte
 MODIFIES I2cStatus: State of error flags
    
----------------------------------------------------------------------------*/
UINT8 I2cRxByte( UINT8 AckState )
{
 UINT8 i;
 UINT8 r = 0;


 for (i= 0;i < 8;i++)
 {
  if ( !I2cRxBit() )
   return false;
  r <<= 1;
  r |= RxBit;
 }


 RxByte = r;


 return ( I2cTxBit ( AckState ) );


}


/*---------------- Function Header -------------------------------------------


 FUNCTION I2cWrite
 PURPOSE  Sequences a write-cycle to a slave device on the I2c bus.
    send START
    send slave-adddress + write flag (check ACK)
    send write pointer (check ACK)
    read data bytes (with NACK at last byte) (check all ACKs)
 INPUT  I2cAddress:    specifies slave device 7-bit address
    DeviceAddress: specifies address pointer within the device
    Data:          Pointer to write-data (byte) array
    ByteCount:     specifies number of bytes to write
 OUTPUT  I2cStatus byte indicating result of I2c cycle.
 MODIFIES I2cStatus:     all flags
    
----------------------------------------------------------------------------*/
UINT8 I2cWrite( UINT8 I2cAddress, UINT8 DeviceAddress, UINT8 *Data, UINT8 ByteCount)
{
 UINT8 i;
 UINT8 *WriteDataPtr;
 
CHECK = 1;
 i = 0;
 
 do { /* attempt to address device up to NACK_RETRY_MAX times */
 
  I2cStatus = 0;


  if ( I2cStart() )
  {
   if ( !I2cTxByte( (I2cAddress * 2) + I2C_WRITE_FLAG ) )
    I2cStop();
  }
 } while ( (I2cStatus != 0) && (++i < NACK_RETRY_MAX) );
CHECK = 0;


 if ( i >= NACK_RETRY_MAX )
  return I2cStatus;
 


 if ( !I2cTxByte( DeviceAddress ) )
 {
  I2cStop();
  return I2cStatus;
 }


 WriteDataPtr = Data;
 for ( i = 0; i < ByteCount; i++)
 {
  if ( !I2cTxByte( *WriteDataPtr++ ) )
  {
   I2cStop();
   return I2cStatus;
  }
 }


 I2cStop();
 return I2cStatus;
}


/*---------------- Function Header -------------------------------------------


 FUNCTION I2cRead
 PURPOSE  Sequences a read-cycle to a slave device on the I2c bus:
    send START
    send slave-adddress + write flag (check ACK)
    send read pointer (check ACK)
    send re-START
    send slave-adddress + read flag (check ACK)
    read data bytes (with NACK at last byte)
 INPUT  I2cAddress:    specifies slave device 7-bit address
    DeviceAddress: specifies address pointer within the device
    Data:          Pointer to return-data (byte) array
    ByteCount:     specifies number of bytes to read
 OUTPUT  I2cStatus byte indicating result of I2c cycle.
 MODIFIES I2cStatus:     all flags
    
----------------------------------------------------------------------------*/
UINT8 I2cRead( UINT8 I2cAddress, UINT8 DeviceAddress, UINT8 *Data, UINT8 ByteCount)
{
 UINT8 i;
 UINT8 *ReadDataPtr;
 
 i = 0;
 do { /* attempt to address device up to NACK_RETRY_MAX times */
 
  I2cStatus = 0;


  if ( I2cStart() )
  {
   if ( !I2cTxByte( (I2cAddress * 2) + I2C_WRITE_FLAG ) )
    I2cStop();
  }
 } while ( (I2cStatus != 0) && (++i < NACK_RETRY_MAX) );


 if ( i >= NACK_RETRY_MAX )
  return I2cStatus;



 if ( !I2cTxByte( DeviceAddress ) )
 {
  I2cStop();
  return I2cStatus;
 }


 i = 0;
 do { /* attempt to address device up to NACK_RETRY_MAX times */
 
  I2cStatus = 0;


  if ( I2cStart() )
  {
   if ( !I2cTxByte( (I2cAddress * 2) + I2C_READ_FLAG ) )
    I2cStop();
  }
 } while ( (I2cStatus != 0) && (++i < NACK_RETRY_MAX) );


 if ( i >= NACK_RETRY_MAX )
  return I2cStatus;



 ReadDataPtr = Data;
 for ( i = 0; i < ByteCount; i++)
 {
  if ( I2cRxByte( (i == (ByteCount - 1) ? 1 : 0 ) ) )
    *ReadDataPtr++ = RxByte;
  else
  {
   I2cStop();
   return I2cStatus;
  }
 }


 I2cStop();
 return I2cStatus;
}

PARTNER CONTENT

文章评论1条评论)

登录后参与讨论

xucun915_925777961 2009-2-27 13:27

学习过,俺就要顶一下,谢了!
相关推荐阅读
用户136065 2012-05-29 16:46
立体车库操作盒(内有本项目的源代码,电路图)
https://static.assets-stash.eet-china.com/album/old-resources/2009/2/26/8ba54db8-208e-4ab8-850e-b7...
用户136065 2008-12-17 13:50
STM32 protel 封装(不断更新中)
STM32 Protel 封装只画了三个封装(LQFP48,LQFP64,LQFP100)https://static.assets-stash.eet-china.com/album/old-res...
用户136065 2008-11-03 16:54
最新发现与创新:科学家证实电子电路存在记忆电阻
 美国科学家日前宣布,他们已证实电子电路存在第四种基本元件———记忆电阻(简称忆阻),并成功设计出一个能工作的忆阻实物模型。   早在1971年,非线性电路理论先驱、美国加利福尼亚大学伯克利分校的华裔...
用户136065 2008-11-03 12:06
国内主要网络电台地址
mms://211.89.225.101/live3 中央电台音乐频道      收听mms://vl.sina.com.cn/popmusic 东广音乐台动感101mms://vstream.sin...
用户136065 2008-11-03 11:47
W5100集TCP/IP协议栈、以太网MAC和PHY为一体
W5100是WIZnet公司最新推出的固件网络芯片,它是在W3150A+的基础上,集成了以太网物理层RTL8201CP核,因此W5100集TCP/IP协议栈、以太网MAC和PHY为一体。W5100支持...
用户136065 2008-10-20 11:22
iccavr用户手册(中文)
https://static.assets-stash.eet-china.com/album/old-resources/2008/10/20/370fcf86-59d6-46f9-a7e5-e01...
EE直播间
更多
我要评论
1
8
关闭 站长推荐上一条 /3 下一条