Click here to Skip to main content
12,829,115 members (37,932 online)
Click here to Skip to main content
Add your own
alternative version


39 bookmarked
Posted 26 Feb 2013

Emulation of I2C Protocol on C#

, 26 Feb 2013 CPOL
Rate this:
Please Sign up or sign in to vote.
This article presents code to emulate I2C protocol in C#, this can be useful in applications like data acquisition without microcontrollers.


In this article, we describe how the I2C protocol could be simulated in a Visual Studio C# application. I2C is a widely used device low end communication protocol. Various computer peripherals comply with I2C protocols, for example: memories, PDAs, cell phones etc. Usually, to access these peripherals, computers require an additional microcontroller/microprocessor. This significantly increases the cost of the device product. This article presents a possible solution to this problem; it describes how a C# application running on a Windows® OS can access an I2C peripheral.


The I2C peripheral interface was invented by Philips Electronics NV. This protocol is popularly used in processors’ communication with memory devices, PDAs, cell phones, etc.

And, C# is a horse power language supported by Microsoft Visual Studio; C# is a kind of language that equips the programmer with versatile features inherited from Java as well as C++. From the evolution of C# it has been an issue of controversy that it is a direct travesty of Java, but features like LINQ and safe switching to pointers prove C# as more advanced compared to its counterparts. Applications built on C# are equally efficient in data acquisition process as are MATLAB  and Labview. In C# we don’t need any kind of extras like ActiveX or mscomm objects as in VB6 or VC++ 6.0. The SerialPort class in C# is enough to support simple hardware at a variety of baud rates.   

Usually, a C# application communicates with I2C using a bridge microcontroller. This type of communication scheme is shown in Fig 1.

Fig 1: A usually followed scheme for communicating an I2C device through a C# application. 

There are certain disadvantages to this scheme and we are going to discuss these disadvantages in the next section. 

Demerits of indirect communication

The scheme (shown in figure 1) suffers with following disadvantages:

Dm = d1 + d2                                  …………………….(1)

This delay will be significant in applications demanding quick data acquisition (it is always desirable to have less delay). The usual value of d1= 20ms (at 9600 baud).

  • As we can observe there is a two stage communication involved; the first application communicates with a microcontroller, then it communicates with the I2C device. Let d1 and d2 be delays involved in these stages, respectively. The total delay in the communication process will be :
  • Secondly, microcontroller cost is also an undesirable factor in peripheral manufacturing. Microcontrollers (having RS232 as well as I2C) are available at a variety of costs (usually ranging from $9 to $30). And a costly microcontroller can substantially increase the final cost of the prototype.

Undoubtedly, eradication of microcontrollers from the scheme (shown in figure 1) would be advantageous in terms of low processing time as well as in cost reduction of the final device. 

Emulation as a possible solution

Since, in C#, a programmer is equipped with the SerialPort class (this class contains lots of methods for sending and receiving ), serial port is an easy interface for applications built in C# to communicate with the outside world. These pins on the serial port could be directly accessed from the application. These pins are: RTS , DTR and CTS (Refer to figure 2). RTS and DTR are output pins, i.e., a C# software application can write these pins with a boolean value which it wants. While CTS is an input pin, a software application can read a boolean value from this pin.

With these pins, can we emulate the I2C protocol? Of course, yes.  Actually, I2C devices communicate with a microcontroller with two pins, SCL and SDA. A sample I2C device is shown (in figure 3).  If we reference the ground levels, the RS232 port of PC and I2C devices are the same, and we follow connections given in table 1, I2C could be easily emulated, rendering the microcontroller of the scheme (shown in figure 1) as redundant. It might look strange, but the application can write a bit for the SDA pin; while, simultaneously, the application can read a bit value from SDA with the help of CTS.  The only complexity is to implement the whole of the I2C protocol in C# code. Once the required code library is ready, C# programmers can perform operations like: data acquisition (I2C sensor ICs like DS1621), memory access, communication with cellphones, etc., in a hassle free manner. Moreover, there will be no overload of firmware programming in microcontrollers.  


Fig 2: RS 232 DB9 Pinout  

Fig 3: DS1621(an I2C device)  pinout  

I2C Protocol at Glance    

Fig 4: Timing diagram of I2C bus (please zoom it to see properly)

The I2C is a bidirectional 2-wire bus. A device that sends data is identified as a transmitter, and a device receiving the data is identified as a receiver. It is responsibility of the master device to generate an SCL (clock signal). Usually, connections between these devices (SDA and SCL lines) are made via the open-drain bidirectional lines. The following bus protocol has been defined (see Figure 4): 

  • Data is initiated when the bus is idle.
  • The data line (SDA) must remain stable when the clock line (SCL) is HIGH. In case there is a transition in SDA while SCL is high, it would be interpreted as a control signal.

Important bus conditions:

  • When SCL and SDA both are high, bus is idle. 
  • Transition of SDA from high to low, while the clock is high, defines a START.
  • Transition of SDA from low to high, while the clock is high, defines a STOP.
  • After START, state of SDA defines data bit (1 or 0) for SCL=1(high). Each bit of data is transmitted in one clock pulse. Data transmission is terminated with a STOP or another START (abandoning previous transmission and start of a new one). Any number of  bytes could transferred between START and STOP conditions  The information is transferred byte-wise, and it is an obligation for   receiver to acknowledge with a ninth-bit.  The master device is responsible for generation an extra clock pulse which is associated with this acknowledge bit. A device that acknowledges, makes SDA line low, and this must remain low when SCL is high (for acknowledgement clock pulse). 
  • To end the data transmission slave puts the data line to high, so that the master could generate the STOP.

If R/W bit (in Figure 4) is 1, data is transferred from master to slave. In this first byte master first sends address of slave, and slave returns an acknowledgement for this.

On the other hand, if R/W bit is 0, data flow is from slave to master. Here also, master first sends the slave’s address, slave returns an acknowledge bit. After this, slave sends the data bytes to the master. Master returns an acknowledgement when it   receives all the bytes expect the last one. When  last byte is received , a ‘not acknowledge’ is returned by master.

In the next section we will see C-sharp implementation of this protocol. It should be noted that this section just mentioned some peripheral details of I2C protocol. 

C# Emulation of I2C  

In this article,  DS1621( a temperature sensor IC, please refer [9] for its specifications) is used as an example of an I2C device. Emulation is divided in following two parts:

Fig 4: Schematic of hardware used for the emulation
  1. Hardware: Figure 5 shows schematic of hardware used for emulation. It could be seen from schematic that no microcontroller is used, for interfacing RS232 with DS1621. Schematic consists of couple of  5.1 V  zeners and  couple of 470 ohm resistances. These resistances and zeners are used to   protect circuitry against high RS232 voltages. A LED with resistance is provided to indicate power supply in the system. A popular voltage converter  LM7805 is used to provide 5V stable DC output from a 9V DC power jack. Please refer to figure 2. for corresponding  pin names (DTR, CTS and RTS) of  RS232 to pin numbers given  in schematic.  We see can that connections are in accordance with as described in third section of this paper. (Hardware PCB files are in supplementary material provided with this paper click here).
  2. Software: This is the C-sharp application for emulation of I2C protocol. To maintain understandability of code. I have made this application as console (no GUI). Methods used in this code are detailed in table 1.
Table 1: Functions in code and their brief descriptions.




This function  initializes a ‘serial port’ object. It also sets initial SCL and SDA states


This function samples SDA state,  whenever  SCL =1(High).    


This provides START in I2C protocol.


This provides STOP in I2C protocol.


This function transmits 1 to I2C device.


This function transmits 1 to I2C device.


This method  transmits a byte to I2C device.


Through this method application reads a bit coming from I2C device.


Through this method application reads a byte from I2C device.


This method is specific for DS1621; it starts one shot mode temperature conversation.


This method is specific for DS1621; it starts temperature conversion sequence.


This method reads temperature in 2 byte format.


This method implements the read_temperature method with proper initiation.


This method is code entry point method.

The main method first calls spinit for required initialization of ‘serialport’ (this class provides interface with RS232 in C#) instance. Then after, main calls  issue_read_temp.  

issue_read_temp provides a sequence  to read temperature from DS1621 using I2C protocol.

The application runs with a console window. It first asks its user to provide port number to which I2C device is connected. When user provides the required information (port number), application takes some time, and if everything goes well (no runtime trouble), application successfully calculates the temperature and delivers it to the user interface.

It was verified that temperature values given by application are correct (by means of comparing temperature values with simple mercury thermometer readings).

Hence, we can say, that application successfully emulates I2C protocol. Using this scheme we are successful in elimination  of microcontroller in C# applications dealing with I2C devices. 

 * Author : NAKUL VYAS
  VERSION : 3.0

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.Ports;

namespace ConsoleApplication8
    class Program
        public static SerialPort sp;
        public static void spinit(int sn)  // function for serial port initialization
          sp =new SerialPort("COM"+sn);
          Console.WriteLine("openning the port..........");
         catch(Exception ex){
             Console.WriteLine("Cannot open port following exception occured:" + ex.Message.ToString());
            //making Clcok and SDA line stable
          sp.RtsEnable = true;
          sp.DtrEnable = true;
        //this samples SDA pin of DS1621 by reading value of ctsHolding of RS232
        public static bool sample() 
         return sp.CtsHolding;
        // This is start condition for DS1621 
        public static void startcmd()
            sp.DtrEnable= true;
            sp.DtrEnable= true;
            sp.RtsEnable = true;
            sp.DtrEnable = false;
        //this is stop condition for Ds1621
            public static void stopcmd()
            sp.DtrEnable =true;
            sp.DtrEnable = false;
            sp.RtsEnable = true;
            sp.DtrEnable = true;
        //This function transmitt 1(high) to DS1621
        public static void tx_1()
        sp.RtsEnable = false;
        sp.DtrEnable = true;
        sp.RtsEnable = true;
        sp.RtsEnable= false;
        //This function transmitt 0(low) to DS1621
        public static void tx_0()
        sp.RtsEnable = false;
        sp.DtrEnable= true;
        sp.DtrEnable = false; 
        sp.RtsEnable = true;
        sp.RtsEnable = false;
       //This functions tranmitt a byte value as a binary string
        public static bool tx_byte(string b)
           foreach (char c in b)
               if (c == '0')
               else if (c == '1')
        return rx_bit();
        //This reads a bit value from DS1621
        public static bool rx_bit()
           bool temp;
           sp.DtrEnable = true;
           sp.RtsEnable = false;
           sp.RtsEnable = true;
           temp = sample();
           sp.RtsEnable = false;
           return temp;

        //This reads a byte value from DS1621
        public static int rx_byte(bool ack)
            int i; 
            int retval=0; 
            for(i = 0;i <=7;i++) 
                retval = retval * 2;
                retval = retval + 1;
        return retval;
        //This Squence is for setting DS1621 for setting it in one shot mode (see data sheet)
        public static void one_shot_mode()
            startcmd(); //start command for DS1621
            //no need of stop

        //This Squence is for setting DS1621 for starting conversion of temperature (see data sheet)
        public static void Start_convert_temperature()
            tx_byte("10010000"); //Bus Master sends DS1621 address; R/ W= 0.DS1621 generates acknowledge bit.
            tx_byte("11101110");// Bus Master sends Start Convert T command protocol.DS1621 generates acknowledge bit.
        //This Squence is for setting DS1621 for reading 2 byte temperature format  MSB and LSB (see data sheet)
        public static double read_temperature()
            int temperature_MSB;
            int temperature_LSB;
            temperature_MSB = rx_byte(true); //MSB is integral value of temperature
            temperature_LSB = rx_byte(false); //LSB is fraction pf temperature
            //to convert temperature in readable format
            double temp = ((temperature_MSB * 256 + temperature_LSB))/256;
            if (temperature_MSB >= 128)
                temp = temp - 256;
            return temp;
        public static double issue_read_temp()
            //an extra stop to stabalize bus
            //issue a one shot mode command
            return read_temperature();
        static void Main(string[] args)
            Console.WriteLine("Enter the COM port number where Hardware is connected :");
            //serial port initialization
            Console.WriteLine("Temperature Value of DS1621 is :");
           //issue a read sequence for DS1621
            int i = 0;
            while (i < 20)

Fig 5: A screen shot of application run.


This article presents a novel approach for communication of a C# application with an I2C device. Conventionally, C# applications first communicate with microcontrollers using a serial communication protocol, and then it is the microcontroller which is responsible for communication with the I2C device. In contrast, this paper presents a scheme in which there is no need of microcontroller for a C# application to communicate with an I2C device. In this scheme, the C# application emulates I2C protocol directly over the RS232 port (DB9 serial). Since there is no need of microcontroller in this scheme, it eliminates firmware overhead and the final cost associated with prototyping. Moreover, unnecessary delay of data processing by microcontroller is also avoided. To verify the proposed scheme, it was successfully demonstrated by emulation of I2C by a C# console application over DS1621 (an example I2C device).


Note: Please use the PCB file here (to open this file you will need a free version of DIPTRACE Software) attached with this project for quick  development of the prototype.


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Nakul Vyas
India India
About Author:

I am specialized with Embedded Systems, my areas of interest are Real time Programming , RTOS, Intelligent Sensors and Actuators, Low level firmware. My projects uploaded on CodeProject are very old and I did them at time of my first year of Bachelors degree.
Further I am not in India, I have now moved to Stuttgart, Germany.

You may also be interested in...


Comments and Discussions

QuestionThat is amazing way to do it Pin
Member 1289857811-Dec-16 8:10
memberMember 1289857811-Dec-16 8:10 
GeneralMy vote of 5 Pin
miguelagl21-Jan-16 3:58
membermiguelagl21-Jan-16 3:58 
QuestionSerial Controller Delay Pin
Jayakumar.ss18-Jun-14 2:28
memberJayakumar.ss18-Jun-14 2:28 
QuestionEmulation of I2C Pin
Member 1082708419-May-14 23:10
memberMember 1082708419-May-14 23:10 
AnswerRe: Emulation of I2C Pin
Nakul Vyas20-May-14 0:18
memberNakul Vyas20-May-14 0:18 
QuestionThanks for your support guys Pin
Nakul Vyas15-Mar-13 6:06
memberNakul Vyas15-Mar-13 6:06 
AnswerRe: Thanks for your support guys Pin
Member 100880251-Jun-13 12:01
memberMember 100880251-Jun-13 12:01 
QuestionClock rate Pin
Mike Marynowski27-Feb-13 13:49
memberMike Marynowski27-Feb-13 13:49 

Nice article! From what I understand of I2C interfaces, they can be clocked at various rates and both ends need to be set to the same speed, no?

From your code it appears that there isn't much in the way of synchronization, i.e. when you send a byte, you just fire off all the bits without any real regard for timing.

How are you controlling the speed of the transmission to ensure it falls within the supported clock speed of the slave device? Is this just based on the baud rate on your serial port? If so, what would be the formula to convert between the baud rate and i2c clock rate?
AnswerRe: Clock rate Pin
Nakul Vyas15-Mar-13 6:04
memberNakul Vyas15-Mar-13 6:04 
GeneralMy vote of 5 Pin
Abinash Bishoyi27-Feb-13 1:50
memberAbinash Bishoyi27-Feb-13 1:50 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.170326.1 | Last Updated 26 Feb 2013
Article Copyright 2013 by Nakul Vyas
Everything else Copyright © CodeProject, 1999-2017
Layout: fixed | fluid