Software I²C Library
The mikroPascal 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:
- This library implements time-based activities, so interrupts need to be disabled when using Software I²C.
- All Software I²C Library functions are blocking-call functions (they are waiting for I²C clock line to become logical one).
- The pins used for the Software I²C communication should be connected to the pull-up resistors. Turning off the LEDs connected to these pins may also be required.
External dependencies of Software I²C Library
| The following variables must be defined in all projects using Software I²C Library: | Description : | Example : |
|---|---|---|
var Soft_I2C_Scl: sbit; bdata; sfr; external; |
Soft I²C Clock line. | var Soft_I2C_Scl: sbit at P1_0_bit; |
var Soft_I2C_Sda: sbit; bdata; sfr; external; |
Soft I²C Data line. | var Soft_I2C_Sda: sbit at P1_1_bit; |
Library Routines
Soft_I2C_Init
| Prototype |
procedure Soft_I2C_Init(); |
|---|---|
| Returns |
Nothing. |
| Description |
Configures the software I²C module. |
| Requires |
|
| Example |
// soft_i2c pinout definition
var Soft_I2C_Scl : sbit at P1_0_bit;
Soft_I2C_Sda : sbit at P1_1_bit;
...
Soft_I2C_Init();
|
Soft_I2C_Start
| Prototype |
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 |
function Soft_I2C_Read(ack: word): byte; |
|---|---|
| Returns |
One byte from the Slave. |
| Description |
Reads one byte from the slave. Parameters :
|
| 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 |
var take : word; ... // Read data and send the not_acknowledge signal take := Soft_I2C_Read(0); |
Soft_I2C_Write
| Prototype |
function Soft_I2C_Write(_data: byte): byte; |
|---|---|
| Returns |
|
| Description |
Sends data byte via the I²C bus. Parameters :
|
| 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 |
var _data, error : byte; ... error := Soft_I2C_Write(data); error := Soft_I2C_Write(0xA3); |
Soft_I2C_Stop
| Prototype |
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 |
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 |
var counter : byte;
procedure Timer1InterruptHandler(); org IVT_ADDR_ET1;
begin
counter := 0;
if (counter >= 20)
begin
Soft_I2C_Break();
counter := 0; // reset counter
end
else
Inc(counter); // increment counter
end;
begin
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;
var seconds, minutes, hours, date, month : byte; // Global date/time variables
var year, RTCModuleAddress, YearOffset : 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
var Soft_I2C_Scl : sbit at P1_0_bit;
var Soft_I2C_Sda : sbit at P1_1_bit;
// End Software I2C connections
// LCD module connections
var LCD_RS : sbit at P2_0_bit;
var LCD_EN : sbit at P2_1_bit;
var LCD_D4 : sbit at P2_2_bit;
var LCD_D5 : sbit at P2_3_bit;
var LCD_D6 : sbit at P2_4_bit;
var LCD_D7 : sbit at P2_5_bit;
// End LCD module connections
//------------------ Performs project-wide init
procedure Init_Main();
begin
{$IFDEF PCF8583}
RTCModuleAddress := 0xA0;
YearOffset := 2008;
{$ENDIF}
{$IFDEF DS1307}
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;
//--------------------- Reads time and date information from PCF8583 RTC
procedure Read_Time_PCF8583();
var byte_read : byte;
begin
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) shr 4)*10 + (byte_read and 0x0F); // Transform seconds
byte_read := Soft_I2C_Read(1); // Read minutes byte
minutes := ((byte_read and 0xF0) shr 4)*10 + (byte_read and 0x0F); // Transform minutes
byte_read := Soft_I2C_Read(1); // Read hours byte
hours := ((byte_read and 0xF0) shr 4)*10 + (byte_read and 0x0F); // Transform hours
if ( (byte_read.B7) and (byte_read.B6) ) then // 12h format && PM flag
hours := hours + 12;
byte_read := Soft_I2C_Read(1); // Read year/date byte
year := YearOffset + ((byte_read and 0xC0) shr 6); // Transform year
date := ((byte_read and 0x30) shr 4)*10 + (byte_read and 0x0F); // Transform date
byte_read := Soft_I2C_Read(0); // Read weekday/month byte
month := ((byte_read and 0x10) shr 4)*10 + (byte_read and 0x0F); // Transform month
Soft_I2C_Stop(); // Issue stop signal
end;
//--------------------- Reads time and date information from DS1307 RTC
procedure Read_Time_DS1307();
var byte_read : byte;
begin
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) shr 4)*10 + (byte_read and 0x0F); // Transform seconds
byte_read := Soft_I2C_Read(1); // Read minutes byte
minutes := ((byte_read and 0x70) shr 4)*10 + (byte_read and 0x0F); // Transform minutes
byte_read := Soft_I2C_Read(1); // Read hours byte
if (byte_read.B6) then // 12h format
begin
hours := ((byte_read and 0x10) shr 4)*10 + (byte_read and 0x0F); // Transform hours
if (byte_read.B5) then // PM flag
hours := hours + 12;
end
else
hours := ((byte_read and 0x30) shr 4)*10 + (byte_read and 0x0F); // Transform hours
byte_read := Soft_I2C_Read(1); // Read weekday byte
byte_read := Soft_I2C_Read(1); // Read date byte
date := ((byte_read and 0x30) shr 4)*10 + (byte_read and 0x0F); // Transform date
byte_read := Soft_I2C_Read(1); // Read month byte
month := ((byte_read and 0x10) shr 4)*10 + (byte_read and 0x0F); // Transform month
byte_read := Soft_I2C_Read(1); // Read year byte
year := YearOffset + ((byte_read and 0xF0) shr 4)*10 + (byte_read and 0x0F); // Transform year
Soft_I2C_Stop(); // Issue stop signal
end;
//--------------------- Reads time and date information from RTC
procedure Read_Time();
begin
{$IFDEF PCF8583}
Read_Time_PCF8583();
{$ENDIF}
{$IFDEF DS1307}
Read_Time_DS1307();
{$ENDIF}
end;
//-------------------- Output values to LCD
procedure Display_Time();
begin
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;
//----------------- Main procedure
begin
Delay_ms(2000);
Init_Main(); // Perform initialization
while TRUE do // Endless loop
begin
Read_Time(); // Read time from RTC
Display_Time(); // Prepare and display on LCD
Delay_ms(1000); // Wait 1 second
end;
end.
What do you think about this topic ? Send us feedback!



