Software I²C Library
The mikroC 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 : |
---|---|---|
extern sfr sbit bdata Soft_I2C_Scl; |
Soft I²C Clock line. | sbit Soft_I2C_Scl at P1_0_bit; |
extern sfr sbit bdata Soft_I2C_Sda; |
Soft I²C Data line. | sbit Soft_I2C_Sda at P1_1_bit; |
Library Routines
Soft_I2C_Init
Prototype |
void Soft_I2C_Init(); |
---|---|
Returns |
Nothing. |
Description |
Configures the software I²C module. |
Requires |
|
Example |
// soft_i2c pinout definition sbit Soft_I2C_Scl at P1_0_bit; sbit Soft_I2C_Sda at P1_1_bit; ... Soft_I2C_Init(); |
Soft_I2C_Start
Prototype |
void Soft_I2C_Start(void); |
---|---|
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 |
unsigned short Soft_I2C_Read(unsigned int ack); |
---|---|
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 |
unsigned short take; ... // Read data and send the not_acknowledge signal take = Soft_I2C_Read(0); |
Soft_I2C_Write
Prototype |
unsigned short Soft_I2C_Write(unsigned short data_); |
---|---|
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 |
unsigned short data_, error; ... error = Soft_I2C_Write(data_); error = Soft_I2C_Write(0xA3); |
Soft_I2C_Stop
Prototype |
void Soft_I2C_Stop(void); |
---|---|
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 |
void Soft_I2C_Break(void); |
---|---|
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 |
char counter = 0; void Timer1InterruptHandler() org IVT_ADDR_ET1{ if (counter >= 20) { Soft_I2C_Break(); counter = 0; // reset counter } else counter++; // increment counter } void 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 ... } |
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 from the RTC and prints it on Lcd.
char seconds, minutes, hours, date, month; // Global date/time variables unsigned int year; unsigned int RTCModuleAddress, YearOffset; // RTC chip description variables #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 sbit Soft_I2C_Scl at P1_0_bit; sbit Soft_I2C_Sda at P1_1_bit; // End Software I2C connections // LCD module connections sbit LCD_RS at P2_0_bit; sbit LCD_EN at P2_1_bit; sbit LCD_D4 at P2_2_bit; sbit LCD_D5 at P2_3_bit; sbit LCD_D6 at P2_4_bit; sbit LCD_D7 at P2_5_bit; // End LCD module connections //------------------ Performs project-wide init void Init_Main() { #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,':'); } //--------------------- Reads time and date information from PCF8583 RTC void Read_Time_PCF8583() { char byte_read; 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 & 0xF0) >> 4)*10 + (byte_read & 0x0F); // Transform seconds byte_read = Soft_I2C_Read(1); // Read minutes byte minutes = ((byte_read & 0xF0) >> 4)*10 + (byte_read & 0x0F); // Transform minutes byte_read = Soft_I2C_Read(1); // Read hours byte hours = ((byte_read & 0xF0) >> 4)*10 + (byte_read & 0x0F); // Transform hours if ( (byte_read.B7) && (byte_read.B6) ) // 12h format && PM flag hours = hours + 12; byte_read = Soft_I2C_Read(1); // Read year/date byte year = YearOffset + ((byte_read & 0xC0) >> 6); // Transform year date = ((byte_read & 0x30) >> 4)*10 + (byte_read & 0x0F); // Transform date byte_read = Soft_I2C_Read(0); // Read weekday/month byte month = ((byte_read & 0x10) >> 4)*10 + (byte_read & 0x0F); // Transform month Soft_I2C_Stop(); // Issue stop signal } //--------------------- Reads time and date information from DS1307 RTC void Read_Time_DS1307() { char byte_read; 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 & 0x70) >> 4)*10 + (byte_read & 0x0F); // Transform seconds byte_read = Soft_I2C_Read(1); // Read minutes byte minutes = ((byte_read & 0x70) >> 4)*10 + (byte_read & 0x0F); // Transform minutes byte_read = Soft_I2C_Read(1); // Read hours byte if (byte_read.B6) { // 12h format hours = ((byte_read & 0x10) >> 4)*10 + (byte_read & 0x0F); // Transform hours if (byte_read.B5) // PM flag hours = hours + 12; } else hours = ((byte_read & 0x30) >> 4)*10 + (byte_read & 0x0F); // Transform hours byte_read = Soft_I2C_Read(1); // Read weekday byte byte_read = Soft_I2C_Read(1); // Read date byte date = ((byte_read & 0x30) >> 4)*10 + (byte_read & 0x0F); // Transform date byte_read = Soft_I2C_Read(1); // Read month byte month = ((byte_read & 0x10) >> 4)*10 + (byte_read & 0x0F); // Transform month byte_read = Soft_I2C_Read(1); // Read year byte year = YearOffset + ((byte_read & 0xF0) >> 4)*10 + (byte_read & 0x0F); // Transform year Soft_I2C_Stop(); // Issue stop signal } //--------------------- Reads time and date information from RTC void Read_Time() { #ifdef PCF8583 Read_Time_PCF8583(); #endif #ifdef DS1307 Read_Time_DS1307(); #endif } //-------------------- Output values to LCD void Display_Time() { Lcd_Chr(1, 6, (date / 10) + 48); // Print tens digit of date variable Lcd_Chr(1, 7, (date % 10) + 48); // Print oness digit of date variable Lcd_Chr(1, 9, (month / 10) + 48); Lcd_Chr(1,10, (month % 10) + 48); Lcd_Chr(1,12, ((year / 1000) % 10) + 48); // Print year Lcd_Chr(1,13, ((year / 100) % 10) + 48); Lcd_Chr(1,14, ((year / 10) % 10) + 48); Lcd_Chr(1,15, (year % 10) + 48); Lcd_Chr(2, 6, (hours / 10) + 48); Lcd_Chr(2, 7, (hours % 10) + 48); Lcd_Chr(2, 9, (minutes / 10) + 48); Lcd_Chr(2,10, (minutes % 10) + 48); Lcd_Chr(2,12, (seconds / 10) + 48); Lcd_Chr(2,13, (seconds % 10) + 48); } //----------------- Main procedure void main() { Delay_ms(2000); Init_Main(); // Perform initialization while (1) { // Endless loop Read_Time(); // Read time from RTC Display_Time(); // Prepare and display on LCD Delay_ms(1000); // Wait 1 second } }
What do you think about this topic ? Send us feedback!