Correct - Lab 5
Correct - Lab 5
Lab. 5
Software Coding of Communication Protocols
Objectives:
Figure 1
The nature of I2C protocol is simple and this simplicity allows us to use two GPIOs on ESP32
to work as SDA and SCL lines. This method of implementing the I2C using GPIOs serves as a
software blueprint for those processors or microcontrollers that are not equipped with an I2C
channel. Moreover, this approach allows to virtually implement multiple I2C channels on a
single embedded controller such as ESP32. As a first example, software I2C is implemented to
communicate with PCF8574 I2C to parallel converter that drives a 20x4 LCD. The C/C++
program given in Program 1 serves as blueprint to create a channel on ESP32 for I2C
communication.LCD that is connected with PCF8574, whereas PCF8574 is interfaced with
ESP32 through software-implemented I2C channel. Run the program given in Program 1
show the output to the lab instructor. Make use of breadboard to implement the circuit.
Follow the safety conditions.
Safety Instructions:
➢ Disconnect the ESP32 board from the computer while setting up the circuit.
➢ Constructing circuit around ESP32 while it is connected with computer can damage both
the board and the computer.
➢ Only connect the ESP32 board with the computer when the circuit has been fully
constructed.
Page 2 of 14
Program 1:
This program has a dependency file PCF8574_LCD.c that contains the PCF8574 interfacing and
an LCD control function using software I2C. The objective of this exercise is to understand
how to manage different software parts at the development phase of an embedded system.
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "PCF8574_LCD.c"
void delay_ms(unsigned intms){
vTaskDelay(pdMS_TO_TICKS(ms));
}void app_main() { char buff[20]; PCF8574_LCD_init();
cursor_position(0,0);lcd_print("ABCDEFGHIJKLMNOPQRST")
;cursor_position(1,0);lcd_print("01234567890123456789"
);cursor_position(2,0);lcd_print("abcdefghijklmnopqrst
")cursor_position(3,0);lcd_print("98765432109876543210
");for(;;);}
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h
#define PCF8574_I2C_SCL 18
#define PCF8574_I2C_SDA 19
#define cmd_delay 20
#define pulse_delay 10
#define PCF8574_I2C_DELAY 10
#define PCF8574_ADDR 0x4E
#define LCD_EN 0x04
#define LCD_RW 0x02 #define LCD_RS 0x01
void PCF8574_i2c_delay() {
esp_rom_delay_us(PCF8574_I2C_DELAY);
} void PCF8574_i2c_init() {
gpio_set_direction(PCF8574_I2C_SCL, GPIO_MODE_OUTPUT);
gpio_set_direction(PCF8574_I2C_SDA, GPIO_MODE_OUTPUT);
gpio_set_level(PCF8574_I2C_SCL, 1);
gpio_set_level(PCF8574_I2C_SDA, 1);
gpio_pullup_en(PCF8574_I2C_SCL);
gpio_pullup_en(PCF8574_I2C_SDA);
} void PCF8574_i2c_start() { gpio_set_level(PCF8574_I2C_SDA, 1);
gpio_set_level(PCF8574_I2C_SCL, 1);
PCF8574_i2c_delay();
gpio_set_level(PCF8574_I2C_SDA, 0); // Start condition
PCF8574_i2c_delay();
gpio_set_level(PCF8574_I2C_SCL, 0);
}void PCF8574_i2c_stop() { gpio_set_level(PCF8574_I2C_SDA, 0);
gpio_set_level(PCF8574_I2C_SCL, 1);
PCF8574_i2c_delay();
gpio_set_level(PCF8574_I2C_SDA, 1); // Stop condition
PCF8574_i2c_delay();
}void PCF8574_i2c_write_bit(uint8_t bit) { gpio_set_level(PCF8574_I2C_SDA, bit);
PCF8574_i2c_delay(); gpio_set_level(PCF8574_I2C_SCL, 1); PCF8574_i2c_delay();
Page 3 of 14
gpio_set_level(PCF8574_I2C_SCL, 0);
} uint8_t PCF8574_i2c_read_bit() {
gpio_set_level(PCF8574_I2C_SDA, 1); // Release SDA to allow slave to control it
PCF8574_i2c_delay();
gpio_set_level(PCF8574_I2C_SCL, 1);
PCF8574_i2c_delay();
uint8_t bit = gpio_get_level(PCF8574_I2C_SDA);
gpio_set_level(PCF8574_I2C_SCL, 0);
return bit;
} void PCF8574_i2c_write_byte(uint8_t byte
for (int i = 0; i < 8; i++) {
PCF8574_i2c_write_bit((byte & 0x80) !=
0); <<= 1;
}PCF8574_i2c_read_bit();
} void PCF8574_write(uint8_t data) {
PCF8574_i2c_start();
PCF8574_i2c_write_byte(PCF8574_ADDR);
PCF8574_i2c_write_byte(data);
PCF8574_i2c_stop();
}void lcd_send_enable_pulse(uint8_t data) { PCF8574_write(data | LCD_EN); // Enable high
esp_rom_delay_us(100);
PCF8574_write(data & ~LCD_EN); // Enable low
esp_rom_delay_us(100);
}void lcd_send(uint8_t value, bool isData) { uint8_t high_nibble = (value & 0xF0);uint8_t
low_nibble = ((value << 4) & 0xF0); // Low nibble if (isData) {
high_nibble |= LCD_RS;
low_nibble |= LCD_RS;
lcd_send_enable_pulse(h
igh_nibble);
lcd_send_enable_pulse(low_nibble);}void lcd_command(uint8_t command) {
lcd_send(command, false); }void lcd_data(uint8_t data) lcd_send(data, true);
}void lcd_init() { vTaskDelay(pdMS_TO_TICKS(1000)); (0x28);
lcd_command(0x0C); // display on, cursor off
lcd_command(0x06); // cursor auto-right move
lcd_command(0x02); // cursor at home
lcd_command(0x01); // clear display
vTaskDelay(pdMS_TO_TICKS(200));}void
cursor_position(char r, char c){
if(r==0) //row 0
lcd_command(0x80+c);
if(r==1) //row 1
lcd_command(0xC0+c);
if(r==2) //row 2
lcd_command(0x94+c);
if(r==3) //row 3
lcd_command(0xD4+c);
}
PCF8574_i2c_init();
lcd_init();}
Task 1:
Make changes in Program 1 such that it uses other GPIOs than those used in program 1 for
implementing I2C channel. Construct the circuit and show the output to the lab instructor.
Task 2:
Make changes in Program 1 such that it implements two software I2C channels on ESP32.
Interface two LCDs and show some text on each LCD. Construct the circuit and show the
output to the lab instructor.
➢ Interfacing Real-Time Clock (RTC)
A real-time clock (RTC) is a digital circuit that automatically computes the time, date and year.
Such a circuit is DS1307 RTC that has I2C interface and provides features of implementing a
complete time management system. DS1307 has a 64x8 volatile memory that can be written to
and read from via I2C interface. Memory locations from 0 to 7 store timing information that
are updated automatically. The information stored in these locations is shown in figure 2.
Figure 2
The memory locations from 08H (8) to 3FH (63) are general-purpose read/write locations.
Program 2:
Copy the following code into the main.c file of your project.
#include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "driver/gpio.h" #include
"PCF8574_LCD.c" #include "DS1307.c"#include <stdio.h>
typedef unsigned char UCHAR;
typedef unsigned int UINT;
UCHAR hrs,min,sec
void delay_ms(unsigned int ms){ vTaskDelay(pdMS_TO_TICKS(ms));
}UCHAR dec2bcd(UCHAR num){ return(((num/10)*6)+num);
}void Set_Time(UCHAR h,UCHAR m,UCHAR s){
WR_DS1307(0,dec2bcd(s)&0x7F); //write seconds with CH=0
WR_DS1307(1,dec2bcd(m)); //write minutes
WR_DS1307(2,dec2bcd(h)); //write hours
} //end Set_Time
void Get_Time(){sec = RD_DS1307(0); min =
RD_DS1307(1);hrs = RD_DS1307(2);
}void Display_Time(){lcd_data((hrs>>4)+48);
lcd_data((hrs&0x0F)+48);lcd_data(':');lcd_data((min
>>4)+48); lcd_data((min&0x0F)+48);
Page 5 of 14
Lab Task 1:
Develop a C/C++ code that interfaces DS1307 RTC with ESP32 using dedicated I2C channel
and LCD using software I2C. The program should display the following information on LCD
according to the following format.
On line 1: Display the time
On line 2: Display name of the day
On line 3: Display date and name of the month
On line 4: Display year
#include <Wire.h> char timeBuffer[9];
#include <LiquidCrystal_I2C.h> snprintf(timeBuffer, sizeof(timeBuffer),
#include "RTClib.h" // Library for DS1307 "%02d:%02d:%02d", now.hour(), now.minute(),
RTC now.second()); lcd.setCursor(0, 0);
RTC_DS1307 rtc; lcd.print("Time: "); lcd.print(timeBuffer);
LiquidCrystal_I2C lcd(0x27, 16, 2 const char* daysOfTheWeek[] = {"Sunday",
"Monday", "Tuesday", "Wednesday",
void setup() { "Thursday", "Friday", "Saturday"};
Wire.begin(); lcd.setCursor(0, 1);
lcd.init(); lcd.print(daysOfTheWeek[now.dayOfTheWeek()
lcd.backlight(); const char* months[] = {"Jan", "Feb", "Mar",
if (!rtc.begin()) { "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct",
"Nov", "Dec"};
lcd.print("RTC not found");
char dateBuffer[20];
while (1);}
snprintf(dateBuffer, sizeof(dateBuffer), "%02d
if (!rtc.isrunning()) { %s", now.day(), months[now.month() - 1]);
lcd.print("RTC updating..."); lcd.setCursor(0, 2);
rtc.adjust(DateTime(F(__DATE__), lcd.print(dateBuffer);
F(__TIME__))); }lcd.clear();
lcd.setCursor(0, 3);
)void loop() {
lcd.print("Year: ");
DateTime now = rtc.now();
lcd.print(now.year());
delay(1000); }
Lab Task 2:
Develop a C/C++ code that interfaces DS1307 RTC with ESP32 using dedicated I2C channel
and LCD using software I2C. The program should display the following information on LCD
according to the following format.
On line 1: Display the time
On line 2: Display name of the day
On line 3: Display date and name of the month
On line 4: Display year
The program should set a soft-coded alarm (with seconds, minutes, hours, day, date, month and
year) and when time matches the alarm data, on board LED should flash.The program should
also include a pushbutton. Alarm data should be displayed on LCD forone second when
pushbutton is pressed.
Page 8 of 14
#include <Wire.h>
#include <LiquidCrystal_I2C.h> lcd.print(days[alarmTime.dayOfTheWeek()]);
#include "RTClib.h" lcd.setCursor(0, 2);
RTC_DS1307 rtc; lcd.printf("%02d %s", alarmTime.day(),
LiquidCrystal_I2C lcd(0x27, 16, 2); months[alarmTime.month() - 1]);
#define LED_PIN 2 lcd.setCursor(0, 3);
#define BUTTON_PIN 4 lcd.print(alarmTime.year());
DateTime alarmTime(2024, 12, 4, 12, 0, 0); delay(1000);}
bool alarmTriggered = false; delay(1000);
void setup() { } const char *days[] = {"Sun", "Mon", "Tue",
Wire.begin(); "Wed", "Thu", "Fri", "Sat"};
lcd.init(); lcd.print(days[now.dayOfTheWeek()]);
lcd.backlight(); lcd.setCursor(0, 2);
pinMode(LED_PIN, OUTPUT); const char *months[] = {"Jan", "Feb",
pinMode(BUTTON_PIN, "Mar", "Apr", "May", "Jun", "Jul", "Aug",
INPUT_PULLUP); "Sep", "Oct", "Nov", "Dec"};
if (!rtc.begin() || !rtc.isrunning()) lcd.printf("%02d %s", now.day(),
rtc.adjust(DateTime(F(__DATE__), months[now.month() - 1]);
F(__TIME__))); lcd.setCursor(0, 3);
} lcd.print(now.year());
void loop() { if (now.unixtime() == alarmTime.unixtime()
DateTime now = rtc.now(); && !alarmTriggered) {
lcd.setCursor(0, 0); alarmTriggered = true;
lcd.printf("%02d:%02d:%02d", for (int i = 0; i < 5; i++) {
now.hour(), now.minute(), now.second()); digitalWrite(LED_PIN, HIGH);
lcd.setCursor(0, 1); { delay(200);
lcd.clear(); lcd.setCursor(0, 0); digitalWrite(LED_PIN, LOW);
lcd.printf("%02d:%02d:%02d", delay(200); }}
alarmTime.hour(), alarmTime.minute(), if (digitalRead(BUTTON_PIN) == LOW)
alarmTime.second());
lcd.setCursor(0, 1);
Lab Task 3:
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include "RTClib.h"
RTC_DS1307 rtc;
LiquidCrystal_I2C lcd(0x27, 16, 2);
#define TEMP_PIN 34
void setup() { Wire.begin(); lcd.init(); lcd.backlight(); if (!rtc.begin() ||
!rtc.isrunning()) rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
}void loop() { DateTime now = rtc.now();int rawValue = analogRead(TEMP_PIN);
float voltage = (rawValue / 4095.0) * 3.3; float temperature = voltage * 100.0;
lcd.setCursor(0, 0);
lcd.printf("%02d:%02d:%02d", now.hour(), now.minute(), now.second());
lcd.setCursor(0, 1);
lcd.printf("%02d/%02d/%04d", now.day(), now.month(), now.year());
lcd.setCursor(0, 2);
lcd.printf("Temp: %.2fC", temperature); delay(1000);
Page 9 of 14
Page 10 of 14
Page 11 of 14
Page 12 of 14
Page 13 of 14
Page 14 of 14
Page 15 of 14
Page 16 of 14
Page 17 of 14