/**
* \addtogroup I2C
* @{
*/
/*****************************************************************************/
/**
* \file I2C.c
* 100kHz I2C master routines for 8051 and Keil C51.
* \author Copyright (c) 2008, Murray R. Van Luyn. <[email protected]>
* \version 0.0
* \date 24-12-08
*/
/*****************************************************************************/
/*****************************************************************************
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************/
#include "I2C.h"
/*****************************************************************************
*
* Private Function Prototypes
*
*****************************************************************************/
static void i2c_delay_5us(void);
/*****************************************************************************
*
* Private Function Implementation
*
*****************************************************************************/
/*****************************************************************************
*
* i2c_delay_5us()
*
*****************************************************************************/
static void i2c_delay_5us(void)
{
/* Generate an approximately 5us delay with an 18.432MHz xtal. */
_nop_(); _nop_(); _nop_(); _nop_();
_nop_(); _nop_(); _nop_(); _nop_();
return;
}
/*****************************************************************************
*
* Public Function Implementation
*
*****************************************************************************/
/*****************************************************************************
*
* i2c_transmit_start()
*
*****************************************************************************/
void i2c_transmit_start(void)
{
/* Transmit I2C start condition sequence. */
SDA = 0;
i2c_delay_5us(); // Delay >= 4us
SCL = 0;
return;
}
/*****************************************************************************
*
* i2c_transmit_restart()
*
*****************************************************************************/
void i2c_transmit_restart(void)
{
/* Transmit I2C restart condition sequence. */
SDA = 1;
SCL = 1;
i2c_delay_5us(); // Delay >= 4.7us
SDA = 0;
i2c_delay_5us(); // Delay >= 4us
SCL = 0;
return;
}
/*****************************************************************************
*
* i2c_transmit_stop()
*
*****************************************************************************/
void i2c_transmit_stop(void)
{
/* Transmit I2C stop condition sequence. */
SDA = 0;
SCL = 1;
i2c_delay_5us(); // Delay >= 4us
SDA = 1;
i2c_delay_5us(); // Delay >= 4.7us
return;
}
/*****************************************************************************
*
* i2c_transmit_byte()
*
*****************************************************************************/
void i2c_transmit_byte(unsigned char byte)
{
unsigned char i;
/* Transmit 'byte' bit-by-bit from MSB to LSB. */
for(i = 8u; i > 0u; i--)
{
if(byte & (1 << (i - 1))) // Is a bit set in 'byte'?
{
SDA = 1; // Bit set so make data output pin high.
}
else
{
SDA = 0; // Bit clear so make data output pin low.
}
// Delay >= 250ns
SCL = 1;
i2c_delay_5us(); // Delay >= 4us
SCL = 0;
}
SDA = 1; // Set data output line as an input pin.
SCL = 1;
i2c_delay_5us(); // Delay >= 4us
/* Wait for slave to acknowledge. */
while(SDA) continue;
SCL = 0;
i2c_delay_5us(); // Delay >= 4.7us
return;
}
/*****************************************************************************
*
* i2c_receive_byte()
*
*****************************************************************************/
unsigned char i2c_receive_byte(bit reply)
{
unsigned char i;
unsigned char byte = 0x00;
SDA = 1; // Set data output line as input pin
/* Receive byte bit-by-bit from MSB to LSB */
for(i = 8u; i > 0u; i--)
{
SCL = 1;
i2c_delay_5us(); // Delay >= 4us
if(SDA)
{
byte |= (1 << (i - 1)); // Incoming bit is high so set
// corresponding bit in 'byte'.
}
else
{
byte &= ~(1 << (i - 1)); // Incoming bit is low so clear
// corresponding bit in 'byte'.
}
SCL = 0;
i2c_delay_5us(); // Delay >= 4.7us
}
/* Send ACK or NAK reply to transmitting slave. */
SDA = reply;
SCL = 1;
i2c_delay_5us(); // Delay >= 4us
SCL = 0;
i2c_delay_5us(); // Delay >= 4.7us
return byte;
}
/** @} */