In this article let’s learn how to overcome the problem of data being destroyed once the NodeMCU resets. This problem persists in Arduino as well. To solve this in Arduino, we use EEPROM [Electrically Erasable Programmable Read-Only Memory]. It is a non-volatile memory where data is written. Here, non-volatile means that the data won’t be lost as soon as the power supply is cut. Hence, data is written permanently and it won’t change unless the user decides to. For a good analogy consider EEPROM as hard-drive that's on your computer.
But boards like NodeMCU have a flash memory which is more advanced than EEPROMs. In EEPROM, data is stored as bytes and hence, storing large amounts of data will be complex and the number of reads and writes is limited. Whereas in flash memory, it is like a thumb drive which has far more reads and writes than EEPROM. Along with this, by using a file system, we can create files, folders and users have the control to rename or delete whatever they create. Even though the file system is stored on the same flash chip as the program, when a new sketch is programmed, it does not modify file system contents. There are two file systems for utilizing the onboard flash on the ESP8266. One is SPIFFS and the other one is LittleFS. SPIFFS is currently deprecated and may be removed in future releases of the ESP core so let’s just focus on LittleFS.
LittleFS for the ESP8266 is mostly like a regular file system in a computer where navigation, creating, renaming, deleting or modifying the files are possible.
(Note: This article was originally published in CircuitDigest and along with co-author Lavanya R. You can find the original article here.)
SuppliesThese are the list of products which can help you do this project with ease
(Affiliate links)
- 16x2 LCD Display : https://amzn.to/3vBJV7s
- I2C module (PC8574T) : https://amzn.to/3vztt7F
- Bread board : https://amzn.to/3yMDobW
- NodeMCU : https://amzn.to/3fum4Re
- WeMos D1 mini (Alternative) : https://amzn.to/2TiGxjm
- Jumper wires (Male to Female) : https://amzn.to/3c1fBLJ
LCD stands for Liquid Crystal Display; is a cost-effective way of displaying text output of microcontrollers/development boards. A 16x2 LCD display can display 16 characters on each line and has 2 such lines. In case there are more lines of information that need to be displayed, messages can scroll through the LCD screen. Now, when it comes to displaying information that is more than “ON or OFF” there’s a limitation with LEDs and Seven Segment Displays since they can display “ON or OFF” state and alphanumeric characters respectively. This limitation can be circumvented easily by using LCD but they take up most of the pins of the microcontroller or the NodeMCU. To avoid this, we use an I2C module; by using I2C module, interfacing LCD can be achieved by only 4 pins.
First, connect the I2C module to the LCD display. Solder Female Header pins to LCD display and connect the I2C module in such a way that the four pins of the I2C (GND, VCC, SDA, SCL) point outwards.
Now to power the circuit, connect, GND pin of the I2C module to the GND pin of ESP8266 and connect the VCC of the I2C module to the Vin pin of ESP8266. (These two pins supply the power to the LCD screen)
Connect SDA of I2C module to D2 pin of ESP8266 Connect SCL of I2C module to D1 pin of ESP8266
Step 2: 16x2 LCD Code:For people who wants to know the basics can start here, if not you can jump to step - to start with LittleFS
#include <LiquidCrystal_I2C.h>
#include <Wire.h>
int lcdColumns = 16;int lcdRows = 2;
LiquidCrystal_I2C lcd(0x27, lcdColumns, lcdRows);
void setup(){
lcd.init(); lcd.backlight();
}
void loop()
{
lcd.setCursor(0, 0);
lcd.print("Hello World!");delay(1000);
lcd.clear();
lcd.setCursor(0,1);
lcd.print("Hello World!");
delay(1000);
lcd.clear();
}
#include <LiquidCrystal_I2C.h>
This library is included to interface using the I2C module.
int lcdColumns = 16;int lcdRows = 2;
These two lines are used to set the LCD number of columns and rows; in our case, it’s 16 columns and 2 rows.
LiquidCrystal_I2C lcd(0x27, lcdColumns, lcdRows);
This is to set LCD address, number of columns and rows. (if you don't know your display address, run an I2C scanner sketch)
void setup()
{
lcd.init();
lcd.backlight();
}
Void setup function is run only once so here, initialization and declaration is done. “lcd.init();” is used to initialize LCD and “lcd.backlight();” is used to turn ON backlight of the LCD display.
lcd.setCursor(0, 0);
In the void loop, “.setCursor” function is used to set the cursor to the required position. Since we want to display the message “Hello World!” in the first column, first row, we give the position “(0, 0)”
lcd.print("Hello World!");
delay(1000);
lcd.print” function will print whatever the message is given. Here, Let’s display “Hello World!” and will create a delay of 1 second. This makes sure that the message displayed will stay long enough for us to see it properly.
lcd.clear();
This function will clear the display to print new message.
lcd.setCursor(0,1);
Now, to create a little animation, let’s set cursor to first column, second row so after displaying the message on the first row for a second, it will shift to second row.
lcd.print("Hello World!");
delay(1000);
After setting to second row, print the same message to display and the delay will make sure that the message will stay for 1 second on the second row as well.
lcd.clear();
This will clear the screen so next time it’s convenient to print messages. This is not absolutely required but it’s good practice to write program this way.
Step-3: LittleFs With 16x2 LCD Display and ESP8266 [Code]The circuit for using LittleFs to write, read and delete files from flash memory remains same as the previous step to display “Hello World”
#include <LiquidCrystal_I2C.h>
#include <Wire.h>
#include <LittleFS.h>
// set the LCD number of columns and rows
int lcdColumns = 16;
int lcdRows = 2;
// set LCD address, number of columns and rows
LiquidCrystal_I2C lcd(0x27, lcdColumns, lcdRows);
//function prototypes
void readData();
void writeData(String data);
void deleteData();
void setup() {
//Start the serial monitor
Serial.begin(115200);
// initialize LCD
lcd.init();
// turn on LCD backlight
lcd.backlight();
// set cursor to first column, first row
lcd.setCursor(0, 0);
lcd.print("Little FS Demo");
delay(1000);
//Start LittleFS
if(!LittleFS.begin()){
Serial.println("An Error has occurred while mounting LittleFS");
//Print the error on display
lcd.clear();
lcd.print("Mounting Error");
delay(1000);
return;
}
//Read the saved data
readData();
}
void loop() {
//Take input from user on serial monitor
if(Serial.available())
{
String data = Serial.readString();
Serial.println(data);
if(data == "D") // To delete the file
{
deleteData();
Serial.println("File deleted!");
return;
}
else if(data == "R") // To read the file
{
readData();
return;
}
Serial.println("Writing Data...");
writeData(data);
Serial.println("done Writing Data!");
}
}
void readData()
{
//Open the file
File file = LittleFS.open("/SavedFile.txt", "r");
//Check if the file exists
if(!file){
//Read the file data and display it on LCD
Serial.println("No Saved Data!");
lcd.clear();
lcd.print("No Saved Data!");
return;
}
lcd.clear();
lcd.print("Saved Data :");
// set cursor to first column, second row
lcd.setCursor(0,1);
//Display on the LCD
while(file.available()){
lcd.write(file.read());
}
//reset cursor poisition
lcd.setCursor(0,0);
//Close the file
file.close();
}
void writeData(String data)
{
//Open the file
File file = LittleFS.open("/SavedFile.txt", "w");
//Write to the file
file.print(data);
delay(1);
//Close the file
file.close();
Serial.println("Write successful");
lcd.clear();
lcd.print("Data Saved :");
// set cursor to first column, second row
lcd.setCursor(0,1);
// print the data on the LCD
lcd.print(data);
// reset cursor position
lcd.setCursor(0,0);
}
void deleteData()
{
//Remove the file
LittleFS.remove("/SavedFile.txt");
lcd.clear();
lcd.print("Data Deleted");
}
These below libraries are required to work with LCD display, I2C and LittleFs.
#include <LiquidCrystal_I2C.h>
#include <Wire.h>
#include <LittleFS.h>
int lcdColumns = 16;
int lcdRows = 2;
This is to set the LCD number of columns and rows. In our case, 16x2 which means 16 columns and 2 rows.
LiquidCrystal_I2C lcd(0x27, lcdColumns, lcdRows);
This function is used to set the LCD address, number of columns and rows.
void readData();
void writeData(String data);
void deleteData();
These are function prototypes. To read the data to the flash memory use the custom function “readData()”. Similarly, “writeData” and “deleteData” are custom functions to write data and to delete data from LittleFs respectively.
Serial.begin(115200);
Start the serial monitor and set the baud rate to 115200.
lcd.init();
lcd.backlight();
“lcd.init” function will initialise LCD and.backlight function will turn on LCD backlight
lcd.setCursor(0, 0);
lcd.print("Little FS Demo");
delay(1000);
Like before, this will set the cursor to the first column, first row and print the message “Little FS Demo” and wait for a second.
if(!LittleFS.begin())
{
Serial.println("An Error has occurred while mounting LittleFS");
lcd.clear();
lcd.print("Mounting Error");
delay(1000);
return;
}
Here, this part of program is used because in case Little Fs fails to start then an error message should be display to notify the user that Little Fs failed to start.
To check whether the file has opened correctly, if it doesn’t open correctly, it will print an error message and end the function. Or it will print the data written whatever was written earlier. On the LCD display, “Mounting Error” message will be displayed.
readData();
This line of code is used to read the saved data.
void loop()
{
if(Serial.available())
{
String data = Serial.readString();
Serial.println(data);
if(data == "D")
{
deleteData();
Serial.println("File deleted!");
return;
}
else if(data == "R")
{
readData();
Return;
}
Serial.println("Writing Data...");
writeData(data);
Serial.println("done Writing Data!");}
}
When the Serial receives some data from the serial monitor the data is read using “serial.readString()” and stored in a string “data”. Then it’ll check to see what command the user has entered and perform delete / read / write based on it.
void readData()
{
File file = LittleFS.open("/SavedFile.txt", "r");
if(!file)
{
Serial.println("No Saved Data!");
lcd.clear();
lcd.print("No Saved Data!"); return;
}
lcd.clear();
lcd.print("Saved Data :");
lcd.setCursor(0,1);
while(file.available())
{
lcd.write(file.read());
}lcd.setCursor(0,0);
file.close();
}
This function will open the LittleFs file and inside that saved text file and display it on serial monitor and the LCD screen.
void writeData(String data)
{
//Open the file
File file = LittleFS.open("/SavedFile.txt", "w");
//Write to the file
file.print(data);
delay(1);
//Close the file
file.close();
Serial.println("Write successful");
lcd.clear();
lcd.print("Data Saved :");
// set cursor to first column, second row
lcd.setCursor(0,1);
// print the data on the LCD
lcd.print(data);
// reset cursor position
lcd.setCursor(0,0);
}
This function will open the LittleFs file and write the user data and display it on serial monitor and the LCD screen.
void deleteData()
{
//Remove the file
LittleFS.remove("/SavedFile.txt");
lcd.clear();
//update the display
lcd.print("Data Deleted");
}
This function will delete the LittleFs file and write the user data and display it on serial monitor and the LCD screen.
Step 4: Little FS WorkingThis is writing the data to the flash memory. This is very simple. The code is written in such a way that it allows the user to type the data very easily. Just open the serial monitor and type the data and press ‘enter’ (Make sure that the Baud rate = 115200 and no line ending is selected). whatever is typed is taken as the data and it is saved to LittleFs file system. The LittleFs file system is mounted on Flash memory of ESP8266. Other than writing in the LittleFs file system, two other tasks can be done. Those are reading and deleting. To do that, the code is written in such a way that it takes input from the user and does the function that the user requests.
When the user enters “D” the file is deleted and “R” to read the file.
(NOTE: it is case sensitive and also any error like “DD” or “dD” instead of “D” will be considered as input data and this will be overwritten on the existing data. The same goes for "R" to read the file)
Step 5: Final ThoughtsThis was just an introduction to LittleFS type of documentation. You can take is a step further and take input from sensor and try to store the collected data in LittleFS (although it's not a viable project since the available flash memory is less and not effective to store data).
If you have any questions regarding the project, do not hesitate to comment down below and for projects checkout my hackster profile.
Need to Develop This Project Into a PCB?Getting a electronics project into production would be nightmare. To ease you into the production world we have developed a platform (PCB CUPID) for PCB enthusiasts and hobbyists to ask and answer questions related to PCB design, fabrication, and assembly.
In addition to the Q&A feature, this website also has a wealth of blog posts and useful resources to help you learn about developing and manufacturing printed circuit boards. Whether you're a beginner looking for a crash course on PCB basics, or an experienced designer looking for tips and tricks, you'll find something of value on the site
So head on over and check it out, and don't forget to participate in the Q&A community to get help and share your own knowledge. Thanks!
Important NoteYou can download the LiquidCrystal_I2C from this link.
To install follow this step
Go to Arduino IDE ---> Sketch - --> Include Library ---> Add .ZIP Library ---> select this zip file
if you like to see the original article click here.
Comments