Software I²C Library

The mikroBasic PRO for 8051 provides routines for implementing Software I²C communication. These routines are hardware independent and can be used with any MCU. The Software I²C library enables you to use MCU as Master in I²C communication. Multi-master mode is not supported.

Notes:

External dependencies of Software I²C Library

The following variables must be defined in all projects using Software I²C Library: Description : Example :
dim Soft_I2C_Scl as sbit bdata sfr external Soft I²C Clock line. dim Soft_I2C_Scl as sbit at P1_3_bit
dim Soft_I2C_Sda as sbit bdata sfr external Soft I²C Data line. dim Soft_I2C_Sda as sbit at P1_4_bit

Library Routines

Soft_I2C_Init

Prototype

sub procedure Soft_I2C_Init()

Returns

Nothing.

Description

Configures the software I²C module.

Requires

Soft_I2C_Scl and Soft_I2C_Sda variables must be defined before using this function.

Example
' soft_i2c pinout definition
dim Soft_I2C_Scl as sbit at P1_3_bit
    Soft_I2C_Sda as sbit at P1_4_bit
...
Soft_I2C_Init()

Soft_I2C_Start

Prototype

sub procedure Soft_I2C_Start()

Returns

Nothing.

Description

Determines if the I²C bus is free and issues START signal.

Requires

Software I²C must be configured before using this function. See Soft_I2C_Init routine.

Example
' Issue START signal
Soft_I2C_Start()

Soft_I2C_Read

Prototype

sub function Soft_I2C_Read(dim ack as word) as byte

Returns

One byte from the Slave.

Description

Reads one byte from the slave.

Parameters :

  • ack: acknowledge signal parameter. If the ack==0 not acknowledge signal will be sent after reading, otherwise the acknowledge signal will be sent.

Requires

Soft I²C must be configured before using this function. See Soft_I2C_Init routine.

Also, START signal needs to be issued in order to use this function. See Soft_I2C_Start routine.

Example
dim take as word
...
' Read data and send the not_acknowledge signal
take = Soft_I2C_Read(0)

Soft_I2C_Write

Prototype

sub function Soft_I2C_Write(dim _Data as byte) as byte

Returns

  • 0 if there were no errors.
  • 1 if write collision was detected on the I²C bus.

Description

Sends data byte via the I²C bus.

Parameters :

  • _Data: data to be sent

Requires

Soft I²C must be configured before using this function. See Soft_I2C_Init routine.

Also, START signal needs to be issued in order to use this function. See Soft_I2C_Start routine.

Example
dim _data, error as byte
...
error = Soft_I2C_Write(data)
error = Soft_I2C_Write(0xA3)

Soft_I2C_Stop

Prototype

sub procedure Soft_I2C_Stop()

Returns

Nothing.

Description

Issues STOP signal.

Requires

Soft I²C must be configured before using this function. See Soft_I2C_Init routine.

Example
' Issue STOP signal
Soft_I2C_Stop()

Soft_I2C_Break

Prototype

sub procedure Soft_I2C_Break()

Returns

Nothing.

Description

All Software I²C Library functions can block the program flow (see note at the top of this page). Calling this routine from interrupt will unblock the program execution. This mechanism is similar to WDT.

Note: Interrupts should be disabled before using Software I²C routines again (see note at the top of this page).

Requires Nothing.
Example
dim counter as byte

sub procedure Timer1InterruptHandler() org IVT_ADDR_ET1
  counter = 0
  if (counter >= 20)
    Soft_I2C_Break()
    counter = 0                  ' reset counter
  else
      Inc(counter)               ' increment counter
  end if
end sub

main:

  TR1_bit = 0                  ' Stop Timer1  
  ET1_bit = 1                  ' Enable Timer1 interrupt
  TH1 = 0x00                   ' Set Timer1 high byte
  TL1 = 0x00                   ' Set Timer1 low byte
  TR1_bit = 1                  ' Run Timer1

  EA_bit = 0                   ' Interrupt disable

  ...

  ' try Soft_I2C_Init with blocking prevention mechanism
  EA_bit = 1                   ' Interrupt enable
  Soft_I2C_Init()
  EA_bit = 0                   ' Interrupt disable

  ...

end.

Library Example

The example demonstrates Software I²C Library routines usage. The 8051 MCU is connected (SCL, SDA pins) to PCF8583 RTC (real-time clock). Program reads date and time are read from the RTC and prints it on LCD.

program RTC_Read

dim seconds, minutes, hours, date_, month_ as byte    ' Global date/time variables
dim year, RTCModuleAddress, YearOffset as word

#DEFINE PCF8583         ' Uncomment this line if you use PCF8583 RTC chip (mE RTC extra board)
'#DEFINE DS1307          ' Uncomment this line if you use DS1307 RTC chip (mE RTC2 extra board)

' Software I2C connections
dim Soft_I2C_Scl as sbit at P1_0_bit
dim Soft_I2C_Sda as sbit at P1_1_bit
' End Software I2C connections

' LCD module connections
dim LCD_RS as sbit at P2_0_bit
dim LCD_EN as sbit at P2_1_bit

dim LCD_D4 as sbit at P2_2_bit
dim LCD_D5 as sbit at P2_3_bit
dim LCD_D6 as sbit at P2_4_bit
dim LCD_D7 as sbit at P2_5_bit
' End LCD module connections

'------------------ Performs project-wide init
sub procedure Init_Main
  #IFDEF PCF8583 THEN
    RTCModuleAddress   = 0xA0
    YearOffset         = 2008
  #ENDIF

  #IFDEF DS1307 THEN
    RTCModuleAddress   = 0xD0
    YearOffset         = 2000
  #ENDIF


  Soft_I2C_Init()           ' Initialize Soft I2C communication
  Lcd_Init()                ' Initialize LCD
  Lcd_Cmd(_LCD_CLEAR)       ' Clear LCD display
  Lcd_Cmd(_LCD_CURSOR_OFF)  ' Turn cursor off

  LCD_Out(1,1,"Date:")      ' Prepare and output static text on LCD
  Lcd_Chr(1,8,":")
  Lcd_Chr(1,11,":")
  LCD_Out(2,1,"Time:")
  Lcd_Chr(2,8,":")
  Lcd_Chr(2,11,":")
end sub

'--------------------- Reads time and date information from PCF8583 RTC
sub procedure Read_Time_PCF8583
dim byte_read as byte
  Soft_I2C_Start()                   ' Issue start signal
  Soft_I2C_Write(RTCModuleAddress)   ' RTC module address + write (R#/W = 0)
  Soft_I2C_Write(2)                  ' Start from seconds byte
  Soft_I2C_Start()                   ' Issue repeated start signal
  Soft_I2C_Write(RTCModuleAddress+1) ' RTC module address + read  (R#/W = 1)

  byte_read = Soft_I2C_Read(1)                                      ' Read seconds byte
  seconds = ((byte_read and 0xF0) >> 4)*10 + (byte_read and 0x0F)   ' Transform seconds

  byte_read = Soft_I2C_Read(1)                                      ' Read minutes byte
  minutes = ((byte_read and 0xF0) >> 4)*10 + (byte_read and 0x0F)   ' Transform minutes

  byte_read = Soft_I2C_Read(1)                                      ' Read hours byte
  hours = ((byte_read and 0xF0) >> 4)*10 + (byte_read and 0x0F)     ' Transform hours
  if ( (byte_read.B7) and (byte_read.B6) ) then                     ' 12h format && PM flag
    hours = hours + 12
  end if
  
  byte_read = Soft_I2C_Read(1)                                      ' Read year/date byte
  year = YearOffset + ((byte_read and 0xC0) >> 6)                   ' Transform year
  date_ = ((byte_read and 0x30) >> 4)*10 + (byte_read and 0x0F)     ' Transform date

  byte_read = Soft_I2C_Read(0)                                      ' Read weekday/month byte
  month_ = ((byte_read and 0x10) >> 4)*10 + (byte_read and 0x0F)    ' Transform month
  Soft_I2C_Stop()                                                   ' Issue stop signal
end sub

'--------------------- Reads time and date information from DS1307 RTC
sub procedure Read_Time_DS1307
dim byte_read as byte
  Soft_I2C_Start()                   ' Issue start signal
  Soft_I2C_Write(RTCModuleAddress)   ' RTC module address + write (R#/W = 0)
  Soft_I2C_Write(0)                  ' Start from seconds byte
  Soft_I2C_Start()                   ' Issue repeated start signal
  Soft_I2C_Write(RTCModuleAddress+1) ' RTC module address + read  (R#/W = 1)

  byte_read = Soft_I2C_Read(1)                                    ' Read seconds byte
  seconds = ((byte_read and 0x70) >> 4)*10 + (byte_read and 0x0F) ' Transform seconds

  byte_read = Soft_I2C_Read(1)                                    ' Read minutes byte
  minutes = ((byte_read and 0x70) >> 4)*10 + (byte_read and 0x0F) ' Transform minutes

  byte_read = Soft_I2C_Read(1)                                    ' Read hours byte
  if (byte_read.B6) then                                          ' 12h format
      hours = ((byte_read and 0x10) >> 4)*10 + (byte_read and 0x0F) ' Transform hours
      if (byte_read.B5) then                                        ' PM flag
        hours = hours + 12
      end if
  else
    hours = ((byte_read and 0x30) >> 4)*10 + (byte_read and 0x0F) ' Transform hours
  end if
  byte_read = Soft_I2C_Read(1)                                    ' Read weekday byte

  byte_read = Soft_I2C_Read(1)                                    ' Read date byte
  date_ = ((byte_read and 0x30) >> 4)*10 + (byte_read and 0x0F)    ' Transform date

  byte_read = Soft_I2C_Read(1)                                    ' Read month byte
  month_ = ((byte_read and 0x10) >> 4)*10 + (byte_read and 0x0F)   ' Transform month

  byte_read = Soft_I2C_Read(1)                                    ' Read year byte
  year = YearOffset + ((byte_read and 0xF0) >> 4)*10 + (byte_read and 0x0F) ' Transform year
  Soft_I2C_Stop()                                                 ' Issue stop signal
end sub
  
'--------------------- Reads time and date information from RTC
sub procedure Read_Time()
  #IFDEF PCF8583 THEN
    Read_Time_PCF8583()
  #ENDIF

  #IFDEF DS1307 THEN
    Read_Time_DS1307()
  #ENDIF
end sub

'-------------------- Output values to LCD
sub procedure Display_Time()
  Lcd_Chr(1, 6, (date_ div 10)   + 48)    ' Print tens digit of date variable
  Lcd_Chr(1, 7, (date_ mod 10)   + 48)    ' Print oness digit of date variable
  Lcd_Chr(1, 9, (month_ div 10)  + 48)
  Lcd_Chr(1,10, (month_ mod 10)  + 48)
  Lcd_Chr(1,12, (word(year div 1000) mod 10) + 48)    ' Print year
  Lcd_Chr(1,13, (word(year div 100)  mod 10) + 48)
  Lcd_Chr(1,14, (word(year div 10)   mod 10) + 48)
  Lcd_Chr(1,15,  word(year mod 10)          + 48)

  Lcd_Chr(2, 6, (hours div 10)   + 48)
  Lcd_Chr(2, 7, (hours mod 10)   + 48)
  Lcd_Chr(2, 9, (minutes div 10) + 48)
  Lcd_Chr(2,10, (minutes mod 10) + 48)
  Lcd_Chr(2,12, (seconds div 10) + 48)
  Lcd_Chr(2,13, (seconds mod 10) + 48)
end sub

'----------------- Main procedure
main:
  Delay_ms(2000)
  Init_Main()             ' Perform initialization

  while TRUE              ' Endless loop
    Read_Time()           ' Read time from RTC
    Display_Time()        ' Prepare and display on LCD
    Delay_ms(1000)        ' Wait 1 second
  wend
end.
Copyright (c) 2002-2013 mikroElektronika. All rights reserved.
What do you think about this topic ? Send us feedback!
Want more examples and libraries? 
Find them on LibStock - A place for the code