0% found this document useful (0 votes)
19 views17 pages

Correct - Lab 5

embedded systems lab5 with codes

Uploaded by

engr.ahmadali99
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
19 views17 pages

Correct - Lab 5

embedded systems lab5 with codes

Uploaded by

engr.ahmadali99
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 17

Page 1 of 14

Lab. 5
Software Coding of Communication Protocols

Interfacing RTC and LCD using I2C link

Objectives:

1. To understand the software implementation of I2C on ESP32 using GPIOs


2. File handling and managing software development for an embedded system
3. Interfacing multiple devices with ESP32 through I2C
4. Real-time data acquisition and timestamping

➢ Software implementation of I2C using GPIOs


I2C is a serial communication protocol that allows a microcontroller (or any digital controller)
to connect sensors, RTCs, displays and several other digital devices using two IO lines. Figure1
shows the waveforms of SDA and SCL lines to communicate a 3-byte message from the master
to the slave.

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);
}

void lcd_print(char *dat){


#define mkstr(dat)
#dat while(*dat != '\0' lcd_data(*(dat++)); //send single character to LCD
} //end lcd_print
void PCF8574_LCD_init(){
Page 4 of 14

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

lcd_data(':'); lcd_data((sec>>4)+48); lcd_data((sec&0x0F)+48);}


void app_main() { //UCHAR buff[20]; PCF8574_LCD_init(); DS1307_i2c_init();
cursor_position(0,3); lcd_print("ESP32 & DS1307"); delay_ms(500); Set_Time(23,59,47); //24H
time format
for(;;){ }//end for } Get_Time(); cursor_position(1,4); Display_Time();delay_ms(1000);
//function generates I2C NACK void DS1307_i2c_nack(){
gpio_set_direction(DS1307_I2C_SCL, GPIO_MODE_OUTPUT);
gpio_set_direction(DS1307_I2C_SDA, GPIO_MODE_OUTPUT);
gpio_set_level(DS1307_I2C_SDA, 1); DS1307_i2c_delay();
gpio_set_level(DS1307_I2C_SCL, 1); DS1307_i2c_delay();
gpio_set_level(DS1307_I2C_SCL, 0); DS1307_i2c_delay();}
//end DS1307_i2c_nack
//function to write an I2C packet void
DS1307_I2C_Write(uint8_t data){
uint8_t i;
gpio_set_direction(DS1307_I2C_SCL, GPIO_MODE_OUTPUT);
gpio_set_direction(DS1307_I2C_SDA, GPIO_MODE_OUTPUT);
gpio_set_level(DS1307_I2C_SCL, 0); DS1307_i2c_delay();
for (i = 0; i < 8; i++) {
if (data & 0x80) {
gpio_set_level(DS1307_I2C_SDA, 1); DS1307_i2c_delay();
}else { }gpio_set_level(DS1307_I2C_SDA, 0);
DS1307_i2c_delay();
gpio_set_level(DS1307_I2C_SCL, 1); DS1307_i2c_delay();
gpio_set_level(DS1307_I2C_SCL, 0); DS1307_i2c_delay();
data <<= 1;
} //end for
gpio_set_level(DS1307_I2C_SCL, 0); DS1307_i2c_delay();
gpio_set_level(DS1307_I2C_SDA, 0); DS1307_i2c_delay();
//ignore ack from salve gpio_set_level(DS1307_I2C_SCL,
1); DS1307_i2c_delay(); DS1307_i2c_delay();
DS1307_i2c_delay(); gpio_set_level(DS1307_I2C_SCL, 0);
} //end DS1307_I2C_Write
//function to read an I2C packet uint8_t
DS1307_I2C_Read(uint8_t j){
uint8_t i,in,byte;
in = 0;
byte = 0;
gpio_set_direction(DS1307_I2C_SCL, GPIO_MODE_OUTPUT);
gpio_set_direction(DS1307_I2C_SDA, GPIO_MODE_INPUT);
gpio_set_level(DS1307_I2C_SCL, 0); DS1307_i2c_delay();
for(i=0; i<8; i++){
gpio_set_level(DS1307_I2C_SCL, 1); DS1307_i2c_delay();
byte <<= 1;
in = gpio_get_level(DS1307_I2C_SDA); byte |= in;
gpio_set_level(DS1307_I2C_SCL, 0); DS1307_i2c_delay(); }
//end for//send ACK if j = 1if(j){
DS1307_i2c_ack();
} //end if else{
DS1307_i2c_nack();
} //end else
return byte;
} //end DS1307_I2C_Read
Page 6 of 14

//Function to write to any


location of DS1307 void
WR_DS1307(uint8_t add,
uint8_t byte){
DS1307_i2c_start();
DS1307_I2C_Write(DS1307_AD
DR_W);
DS1307_I2C_Write(add);
DS1307_I2C_Write(byte);
DS1307_i2c_stop();
} //end WR_DS1307
//Function to read from
any location of DS1307
uint8_t RD_DS1307(uint8_t
add){
uint8_t out;
DS1307_i2c_start();
DS1307_I2C_Write(DS1307_AD
DR_W);
DS1307_I2C_Write(add);
DS1307_i2c_start();
DS1307_I2C_Write(DS1307_AD
DR_R);
out =
DS1307_I2C_Read(NACK);
return out;} //end
RD_DS1307
Page 7 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

You might also like