Overview
The Two Wire Interface (TWI) is a serial communication protocol that implements only two wires - Serial Data (SDA) and Serial Clock (SCL). It was developed by Phillip. This protocol is commonly used for communicating between on-board devices at short range. It saves the number of micro-processor I/O that traditionally uses the Motorola 6800 parallel data bus. TWI able to handles up to 127 TWI slave devices connects on a single two-wire bus. Many small footprint chips use this communication protocol such as EEPROM, Real Time Clock (RTC) chip, monochrome OLED display, I/O expansion chip, RFID Reader chip, etc.
![]() |
| Example Picture |
This protocol is easy to implement both hardware and software. Most of modern micro-controller has TWI/I2C interface. The user just needs to configure its overall operations such as clock setting, size of slave address (7-bit or 8-bit etc), sending data bytes to slave devices, and receiving data packets. Many programmers write a software TWI routine to implement this serial communication protocol. It's very easy and independence of dedicated micro-controller TWI module. It's universal because it is very easy to read and understand for most of programmer using C or Assembly language.
Arduino Wire Library
The Arduino IDE has many build-in libraries both hardware and software after finished installation. The Wire library is written in high level C++ language that is popular for its Object Oriented Programming (OOP) features.
To be able to call any function of this library, the programmer have to put, #include<Wire.h> that's already installed with Arduino IDE. These are some basic functions of this library,
Routines for Master Device Writing
- Begin
- beginTransmission
- write
- endTransmission
Routines for Master Device Reading
- requestFrom
- available
- read
There some build-in examples for this library. Go to File Menu > Examples > Wire, and click on any listed Sketch.
![]() |
| Wire Library Example |
DS1307 Real Time Clock (RTC) Example
The time keeping chip is widely used in most modern electronic equipment. Most of them uses the TWI communication interface because it doesn't need a high speed data communication. Its clock frequency is around 100KHz that is very suitable for most of data transmission. On the other hands, those chips are placed on board communicating at very short range.
To get started I installed a third-party Real Time Clock library. Install and open an example "DS1307_Simple.ino" to set and test the DS1307 RTC chip.
![]() |
| Open a DS1307 RTC example |
This example will set and get the date/time calendar data from the DS1307 Real Time Clock (RTC) chip. The Arduino Wire uses the TWI 7-bit slave address. So the 7-bit TWI slave of the DS1307/DS3231 is 0x68 instead of 0xD0.
![]() |
| Simple_DS1307.ino |
The RTC data is sent over the serial terminal.
ESP8266 TWI DS1307 RTC and 16x2 Character LCD
I added a 16x2 character LCD to the NodeMCU ESP-12E Module to show date and time reading from DS1307 Real Time Clock (RTC) chip. I use the installed LiquidCrystal Library created by another author. This Arduino Library is compatible with the ESP8266 IoT chip.
Schematic
I use my DIY ESP8266 TWI board to test this example.
![]() |
| Schematic DIY ESP8266 TWI Board |
DS1307 RTC and ESP-12E Connections
| ESP-12E | On-Board DS1307 |
|---|---|
| GND | GND |
| VCC | VIN or +3.3V |
| SCL | PIN D1 (GPIO5) |
| SDA | PIN D2 (GPIO4) |
We can not share these two pins with LCD. It doesn't work.
ESP-12E and HD44780 16x2 Character LCD Connections
I wire the 16x2 character LCD on breadboard.
| 16x2 LCD | ESP-12E |
|---|---|
| GND | GND |
| VCC | VIN |
| V0 | POT Output |
| RS | D0 (GPIO16) |
| R/W | GND |
| E | D3 (GPIO0) |
| D4 | D4 (GPIO2) |
| D5 | D5 (GPIO14) |
| D6 | D6 (GPIO12 |
| D7 | RX (GPIO3) |
| A | +3.3V or VIN |
| K | GND |
The ESP-12E pin D7(RX2) and D8(TX2) can not be used with the character LCD. It's reserve for on-board serial communication with host PC.
ESP-12E Arduino Source Code
I added the LiquidCrystal library to the original RTC source code.
/* for normal hardware wire use below */- #include <Wire.h> // must be included here so that Arduino library object file references work
- #include <RtcDS1307.h>
- RtcDS1307<TwoWire> Rtc(Wire);
- /* for normal hardware wire use above */
- #include <LiquidCrystal.h>
- const int rs = 16, en = 0, d4 = 2, d5 = 14, d6 = 12, d7 = 3;
- LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
- // handy routine to return true if there was an error
- // but it will also print out an error message with the given topic
- bool wasError(const char* errorTopic = "")
- {
- uint8_t error = Rtc.LastError();
- if (error != 0)
- {
- // we have a communications error
- // see https://www.arduino.cc/reference/en/language/functions/communication/wire/endtransmission/
- // for what the number means
- Serial.print("[");
- Serial.print(errorTopic);
- Serial.print("] WIRE communications error (");
- Serial.print(error);
- Serial.print(") : ");
- switch (error)
- {
- case Rtc_Wire_Error_None:
- Serial.println("(none?!)");
- break;
- case Rtc_Wire_Error_TxBufferOverflow:
- Serial.println("transmit buffer overflow");
- break;
- case Rtc_Wire_Error_NoAddressableDevice:
- Serial.println("no device responded");
- break;
- case Rtc_Wire_Error_UnsupportedRequest:
- Serial.println("device doesn't support request");
- break;
- case Rtc_Wire_Error_Unspecific:
- Serial.println("unspecified error");
- break;
- case Rtc_Wire_Error_CommunicationTimeout:
- Serial.println("communications timed out");
- break;
- }
- return true;
- }
- return false;
- }
- void setup ()
- {
- Serial.begin(115200);
- Serial.print("compiled: ");
- Serial.print(__DATE__);
- Serial.println(__TIME__);
- //--------RTC SETUP ------------
- // if you are using ESP-01 then uncomment the line below to reset the pins to
- // the available pins for SDA, SCL
- // Rtc.Begin(0, 2); // due to limited pins, use pin 0 and 2 for SDA, SCL
- Rtc.Begin();
- #if defined(WIRE_HAS_TIMEOUT)
- Wire.setWireTimeout(3000 /* us */, true /* reset_on_timeout */);
- #endif
- RtcDateTime compiled = RtcDateTime(__DATE__, __TIME__);
- printDateTime(compiled);
- Serial.println();
- if (!Rtc.IsDateTimeValid())
- {
- if (!wasError("setup IsDateTimeValid"))
- {
- // Common Causes:
- // 1) first time you ran and the device wasn't running yet
- // 2) the battery on the device is low or even missing
- Serial.println("RTC lost confidence in the DateTime!");
- // following line sets the RTC to the date & time this sketch was compiled
- // it will also reset the valid flag internally unless the Rtc device is
- // having an issue
- Rtc.SetDateTime(compiled);
- }
- }
- if (!Rtc.GetIsRunning())
- {
- if (!wasError("setup GetIsRunning"))
- {
- Serial.println("RTC was not actively running, starting now");
- Rtc.SetIsRunning(true);
- }
- }
- RtcDateTime now = Rtc.GetDateTime();
- if (!wasError("setup GetDateTime"))
- {
- if (now < compiled)
- {
- Serial.println("RTC is older than compile time, updating DateTime");
- Rtc.SetDateTime(compiled);
- }
- else if (now > compiled)
- {
- Serial.println("RTC is newer than compile time, this is expected");
- }
- else if (now == compiled)
- {
- Serial.println("RTC is the same as compile time, while not expected all is still fine");
- }
- }
- // never assume the Rtc was last configured by you, so
- // just clear them to your needed state
- Rtc.SetSquareWavePin(DS1307SquareWaveOut_1Hz);
- wasError("setup SetSquareWavePin");
- lcd.begin(16, 2);
- lcd.clear();
- // Print a message to the LCD.
- lcd.print("ESP12-E I2C");
- lcd.setCursor(0, 1);
- lcd.print("DS1307 RTC");
- delay(5000);
- lcd.clear();
- }
- void loop ()
- {
- if (!Rtc.IsDateTimeValid())
- {
- if (!wasError("loop IsDateTimeValid"))
- {
- // Common Causes:
- // 1) the battery on the device is low or even missing and the power line was disconnected
- Serial.println("RTC lost confidence in the DateTime!");
- }
- }
- RtcDateTime now = Rtc.GetDateTime();
- if (!wasError("loop GetDateTime"))
- {
- printDateTime(now);
- Serial.println();
- }
- delay(800);
- }
- #define countof(a) (sizeof(a) / sizeof(a[0]))
- void printDateTime(const RtcDateTime& dt)
- {
- char datestring[26];
- snprintf_P(datestring,
- countof(datestring),
- PSTR("%02u/%02u/%04u %02u:%02u:%02u"),
- dt.Month(),
- dt.Day(),
- dt.Year(),
- dt.Hour(),
- dt.Minute(),
- dt.Second() );
- Serial.print(datestring);
- lcd.setCursor(0, 0);
- lcd.print("Date: " + String(dt.Year()) + "/" + String(dt.Month()) + "/" + String(dt.Day()));
- lcd.setCursor(0, 1);
- lcd.print("Time: " + String(dt.Hour()) + ":" + String(dt.Minute()) + "/" + String(dt.Second()));
- }
Pictures
I tested this example using my DIY ESP8266 TWI Board.
Video







No comments:
Post a Comment