The I2C bus is an easy and cheap way to add peripherals to your micro over
only 2 lines.
Unfortunately many micros serve not the I2C bus. But the I2C protocol is so easy so it can be build in software. There are no maximum timing limitations, so interrupts must not be disabled during I2C data transmission. The master give the clock so it can stretch it whenever interrupts must be served.
But only a single master can be build in software. If other masters on the
bus or acting as slave you must be able to serve the maximum speed in all
cases. This can only be done with high speed micros (e.g. Atmels AVR or Scenix
There are 2 bidirectional lines needed: SDA for data and SCL for clock. Since the 8051 ports are open drain with internal pull up, these can directly access the I2C bus. On short distance (e.g. an EEPROM X24C02 on the micro) you need no additional resistors. On longer distance its recommended to add two resistors of 1.8kOhms against VCC on both lines. Very long distances (up to 300 meters) you can manage with driver circuits.
All I2C transfers are preceded with sending START. Then the I2C-address must be send. The lowest bit of the address determine if the following bytes are sent (0) or received (1). If the address not match, the slave ignore all further data until the next START. If the address match it sends an acknowledge to the master. Also all further bytes are acknowledged. If the master read data it generate the acknowledge to permit the slave to send the next byte. Only before receiving the last byte, the master send a not acknowledge. This must be done to prevent conflicting the STOP with the next byte sent by the slave. Generally all transfers finished by sending STOP. This generate a bus free state and I2C slaves can go to power down or initialize a write cycle (EEPROM). But a next START can be generated also without preceding a STOP.
There are 4 basic routines available:
There are minimal timing conditions on the I2C bus. To keep these conditions,
delays generated by additional NOP operations. To make it easy to adapt it
to other crystal frequency the expression "Cycle_1ms" must be defined.
Its value define the cycle count during 1millisecond (crystal / 12000 at 8051 or crystal / 4000 at Dallas micro).
The example contain also complete driver routines for the IO-expander circuit
PCF8574 and for serial EEPROM. On EEPROMs are 2 different addressing modes
implemented. But there is no way to detect which was connected.
On EEPROMs up to 2kByte the 3 higher address bits are included in the I2C-device address.
The expression: "ExtAdrMode equ 0" must be defined to access the following EEPROMs: 24C02, 24C04, 24C08 and 24C16.
The 2kbyte EEPROM is also available as 24C164 for the extended address mode. On higher size (e.g. 24C32) always the extended address mode was used.
The expression: "ExtAdrMode equ 1" must be defined to access the following EEPROMs: 24C164, 24C32, 24C64, 24C128 and 24C256. Then the I2C address was set to all address pins of the EEPROM connect to GND. But you can change it to serve more EEPROM devices if you need it.
The EEPROM routines can also be used to access RTC or RAM devices (e.g. PCF8583).
If the I2C slaves powered separate or the 8051 was reset during an I2C transmission the I2C bus can be in an unknown state. Then its recommended to bring the I2C bus into the STOP state. In the worst case a slave can be addressed and want to send the byte 00 to the master. Then all 8 bits must be clocked out before the master can generate a STOP. So you must try to send a STOP until 9 times. The SI2CRES routine handle this. It must be called only one time after the 8051 was reset.