G2Labs Grzegorz Grzęda
I2C Communication with AVR Atmega-328: A Step-by-Step Tutorial
March 4, 2024
I2C Communication with AVR Atmega-328: A Step-By-Step Tutorial
The Inter-Integrated Circuit (I2C) protocol is widely used for communication between microcontrollers and peripheral devices in embedded systems. It is a convenient and efficient method that allows multiple devices to communicate over just two wires. In this tutorial, we will explore the basics of I2C communication using an AVR Atmega-328 microcontroller.
What is I2C?
I2C is a serial communication protocol developed by Philips in the 1980s. It provides a simple and elegant master-slave communication scheme. I2C uses two wires for communication: a clock line (SCL) and a data line (SDA).
I2C supports multi-master communication, meaning multiple microcontrollers can act as masters on the bus and interact with slave devices. The protocol utilizes a 7-bit or 10-bit address scheme to uniquely identify devices on the bus.
Setting Up I2C Hardware
To use I2C, we need to connect our microcontroller to peripheral devices. The Atmega-328 has built-in hardware support for I2C communication, which is available on the two pins: SDA (Analog pin 4) and SCL (Analog pin 5).
To establish reliable communication, pull-up resistors should be connected to both SDA and SCL lines. These resistors ensure that the lines are pulled high when they are not being actively driven by devices. A typical value for these resistors is between 2.2kΩ and 10kΩ.
Enabling I2C Communication
Before we can start using the I2C interface on the Atmega-328, we need to enable it in our code. The AVR libraries provide a simple API to configure and utilize I2C functionality.
To begin, we need to include the avr/io.h
and util/twi.h
headers in our code. The avr/io.h
header file provides access to general-purpose input/output (GPIO) pins, while util/twi.h
gives us access to I2C-specific functions.
Next, we need to define the I2C bit rate. The bit rate determines the speed of communication. The Atmega-328 supports standard-mode (100kHz) and fast-mode (400kHz) communication. We can choose between these two by defining the appropriate clock frequency.
Now, let’s configure the I2C interface by initializing the control registers and enabling I2C functionality.
Writing and Reading Data
To initiate data transmission, the master sends a start condition followed by the slave address and a read/write bit. If the slave acknowledges the address, the master can send or receive data.
Let’s take a look at an example of writing data to a slave device.
|
|
The above code initializes the I2C bus by sending a start condition. It then transmits the slave address along with the write bit and waits for the address to be transmitted. After the address is acknowledged, the function sends the data and waits for it to be transmitted. Finally, it sends a stop condition to complete the transaction.
Reading data from a slave device can be accomplished with slight modifications to the i2c_write()
function. Let’s take a look at an example.
|
|
In this code, we send a start condition and transmit the slave address with the read bit. After the address is acknowledged, we switch the I2C interface to receive mode. We then wait for the data to be received, store it in a variable, and send a stop condition to end the transaction.
Conclusion
In this tutorial, we explored the basics of I2C communication using an AVR Atmega-328 microcontroller. We discussed the hardware setup required and provided a step-by-step guide to enable and utilize the I2C interface.
I2C is a versatile protocol that allows for seamless communication between microcontrollers and peripheral devices. With the knowledge gained from this tutorial, you can now incorporate I2C communication into your embedded systems and build more capable and interconnected devices. Happy coding!
References: