The task is to create a unit preference management system using a microcontroller, where the device allows users to select their preferred measurement units for various parameters such as Temperature, Distance, Weight, and Volume through a serial terminal (e.g., PuTTY or Arduino IDE).
Requirements
Why Use EEPROM?
EEPROM (Electrically Erasable Programmable Read-Only Memory) is a form of non-volatile memory that retains stored data even when power is turned off.
It is ideal for this application as it allows the system to store and recall user preferences reliably across restarts, ensuring a consistent user experience.
This task can be implemented on the following microcontrollers
We are using the ESP32 DevKitC v4 development board and programming it using the Arduino IDE.
ESP32 does not have a real EEPROM chip inside. Instead, part of its Flash memory is used to simulate EEPROM behavior.
Connect the ESP32 development board to your computer using a USB cable.
#include <EEPROM.h>
//Constants for Menu Options
const char* tempUnits[] = { "Celsius", "Fahrenheit" };
const char* distUnits[] = { "Kilometers", "Miles" };
const char* weightUnits[] = { "Kilograms", "Pounds" };
const char* volumeUnits[] = { "Liters", "Gallons" };
//Struct to hold user preferences
struct Preferences {
uint8_t tempUnit;
uint8_t distUnit;
uint8_t weightUnit;
uint8_t volumeUnit;
};
Preferences userPreferences;
//EEPROM Configuration
const int eepromAddress = 0;
#define EEPROM_SIZE sizeof(Preferences)
void setup() {
delay(2000);
Serial.begin(115200);
EEPROM.begin(EEPROM_SIZE);
EEPROM.get(eepromAddress, userPreferences);
// Validate stored preferences
if (userPreferences.tempUnit > 1 || userPreferences.distUnit > 1 || userPreferences.weightUnit > 1 || userPreferences.volumeUnit > 1) {
resetPreferences();
}
displayCurrentPreferences();
displayMenu();
}
void loop() {
if (Serial.available()) {
handleMenuInput();
}
}
//Display Current Preferences
void displayCurrentPreferences() {
Serial.println("\nCurrent Preferences:");
Serial.print("1. Temperature: ");
Serial.println(tempUnits[userPreferences.tempUnit]);
Serial.print("2. Distance: ");
Serial.println(distUnits[userPreferences.distUnit]);
Serial.print("3. Weight: ");
Serial.println(weightUnits[userPreferences.weightUnit]);
Serial.print("4. Volume: ");
Serial.println(volumeUnits[userPreferences.volumeUnit]);
Serial.println();
}
//Display Menu
void displayMenu() {
Serial.println("\nMenu Options:");
Serial.println("1: Set Temperature Unit");
Serial.println("2: Set Distance Unit");
Serial.println("3: Set Weight Unit");
Serial.println("4: Set Volume Unit");
Serial.println("5: Reset to Default Preferences");
Serial.println("Enter your choice (1–5): ");
}
//Handle User Input
void handleMenuInput() {
static int option = -1;
String input = Serial.readStringUntil('\n');
input.trim();
// Step 1: Get the menu option
if (option == -1) {
option = input.toInt();
if (option < 1 || option > 5) {
Serial.println("Invalid option! Please enter 1–5.");
option = -1;
displayMenu();
return;
}
if (option == 5) {
resetPreferences();
displayCurrentPreferences();
option = -1;
displayMenu();
return;
}
// Ask for the preference value based on selected option
switch (option) {
case 1:
Serial.println("Enter Temperature Unit (0: Celsius, 1: Fahrenheit): ");
break;
case 2:
Serial.println("Enter Distance Unit (0: Kilometers, 1: Miles): ");
break;
case 3:
Serial.println("Enter Weight Unit (0: Kilograms, 1: Pounds): ");
break;
case 4:
Serial.println("Enter Volume Unit (0: Liters, 1: Gallons): ");
break;
}
return;
}
// Step 2: Get and validate preference value
int value = input.toInt();
if (value < 0 || value > 1) {
Serial.println("Invalid preference! Must be 0 or 1.");
option = -1;
displayMenu();
return;
}
// Step 3: Apply based on selected option
switch (option) {
case 1:
userPreferences.tempUnit = value;
break;
case 2:
userPreferences.distUnit = value;
break;
case 3:
userPreferences.weightUnit = value;
break;
case 4:
userPreferences.volumeUnit = value;
break;
}
savePreferences();
Serial.println("Preference updated successfully!");
displayCurrentPreferences();
// Reset for next input
option = -1;
displayMenu();
}
//Save Preferences to EEPROM
void savePreferences() {
EEPROM.put(eepromAddress, userPreferences);
if (EEPROM.commit()) {
Serial.println("Preferences Saved!");
} else {
Serial.println("Error saving preferences!");
}
}
//Reset to Default
void resetPreferences() {
userPreferences = { 0, 0, 0, 0 }; // Default values
savePreferences();
Serial.println("Preferences Reset to Default!");
}
tempUnit, distUnit, weightUnit, volumeUnit — each representing a binary choice (0 or 1).EEPROM.begin(EEPROM_SIZE) and loads saved data using EEPROM.get().resetPreferences() to restore defaults.handleMenuInput() whenever data is available.displayCurrentPreferences()tempUnits[userPreferences.tempUnit]).displayMenu()handleMenuInput()savePreferences().EEPROM.commit() to make data permanent.savePreferences()EEPROM.put() and commits the change.resetPreferences()EEPROM.begin(8000)) can corrupt other Flash data or cause runtime errors. EEPROM.commit() only when values actually change.EEPROM.commit() after writingWe are using the Arduino UNO development board and programming it using the Arduino IDE.
Connect the Arduino UNO development board to your computer using a USB cable.
We are going to use EEPROM.h library to implement this task. In Arduino UNO, there is a separate 1KB EEPROM chip available.
#include <EEPROM.h>
// Constants for Menu Options
const char* tempUnits[] = { "Celsius", "Fahrenheit" };
const char* distUnits[] = { "Kilometers", "Miles" };
const char* weightUnits[] = { "Kilograms", "Pounds" };
const char* volumeUnits[] = { "Liters", "Gallons" };
//Struct to hold user preferences
struct Preferences {
uint8_t tempUnit; // 0: Celsius, 1: Fahrenheit
uint8_t distUnit; // 0: Kilometers, 1: Miles
uint8_t weightUnit; // 0: Kilograms, 1: Pounds
uint8_t volumeUnit; // 0: Liters, 1: Gallons
};
Preferences userPreferences;
// EEPROM address for preferences
const int eepromAddress = 0;
//Global Variables
int currentOption = -1; // Tracks selected option
void setup() {
Serial.begin(9600);
delay(1000);
// Load preferences from EEPROM
EEPROM.get(eepromAddress, userPreferences);
// Validate loaded preferences
if (userPreferences.tempUnit > 1 || userPreferences.distUnit > 1 || userPreferences.weightUnit > 1 || userPreferences.volumeUnit > 1) {
resetPreferences();
}
displayCurrentPreferences();
displayMenu();
}
void loop() {
if (Serial.available()) {
handleMenuInput();
}
}
//Display Current Preferences
void displayCurrentPreferences() {
Serial.println("\nCurrent Preferences:");
Serial.print("1. Temperature: ");
Serial.println(tempUnits[userPreferences.tempUnit]);
Serial.print("2. Distance: ");
Serial.println(distUnits[userPreferences.distUnit]);
Serial.print("3. Weight: ");
Serial.println(weightUnits[userPreferences.weightUnit]);
Serial.print("4. Volume: ");
Serial.println(volumeUnits[userPreferences.volumeUnit]);
Serial.println();
}
//Display Menu
void displayMenu() {
Serial.println("\nMenu Options:");
Serial.println("1: Set Temperature Unit ");
Serial.println("2: Set Distance Unit ");
Serial.println("3: Set Weight Unit ");
Serial.println("4: Set Volume Unit ");
Serial.println("5: Reset to Default Preferences");
Serial.println("Enter your choice (1–5): ");
}
//Handle Menu Input
void handleMenuInput() {
String input = Serial.readStringUntil('\n');
input.trim();
// Step 1: If no option selected, expect menu choice
if (currentOption == -1) {
int option = input.toInt();
if (option < 1 || option > 5) {
Serial.println("Invalid option! Please enter a number between 1–5.");
displayMenu();
return;
}
if (option == 5) {
resetPreferences();
displayCurrentPreferences();
displayMenu();
return;
}
currentOption = option;
// Ask for preference value based on option
switch (option) {
case 1:
Serial.println("Enter Temperature Unit (0: Celsius, 1: Fahrenheit): ");
break;
case 2:
Serial.println("Enter Distance Unit (0: Kilometers, 1: Miles): ");
break;
case 3:
Serial.println("Enter Weight Unit (0: Kilograms, 1: Pounds): ");
break;
case 4:
Serial.println("Enter Volume Unit (0: Liters, 1: Gallons): ");
break;
}
return;
}
// Step 2: If option already selected, expect preference value
int value = input.toInt();
if (value < 0 || value > 1) {
Serial.println("Invalid value! Must be 0 or 1.");
currentOption = -1;
displayMenu();
return;
}
// Update based on option
switch (currentOption) {
case 1:
userPreferences.tempUnit = value;
Serial.print("Temperature Unit set to: ");
Serial.println(tempUnits[value]);
break;
case 2:
userPreferences.distUnit = value;
Serial.print("Distance Unit set to: ");
Serial.println(distUnits[value]);
break;
case 3:
userPreferences.weightUnit = value;
Serial.print("Weight Unit set to: ");
Serial.println(weightUnits[value]);
break;
case 4:
userPreferences.volumeUnit = value;
Serial.print("Volume Unit set to: ");
Serial.println(volumeUnits[value]);
break;
}
savePreferences();
// Reset and show updates
currentOption = -1;
displayCurrentPreferences();
displayMenu();
}
//Save Preferences to EEPROM
void savePreferences() {
EEPROM.put(eepromAddress, userPreferences);
Serial.println("Preferences Saved!");
}
//Reset to Default
void resetPreferences() {
userPreferences = { 0, 0, 0, 0 }; // Default: Celsius, Kilometers, Kilograms, Liters
savePreferences();
Serial.println("Preferences Reset to Default!");
}tempUnit: 0 = Celsius, 1 = FahrenheitweightUnit: 0 = Kilograms, 1 = PoundsvolumeUnit: 0 = Liters, 1 = Gallonssetup()EEPROM.get().loop()handleMenuInput() to process the user’s command.displayCurrentPreferences()displayMenu()handleMenuInput()savePreferences()EEPROM.put().resetPreferences()