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

📄 i2c.c

📁 qprox公司的芯片qt60xx0的驱动程序
💻 C
字号:
/*============================================================================
    Project     QT60xx0 Example Code
    File        i2c.c
    Function    Driver code for QT60xx0 via I2C interface
    Requires    Silicon Labs C8051F310 target
    Originated	D Spokes

	Description	This driver bit-bangs the I2C master function.
				Port 0, bit 7 provides the SCL signal
				Port 0, bit 6 provides the SDA signal.
				Interface to the driver comprises three functions:
				  InitI2c() configures the processor I/O and initialises the driver variables
				  I2cWrite() executes a multi-byte write transfer to a slave
				  I2cRead() executes a multi-byte read transfer from a slave    
				All three functions return a single byte indicating driver status

    (c) Quantum Research Group
============================================================================*/
#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;
}

⌨️ 快捷键说明

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