Arduino Simulation ELP305

Arduino Simulation ELP305

Embedded Systems Laboratory

Experiments covering GPIO, displays, sensors, waveform generation, RTC systems, automation, and embedded software development.

Building Embedded Systems with Arduino: A Digital Electronics

This article documents a series of Arduino-based embedded systems projects completed as part of a Digital Electronics laboratory course. The projects progress from basic GPIO control and display interfacing to automation systems, waveform generation, and real-time monitoring using sensors, communication buses, and peripheral devices.

The objective was not only to implement working hardware but also to understand the engineering principles behind digital logic, interfacing, timing, automation, and real-time embedded software development.


Table of Contents


List of Figures

List of Figures

Experiment 0 — Digital Output and Display Interfacing

FigureDescription
Fig. 0.1LED Blink Circuit Diagram
Fig. 0.27-Segment Display Output
Fig. 0.3LED Matrix Character Display

Experiment 1 — Environmental Monitoring and Automation

FigureDescription
Fig. 1.1Temperature Control System — Heating Condition
Fig. 1.2Temperature Control System — Cooling Condition
Fig. 1.3Smart Weather Monitor — Hot Weather
Fig. 1.4Smart Weather Monitor — Cold Weather
Fig. 1.5Smart Weather Monitor — Extreme Temperature Alert
Fig. 1.6Smart Weather Monitor — Normal Weather

Experiment 2 — Scientific Calculator Using Arduino

FigureDescription
Fig. 2.1Calculator Output Screen
Fig. 2.2History Navigation Interface
Fig. 2.3Password Lock Screen
Fig. 2.4Prefix Expression Display

Experiment 3 — Multi-Waveform Generator

FigureDescription
Fig. 3.1PWM Waveform
Fig. 3.2Sine Wave Output
Fig. 3.3Triangle Wave Output

Experiment 4 — RTC-Based Smart Monitoring and Automation System

FigureDescription
Fig. 4.1Final Integrated RTC Monitoring System

Experiment 0 — Digital Output and Display Interfacing

Objective

To interface an LED with an Arduino board and program it to blink at specific time intervals using digital output pins and delay functions. The experiment demonstrates the basic operation of GPIO (General Purpose Input/Output), use of pinMode(), digitalWrite(), and timing control using delay() in Arduino programming.


Understanding

In this program, the LED connected to digital pin 13 of the Arduino is controlled using software instructions. Inside the setup() function, pin 13 is configured as an output pin using pinMode(13, OUTPUT).

The loop() function runs continuously. The instruction digitalWrite(13, HIGH) turns the LED ON by supplying voltage to the pin, and delay(1200) keeps it ON for 1200 milliseconds (1.2 seconds). Then digitalWrite(13, LOW) turns the LED OFF, and delay(1400) keeps it OFF for 1400 milliseconds (1.4 seconds).

Thus, the LED repeatedly blinks with different ON and OFF durations, demonstrating basic Arduino programming and timing control.


Code

void setup() {
  pinMode(13, OUTPUT);
}

void loop() {
  digitalWrite(13, HIGH);
  delay(1200);

  digitalWrite(13, LOW);
  delay(1400);
}

Screenshot

LED Blink Output


Conclusion

The LED blinking program was successfully implemented using the Arduino board. The experiment demonstrated how to configure a digital pin as an output and control the ON/OFF state of an LED using digitalWrite() and delay() functions.

The LED blinked continuously with specified timing intervals, verifying the correct operation of the program and providing a basic understanding of Arduino GPIO control and embedded programming concepts.


2. 7-Segment Display

Objective

To interface a 7-segment display with an Arduino board and display numerical digits from 0 to 9 using digital output pins. The experiment demonstrates the working principle of seven-segment displays, array-based programming, and digital output control in embedded systems.


Theory

A 7-segment display consists of seven LEDs labeled as a to g. Different combinations of these segments are turned ON or OFF to display numerical digits.

In this program, the segment pins are stored in the array segPins[7], where each element corresponds to one segment of the display. Another two-dimensional array digits[10][7] stores the segment patterns required to display digits from 0 to 9.

The function displayDigit(int num) takes a digit as input and activates the corresponding segments by sending HIGH or LOW signals to the display pins using digitalWrite().

Inside the loop() function, a for loop continuously counts from 0 to 9. Each digit is displayed for 1 second using delay(1000).

This experiment demonstrates display interfacing, array handling, function usage, looping structures, and GPIO programming using Arduino.


Code

int segPins[7] = {2,3,4,5,6,7,8};

byte digits[10][7] = {
  {1,1,1,1,1,1,0}, //0
  {0,1,1,0,0,0,0}, //1
  {1,1,0,1,1,0,1}, //2
  {1,1,1,1,0,0,1}, //3
  {0,1,1,0,0,1,1}, //4
  {1,0,1,1,0,1,1}, //5
  {1,0,1,1,1,1,1}, //6
  {1,1,1,0,0,0,0}, //7
  {1,1,1,1,1,1,1}, //8
  {1,1,1,1,0,1,1}  //9
};

void displayDigit(int num)
{
  for(int i=0; i<7; i++)
  {
    digitalWrite(segPins[i], digits[num][i]);
  }
}

void setup()
{
  for(int i=0; i<7; i++)
  {
    pinMode(segPins[i], OUTPUT);
  }
}

void loop()
{
  for(int count=0; count<=9; count++)
  {
    displayDigit(count);
    delay(1000);
  }
}

Screenshot

7 Segment Display Output


Conclusion

The 7-segment display was successfully interfaced with the Arduino board to display digits from 0 to 9 sequentially. The experiment demonstrated how multiple digital output pins can be controlled using arrays and functions to generate different display patterns.

The program verified the proper operation of GPIO control, looping structures, and display interfacing techniques in embedded systems using Arduino programming.


3. LED Matrix Display

Objective

To interface an 8×8 LED matrix display with an Arduino board and display the character T using row-column scanning techniques. The experiment demonstrates multiplexing, GPIO control, binary pattern representation, and matrix display interfacing in embedded systems.


theory

An 8×8 LED matrix consists of 64 LEDs arranged in rows and columns. Each LED is controlled by activating a specific row and column simultaneously.

In this program, the row pins are stored in the array rowPins[8] and the column pins are stored in colPins[8]. The binary pattern representing the letter T is stored in the array T[8].

Each binary value corresponds to one row of the matrix:

Inside the loop() function, the program scans each row one at a time. First, all rows are turned OFF. Then the required column pattern is applied using digitalWrite() and bitRead() functions. Finally, the selected row is activated for a very short duration using delay(2).

This rapid scanning process occurs continuously, creating the illusion of a stable character display due to persistence of vision.

The experiment demonstrates matrix multiplexing, binary data representation, row-column addressing, and display interfacing using Arduino.


Code

int rowPins[8] = {2,3,4,5,6,7,8,9};
int colPins[8] = {10,11,12,13,A3,A2,A1,A0};

// Letter T
byte T[8] = {
  B11111111,
  B00011000,
  B00011000,
  B00011000,
  B00011000,
  B00011000,
  B00011000,
  B00011000
};

void setup()
{
  for(int i=0; i<8; i++)
  {
    pinMode(rowPins[i], OUTPUT);
    pinMode(colPins[i], OUTPUT);
  }
}

void loop()
{
  for(int row=0; row<8; row++)
  {
    for(int i=0; i<8; i++)
    {
      digitalWrite(rowPins[i], LOW);
    }

    for(int col=0; col<8; col++)
    {
      if(bitRead(T[row], 7-col))
      {
        digitalWrite(colPins[col], LOW);
      }
      else
      {
        digitalWrite(colPins[col], HIGH);
      }
    }

    digitalWrite(rowPins[row], HIGH);

    delay(2);
  }
}

Screenshot

LED Matrix Display Output


Conclusion

The 8×8 LED matrix display was successfully interfaced with the Arduino board to display the character T. The experiment demonstrated how row-column scanning and multiplexing techniques are used to control multiple LEDs efficiently using limited GPIO pins.

The program verified the working of binary pattern mapping, bit manipulation, and dynamic display refreshing in embedded systems using Arduino programming.

Experiment 1 — Environmental Monitoring and Automation

1. Temperature Control System


Objective

To interface a temperature sensor with an Arduino board and implement an automatic temperature control system using LEDs and a DC motor. The experiment demonstrates sensor interfacing, conditional control, digital output operation, and automation using Arduino programming.


Components Required


Theory

Temperature monitoring and control systems are widely used in embedded systems and industrial automation. In this experiment, the DHT22 digital temperature sensor is interfaced with the Arduino Uno to continuously monitor environmental temperature.

The Arduino reads temperature data from the sensor and performs different actions depending on the temperature range:

The experiment demonstrates:


Circuit Connections

ComponentArduino Pin
DHT22 OutputD2
Warning LEDD3
Heater LEDD5
RelayD8
GND ConnectionsGND
ComponentConnection
RelayPower Supply
FanRelay

Arduino Code

#include <DHT.h>

#define DHTPIN 2
#define DHTTYPE DHT22

DHT dht(DHTPIN, DHTTYPE);

void setup() {

  Serial.begin(9600);

  dht.begin();

  pinMode(3, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(8, OUTPUT);
}

void loop() {

  float temp = dht.readTemperature();

  Serial.println(temp);

  if (isnan(temp)) {

    digitalWrite(3, LOW);
    digitalWrite(5, LOW);
    digitalWrite(8, LOW);

    return;
  }

  // HOT CONDITION
  if(temp > 35) {

    digitalWrite(3, HIGH);
    digitalWrite(8, HIGH);
    digitalWrite(5, LOW);
  }

  // COLD CONDITION
  else if(temp < 25) {

    digitalWrite(5, HIGH);
    digitalWrite(3, LOW);
    digitalWrite(8, LOW);
  }

  // NORMAL CONDITION
  else {

    digitalWrite(3, LOW);
    digitalWrite(5, LOW);
    digitalWrite(8, LOW);
  }

  delay(1000);
}

Screenshots

Heating Condition

When temperature falls below 25°C, the heater indicator LED turns ON. Heating Simulation

Cooling Condition

When temperature rises above 35°C, the warning LED and cooling fan turn ON.

Cooling Simulation


Observations

Temperature RangeOutput Condition
Below 25°CHeater LED ON
25°C – 35°CAll Outputs OFF
Above 35°CWarning LED and Fan ON

Conclusion

The experiment successfully demonstrated temperature sensing and automatic control using Arduino. The DHT22 sensor accurately measured temperature, and the Arduino performed appropriate control actions using conditional logic.

The experiment verified practical concepts of:

The system can be further expanded for industrial temperature monitoring, smart home automation, and environmental control applications

2. Smart Weather Monitoring and Extreme Temperature Alert System


Objective

To design and implement a smart weather monitoring system using Arduino Uno, DHT22 sensor, LCD display, LEDs, DC motor, and buzzer. The system continuously monitors temperature and humidity conditions and displays different weather states such as normal weather, hot weather, cold weather, heat wave, and extreme temperature alerts.


Components Required


Theory

Smart weather monitoring systems are widely used in embedded systems, environmental monitoring, industrial automation, and safety systems. In this experiment, the DHT22 sensor continuously measures environmental temperature and humidity and sends the data digitally to the Arduino Uno.

The Arduino processes the sensor values and displays different weather conditions on a 16×2 LCD display. Depending on temperature and humidity conditions, LEDs, cooling fan, and alarm systems are activated automatically.

The system works according to the following conditions:


Circuit Connections

ComponentArduino Pin
DHT22 OutputD2
Warning LEDD3
Heater LEDD5
RelayD8
Buzzer / Audio OutputD9
LCD RSA0
LCD ENA1
LCD D4A2
LCD D5A3
LCD D6A4
LCD D7A5
ComponentConnection
RelayPower Supply
FanRelay

Arduino Code

#include <DHT.h>
#include <LiquidCrystal.h>

LiquidCrystal lcd(A0, A1, A2, A3, A4, A5);

#define DHTPIN 2
#define DHTTYPE DHT22

DHT t(DHTPIN, DHTTYPE);

void setup() {

  Serial.begin(9600);

  t.begin();

  lcd.begin(16,2);

  pinMode(3, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(8, OUTPUT);
  pinMode(9, OUTPUT);
}

void loop() {

  float temp = t.readTemperature();
  float humid = t.readHumidity();

  Serial.print("Temperature: ");
  Serial.println(temp);

  Serial.print("Humidity: ");
  Serial.println(humid);

  if(isnan(temp) || isnan(humid)) {

    digitalWrite(3, LOW);
    digitalWrite(5, LOW);
    digitalWrite(8, LOW);

    noTone(9);

    lcd.clear();

    lcd.setCursor(0,0);
    lcd.print("SENSOR ERROR");

    delay(1000);

    return;
  }

  if(temp > 45) {

    tone(9,1000);

    digitalWrite(3, HIGH);
    digitalWrite(8, HIGH);
    digitalWrite(5, LOW);

    lcd.clear();

    lcd.setCursor(0,0);
    lcd.print("EXTREME TEMP");

    lcd.setCursor(0,1);
    lcd.print("ALERT");
  }

  else if(temp > 40 && humid < 30) {

    noTone(9);

    digitalWrite(3, HIGH);
    digitalWrite(8, HIGH);
    digitalWrite(5, LOW);

    lcd.clear();

    lcd.setCursor(0,0);
    lcd.print("HEAT WAVE");

    lcd.setCursor(0,1);
    lcd.print("DRY WEATHER");
  }

  else if(temp > 35) {

    noTone(9);

    digitalWrite(3, HIGH);
    digitalWrite(8, HIGH);
    digitalWrite(5, LOW);

    lcd.clear();

    lcd.setCursor(0,0);
    lcd.print("HOT WEATHER");

    lcd.setCursor(0,1);
    lcd.print("TEMP HIGH");
  }

  else if(temp < 15) {

    noTone(9);

    digitalWrite(3, LOW);
    digitalWrite(8, LOW);
    digitalWrite(5, HIGH);

    lcd.clear();

    lcd.setCursor(0,0);
    lcd.print("COLD WEATHER");

    lcd.setCursor(0,1);
    lcd.print("TEMP LOW");
  }

  else if(humid > 80) {

    noTone(9);

    digitalWrite(3, LOW);
    digitalWrite(5, LOW);
    digitalWrite(8, LOW);

    lcd.clear();

    lcd.setCursor(0,0);
    lcd.print("RAIN");

    lcd.setCursor(0,1);
    lcd.print("POSSIBILITY");
  }

  else {

    noTone(9);

    digitalWrite(3, LOW);
    digitalWrite(5, LOW);
    digitalWrite(8, LOW);

    lcd.clear();

    lcd.setCursor(0,0);
    lcd.print("NORMAL");

    lcd.setCursor(0,1);
    lcd.print("WEATHER");
  }

  delay(1000);
}

Screenshots

Hot Weather Condition

Hot Weather

When the temperature exceeds 35°C, the warning LED and cooling fan turn ON, and the LCD displays “HOT WEATHER”.


Cold Weather Condition

Cold Weather

When the temperature falls below 15°C, the heater indicator LED turns ON and the LCD displays “COLD WEATHER”.


Extreme Temperature Alert

Extreme Temperature

When the temperature exceeds 45°C, the buzzer activates along with the warning LED and cooling fan, and the LCD displays “EXTREME TEMP ALERT”.


Normal Weather Condition

Normal Weather

When the temperature and humidity remain within the normal range, all indicators remain OFF and the LCD displays “NORMAL WEATHER”.

Extreme temperatures and rain possibility is not shown.


Observations

Weather ConditionOutput Response
Temperature < 15°CHeater LED ON
15°C – 35°CNormal Weather
Temperature > 35°CWarning LED + Cooling Fan ON
Temperature > 45°CWarning LED + Cooling Fan + Buzzer ON
Humidity > 80%Rain Possibility Detection
Temperature > 40°C and Humidity < 30%Heat Wave Detection

Conclusion

The experiment successfully demonstrated a smart weather monitoring and alert system using Arduino and DHT22 sensor interfacing. The system continuously monitored temperature and humidity and automatically generated warnings and alerts based on environmental conditions.

The experiment verified:

The project can be further extended into smart weather stations, industrial environmental monitoring systems, smart home automation, and disaster warning systems.

Experiment 2 — Scientific Calculator Using Arduino

Calculator

Objective

The objective of this project is to design and implement a compact scientific calculator using Arduino UNO, PCD8544 graphical LCD, and a matrix keypad. The calculator supports arithmetic operations, infix-to-prefix conversion, prefix evaluation, history storage, expression editing, and password protection.


Components Used

ComponentQuantityPurpose
Arduino UNO1Main controller
PCD8544 Nokia 5110 LCD1Display
5×6 Matrix Keypad1User input
Jumper WiresMultipleConnections
USB Cable1Programming and power

Arduino Code Libraries Used

The following Arduino libraries were used in the program:

LibraryPurpose
Adafruit_GFX.hGraphics handling
Adafruit_PCD8544.hNokia 5110 LCD control
Keypad.hMatrix keypad scanning
math.hMathematical operations
string.hCharacter array handling
stdlib.hNumeric conversions

Circuit Connections

PCD8544 LCD Connections

LCD PinArduino UNO Pin
RSTA0
CE / CSA1
DCA2
DINA3
CLKA4
VCC3.3V
LIGHT3.3V
GNDGND

Keypad Connections

Row Pins

Keypad RowArduino Pin
R1D2
R2D3
R3D4
R4D5
R5D6
R6D7

Column Pins

Keypad ColumnArduino Pin
C1D8
C2D9
C3D10
C4D11
C5D12

Working Principle

The calculator accepts expressions in infix form such as:

86*55-(9/4)

The processing flow is:

INFIX

INFIX TO PREFIX

PREFIX EVALUATION

RESULT DISPLAY

The expression is first converted into prefix notation and then evaluated using stack-based processing.


Why Prefix Conversion Was Used

The prefix conversion mechanism was implemented to demonstrate compiler-design concepts and stack-based expression evaluation.

Advantages:

Example:

Infix Expression

7+8*2

Prefix Expression

+7*82

The calculator internally evaluates the converted prefix expression.


Prefix Evaluation Method

The prefix expression is evaluated from:

Right → Left

Algorithm:

  1. Read symbol
  2. If operand:
    • push to stack
  3. If operator:
    • pop two operands
    • apply operation
    • push result back

Mathematical Functions Supported

FunctionSymbol
Addition+
Subtraction-
Multiplication*
Division/
Power^
Square RootR
Percentage%
Parentheses( ) { }

Cursor Navigation

The calculator supports cursor-based editing.

KeyOperation
<Move cursor left
>Move cursor right
BDelete previous character

This allows insertion and modification of expressions at arbitrary positions.


History Function

The calculator stores previously entered expressions.

Features

Controls

KeyFunction
HEnter history mode
<Previous expression
>Next expression
=Reload selected expression
CExit history mode

Lock Function

A password-protection system was implemented to restrict calculator access.

Password

123

Working

When the user presses:

L

the calculator enters lock mode.

Display shows:

ENTER PSWD

Correct Password

If password entered is:

123

the calculator unlocks successfully.

Incorrect Password

For invalid password:

INVALID

is displayed and the calculator remains locked.


Arduino Program Structure

Main program modules:

FunctionPurpose
renderDisplay()Updates LCD
insertChar()Inserts characters
backspace()Deletes characters
infixToPrefix()Converts expressions
evaluatePrefix()Evaluates prefix expression
saveHistory()Stores history
showHistory()Displays history
loadHistory()Recalls history
showMessage()Displays notifications

Code

// ======================================================
// LIBRARIES
// ======================================================
#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>
#include <Keypad.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>

// ======================================================
// DISPLAY VARIABLES
// ======================================================
Adafruit_PCD8544 display(A4,A3,A2,A1,A0);

// ======================================================
// EXPRESSION VARIABLES
// ======================================================
char expr[31]="";
char prefixExpr[31]="";
char tempExpr[31]="";
int exprLen=0;
int cursorPos=0;
float ans=0;

// ======================================================
// LOCK SYSTEM VARIABLES
// ======================================================
bool locked=false;
char entered[4]="";
int passPos=0;

// ======================================================
// HISTORY VARIABLES
// ======================================================
char history[5][31];
int historyCount=0;
int historyIndex=0;
bool historyMode=false;

// ======================================================
// STACK VARIABLES
// ======================================================
float valueStack[20];
char opStack[20];
int vTop;
int oTop;

// ======================================================
// KEYPAD VARIABLES
// ======================================================
const byte ROWS=6;
const byte COLS=5;
char keys[ROWS][COLS]={
{'1','2','3','+','-'},
{'4','5','6','*','/'},
{'7','8','9','(',')'},
{'C','0','.','=','R'},
{'H','{','}','L','%'},
{'^','<','>','B','A'}
};
byte rowPins[ROWS]={2,3,4,5,6,7};
byte colPins[COLS]={8,9,10,11,12};
Keypad keypad=Keypad(makeKeymap(keys),rowPins,colPins,ROWS,COLS);

// ======================================================
// DISPLAY FUNCTION
// ======================================================
void renderDisplay(){
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(BLACK);
display.setCursor(0,0);
display.println("Calculator");
display.drawLine(0,8,83,8,BLACK);
int start=0;
int visibleChars=14;
if(cursorPos>=visibleChars){
start=cursorPos-visibleChars+1;
}
display.setCursor(0,18);
for(int i=start;i<exprLen&&i<start+visibleChars;i++){
display.print(expr[i]);
}
int localCursor=cursorPos-start;
int cursorX=localCursor*6;
display.drawLine(cursorX,35,cursorX+5,35,BLACK);
display.display();
}

// ======================================================
// MESSAGE DISPLAY FUNCTION
// ======================================================
void showMessage(const char* msg){
display.clearDisplay();
display.setTextSize(1);
display.setCursor(0,20);
display.println(msg);
display.display();
delay(700);
renderDisplay();
}

// ======================================================
// OPERATOR CHECK FUNCTION
// ======================================================
bool isOperator(char c){
return(c=='+'||c=='-'||c=='*'||c=='/'||c=='^');
}

// ======================================================
// OPERATOR PRECEDENCE FUNCTION
// ======================================================
int precedence(char op){
if(op=='+'||op=='-')
return 1;
if(op=='*'||op=='/')
return 2;
if(op=='^')
return 3;
return 0;
}

// ======================================================
// OPERATION EXECUTION FUNCTION
// ======================================================
float applyOp(float a,float b,char op){
switch(op){
case '+':
return a+b;
case '-':
return a-b;
case '*':
return a*b;
case '/':
if(b!=0)
return a/b;
return 0;
case '^':
return pow(a,b);
}
return 0;
}

// ======================================================
// STRING REVERSE FUNCTION
// ======================================================
void reverseString(char src[],char dest[]){
int len=strlen(src);
for(int i=0;i<len;i++){
dest[i]=src[len-1-i];
}
dest[len]='\0';
}

// ======================================================
// INFIX TO PREFIX CONVERSION
// ======================================================
void infixToPrefix(){
reverseString(expr,tempExpr);
for(int i=0;tempExpr[i]!='\0';i++){
if(tempExpr[i]=='(')
tempExpr[i]=')';
else if(tempExpr[i]==')')
tempExpr[i]='(';
else if(tempExpr[i]=='{')
tempExpr[i]='}';
else if(tempExpr[i]=='}')
tempExpr[i]='{';
}
char postfix[31]="";
int p=0;
oTop=-1;
int i=0;
while(tempExpr[i]!='\0'){
if(isDigit(tempExpr[i])||tempExpr[i]=='.'){
postfix[p++]=tempExpr[i];
}
else if(tempExpr[i]=='('||tempExpr[i]=='{'){
opStack[++oTop]=tempExpr[i];
}
else if(tempExpr[i]==')'||tempExpr[i]=='}'){
while(oTop>=0&&opStack[oTop]!='('&&opStack[oTop]!='{'){
postfix[p++]=opStack[oTop--];
}
oTop--;
}
else{
while(oTop>=0&&precedence(opStack[oTop])>precedence(tempExpr[i])){
postfix[p++]=opStack[oTop--];
}
opStack[++oTop]=tempExpr[i];
}
i++;
}
while(oTop>=0){
postfix[p++]=opStack[oTop--];
}
postfix[p]='\0';
reverseString(postfix,prefixExpr);
}

// ======================================================
// PREFIX EVALUATION FUNCTION
// ======================================================
float evaluatePrefix(){
vTop=-1;
int len=strlen(prefixExpr);
for(int i=len-1;i>=0;i--){
if(isDigit(prefixExpr[i])){
float val=prefixExpr[i]-'0';
valueStack[++vTop]=val;
}
else if(isOperator(prefixExpr[i])){
float a=valueStack[vTop--];
float b=valueStack[vTop--];
valueStack[++vTop]=applyOp(a,b,prefixExpr[i]);
}
}
return valueStack[vTop];
}

// ======================================================
// CHARACTER INSERT FUNCTION
// ======================================================
void insertChar(char c){
if(exprLen>=30)
return;
if(cursorPos>0&&isOperator(c)&&isOperator(expr[cursorPos-1])){
return;
}
for(int i=exprLen;i>cursorPos;i--){
expr[i]=expr[i-1];
}
expr[cursorPos]=c;
exprLen++;
cursorPos++;
expr[exprLen]='\0';
}

// ======================================================
// BACKSPACE FUNCTION
// ======================================================
void backspace(){
if(exprLen<=0||cursorPos<=0)
return;
for(int i=cursorPos-1;i<exprLen-1;i++){
expr[i]=expr[i+1];
}
exprLen--;
cursorPos--;
expr[exprLen]='\0';
}

// ======================================================
// CLEAR EXPRESSION FUNCTION
// ======================================================
void clearExpr(){
exprLen=0;
cursorPos=0;
expr[0]='\0';
}

// ======================================================
// SAVE HISTORY FUNCTION
// ======================================================
void saveHistory(){
if(historyCount<5){
strcpy(history[historyCount++],expr);
}
else{
for(int i=1;i<5;i++){
strcpy(history[i-1],history[i]);
}
strcpy(history[4],expr);
}
}

// ======================================================
// SHOW HISTORY FUNCTION
// ======================================================
void showHistory(){
display.clearDisplay();
display.setTextSize(1);
display.setCursor(0,0);
display.println("HISTORY");
display.setCursor(0,20);
display.println(history[historyIndex]);
display.display();
}

// ======================================================
// LOAD HISTORY FUNCTION
// ======================================================
void loadHistory(){
strcpy(expr,history[historyIndex]);
exprLen=strlen(expr);
cursorPos=exprLen;
historyMode=false;
renderDisplay();
}

// ======================================================
// PREFIX DISPLAY FUNCTION
// ======================================================
void showPrefix(){
display.clearDisplay();
display.setTextSize(1);
display.setCursor(0,0);
display.println("PREFIX");
display.setCursor(0,20);
display.println(prefixExpr);
display.display();
delay(1000);
}

// ======================================================
// SETUP FUNCTION
// ======================================================
void setup(){
display.begin();
display.setContrast(60);
clearExpr();
renderDisplay();
}

// ======================================================
// MAIN LOOP FUNCTION
// ======================================================
void loop(){
char key=keypad.getKey();
if(!key)
return;

// ======================================================
// LOCK MODE
// ======================================================
if(locked){
if(isDigit(key)){
if(passPos<3){
entered[passPos++]=key;
entered[passPos]='\0';
}
}
else if(key=='='){
if(strcmp(entered,"123")==0){
locked=false;
passPos=0;
entered[0]='\0';
renderDisplay();
}
else{
passPos=0;
entered[0]='\0';
showMessage("INVALID");
}
}
display.clearDisplay();
display.setCursor(0,0);
display.println("ENTER PSWD");
display.display();
return;
}

// ======================================================
// HISTORY MODE
// ======================================================
if(historyMode){
if(key=='<'){
if(historyIndex>0)
historyIndex--;
}
else if(key=='>'){
if(historyIndex<historyCount-1){
historyIndex++;
}
}
else if(key=='='){
loadHistory();
return;
}
else if(key=='C'){
historyMode=false;
renderDisplay();
return;
}
showHistory();
return;
}

// ======================================================
// NORMAL CALCULATOR MODE
// ======================================================
switch(key){
case 'C':
clearExpr();
break;

case 'B':
backspace();
break;

case '<':
if(cursorPos>0)
cursorPos--;
break;

case '>':
if(cursorPos<exprLen)
cursorPos++;
break;

case 'L':
locked=true;
passPos=0;
entered[0]='\0';
break;

case 'H':
if(historyCount>0){
historyMode=true;
historyIndex=historyCount-1;
showHistory();
}
return;

case 'R':
ans=sqrt(evaluatePrefix());
dtostrf(ans,0,2,expr);
exprLen=strlen(expr);
cursorPos=exprLen;
break;

case '%':
ans=evaluatePrefix()/100.0;
dtostrf(ans,0,2,expr);
exprLen=strlen(expr);
cursorPos=exprLen;
break;

case '=':
if(exprLen==0)
break;
infixToPrefix();
showPrefix();
ans=evaluatePrefix();
saveHistory();
dtostrf(ans,0,2,expr);
exprLen=strlen(expr);
cursorPos=exprLen;
break;

default:
insertChar(key);
}
renderDisplay();
}

Screenshots

1. Calculator Output

Calculator Output

Description:
This screenshot shows successful arithmetic evaluation and result display on the PCD8544 LCD.


2. History Navigation

History Navigation

Description:
This screenshot demonstrates the history system where previously entered expressions can be navigated and reloaded.


3. Lock Screen

Lock Screen

Description:
This screenshot shows the password-protected lock mode. The calculator requests a password before access is granted.


4. Prefix Expression Display

Prefix Expression

Description:
This screenshot shows the generated prefix notation after converting the infix expression entered by the user.


Calculator Output

The calculator successfully evaluates arithmetic expressions.

Example:

78*54-6

Output:

4206

History Navigation

The history system stores and reloads previous expressions.

Stored expression example:

86*55-(9/4)

Lock Screen

Password protection system:

Screen displayed:

ENTER PSWD

Prefix Conversion Display

The calculator shows the generated prefix expression.

Example prefix output:

-+7*3365

Conclusion

The project successfully implemented a scientific calculator using Arduino UNO and PCD8544 display.

The system demonstrated:

The replacement of the OLED display with the PCD8544 LCD significantly improved system stability and memory efficiency.

The project integrates concepts from:

into a compact and efficient hardware implementation.

Experiment 3 — Multi-Waveform Generator

1.Waveform Generator

Objective

To design and implement a multi-waveform generator using Arduino Uno, an 8-bit R-2R DAC, a Nokia PCD8544 LCD display, push buttons, and a potentiometer. The system generates sine, triangle, and PWM waveforms selectable via dedicated push buttons, with frequency controlled by a potentiometer.


Components Required

ComponentQuantityPurpose
Arduino Uno1Main controller
Nokia PCD8544 LCD1Display waveform info
R-2R DAC (8-bit)1Analog wave output
Push Buttons3Wave selection (S/T/P)
Potentiometer (10 kΩ)1Frequency control
Resistor 220Ω1DAC output filter
Capacitor 10 µF1Signal smoothing
Connecting WiresMultipleConnections

Circuit Connections

ComponentArduino Pin
DAC D0–D7D6–D13
DAC OUTOscilloscope Channel 1
PWM OutputD5 → Oscilloscope Channel 2
Sine ButtonD2
Triangle ButtonD3
PWM ButtonD4
PotentiometerA5
LCD RSTA0
LCD CSA1
LCD DCA2
LCD DINA3
LCD CLKA4

Working Principle

The waveform generator operates three independent wave logics unified under a single non-blocking loop. The triangle wave logic increments and decrements an integer value by a fixed step of 8 between 0 and 255, writing each step to the 8-bit R-2R DAC on pins D6–D13 using bitwise shifting — this is the exact logic from the standalone triangle sketch. The sine wave logic advances a floating-point angle variable by 0.2 radians per step, computes 127 + 127 * sin(angle), and writes the result to the same DAC — identical to the standalone sine sketch. The PWM logic toggles pin D5 HIGH and LOW with a fixed 500 µs half-period, matching the original standalone PWM sketch exactly. Since sine and triangle are never active simultaneously — the push buttons ensure only one is selected at a time — both safely share the same DAC pins without conflict. The key integration technique is replacing each sketch’s delayMicroseconds() with a micros()-based non-blocking timer, so the PWM toggle and the DAC output each check elapsed time independently without freezing one another. The potentiometer on A5 maps to the DAC update interval (controlling sine and triangle frequency), while PWM remains fixed at 1 kHz as in the original. The PCD8544 display refreshes every 300 ms showing the active waveform name, step size, amplitude, and output pin.


Code

#include <math.h>
#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>

Adafruit_PCD8544 display = Adafruit_PCD8544(A4, A3, A2, A1, A0);

int dacPins[8] = {6, 7, 8, 9, 10, 11, 12, 13};
int pwmPin = 5;

const int btnSine = 2;
const int btnTri  = 3;
const int btnPWM  = 4;
const int potPin  = A5;

char activeWave = 'S';

// original triangle state
int value     = 0;
int direction = 1;

// original sine state
float angle = 0;

// pwm state
bool pwmState = false;

unsigned long lastDac     = 0;
unsigned long lastPwm     = 0;
unsigned long lastDisplay = 0;

const unsigned long PWM_HALF = 5000; // 5ms each side → 100 Hz, visible on scope

unsigned long getDacDelay(int potVal) {
  return (unsigned long)map(potVal, 0, 1023, 50, 500);
}

void outputDAC(int number) {
  for (int i = 0; i < 8; i++) {
    digitalWrite(dacPins[i], (number >> i) & 1);
  }
}

void updateDisplay(char wave, int potVal) {
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(BLACK);

  display.setCursor(0, 0);
  switch (wave) {
    case 'S': display.print(F("Waveform: SINE")); break;
    case 'T': display.print(F("Waveform: TRI"));  break;
    case 'P': display.print(F("Waveform: PWM"));  break;
  }

  display.setCursor(0, 10);
  display.print(F("Pot: "));
  display.print(potVal);

  display.setCursor(0, 20);
  switch (wave) {
    case 'S':
    case 'T': display.print(F("Amp: 127 DAC")); break;
    case 'P': display.print(F("Duty: 50%"));    break;
  }

  display.setCursor(0, 30);
  switch (wave) {
    case 'S': display.print(F("Step: 0.2 rad")); break;
    case 'T': display.print(F("Step: 8"));       break;
    case 'P': display.print(F("Period: 1ms"));   break;
  }

  display.setCursor(0, 40);
  switch (wave) {
    case 'S':
    case 'T': display.print(F("Out: D6-D13 DAC")); break;
    case 'P': display.print(F("Out: D5"));          break;
  }

  display.display();
}

void setup() {
  for (int i = 0; i < 8; i++) pinMode(dacPins[i], OUTPUT);
  pinMode(pwmPin,  OUTPUT);
  pinMode(btnSine, INPUT_PULLUP);
  pinMode(btnTri,  INPUT_PULLUP);
  pinMode(btnPWM,  INPUT_PULLUP);

  display.begin();
  display.setContrast(57);
  display.clearDisplay();
  display.display();

  Serial.begin(9600);
  updateDisplay(activeWave, 512);
}

void loop() {
  unsigned long now = micros();
  int potVal        = analogRead(potPin);
  unsigned long dacDelay = getDacDelay(potVal);

  // Buttons
  if (digitalRead(btnSine) == LOW && activeWave != 'S') {
    activeWave = 'S'; angle = 0; delay(50);
  } else if (digitalRead(btnTri) == LOW && activeWave != 'T') {
    activeWave = 'T'; value = 0; direction = 1; delay(50);
  } else if (digitalRead(btnPWM) == LOW && activeWave != 'P') {
    activeWave = 'P'; outputDAC(0); pwmState = false; delay(50);
  }

  // PWM — fixed 5ms half period, independent of DAC
  if (now - lastPwm >= PWM_HALF) {
    lastPwm = now;
    if (activeWave == 'P') {
      pwmState = !pwmState;
      digitalWrite(pwmPin, pwmState ? HIGH : LOW);
    } else {
      digitalWrite(pwmPin, LOW);
    }
  }

  // DAC — sine or triangle, pot controls speed
  if (now - lastDac >= dacDelay) {
    lastDac = now;

    if (activeWave == 'S') {
      // exact original sine logic
      int sineValue = 127 + 127 * sin(angle);
      outputDAC(sineValue);
      angle += 0.2;
      if (angle >= 6.283) angle = 0;

    } else if (activeWave == 'T') {
      // exact original triangle logic
      outputDAC(value);
      value += direction * 8;
      if (value >= 255) { value = 255; direction = -1; }
      if (value <= 0)   { value = 0;   direction =  1; }
    }
  }

  // Display every 300ms
  if (millis() - lastDisplay >= 300) {
    lastDisplay = millis();
    updateDisplay(activeWave, potVal);
  }
}

Screenshots

PWM Wave

PWM Wave

Sine Wave

Sine Wave

Triangle Wave

Triangle Wave


Observations

WaveformOutput PinFrequency ControlStep SizeAmplitude
SineD6–D13 (DAC)Potentiometer0.2 rad127 DAC counts
TriangleD6–D13 (DAC)Potentiometer8 counts127 DAC counts
PWMD5Fixed5V (digital)

Reference

Know about Embedded System, “DAC Digital to Analog Converter,” YouTube playlist available: https://youtube.com/playlist?list=PL64VXTyRJbOoH6Zn5ddF9vljSijatvazM.


Conclusion

The experiment successfully demonstrated a multi-waveform generator using Arduino and an 8-bit R-2R DAC. All three waveforms — sine, triangle, and PWM — operated correctly and were clearly visible on the oscilloscope. The non-blocking micros() timing approach preserved the original wave mathematics from each standalone sketch while allowing all three to coexist in a single unified program. The potentiometer provided real-time frequency control for sine and triangle waves, and the Nokia PCD8544 display correctly reported waveform characteristics for each selected mode.

Experiment 4 — RTC-Based Smart Monitoring and Automation System

Objective

The objective of this experiment was to interface the DS1307 Real Time Clock (RTC) module with Arduino Uno using the I2C communication protocol and display real-time clock data on a 16×2 LCD display. The project was further extended to implement alarm functionality, keypad-based time configuration, automatic motor control, and periodic temperature logging using a DS18B20 digital temperature sensor.  


Introduction

Real Time Clock (RTC) modules are widely used in embedded systems where accurate timekeeping is required independently of the main controller operation. The DS1307 RTC module communicates with microcontrollers using the I2C bus and maintains time even during power interruptions through a backup battery.

In this experiment, the RTC module was interfaced with an Arduino Uno to create a fully functional real-time monitoring and automation system. The system was developed progressively in multiple stages:


Components Required

ComponentPurpose
Arduino UnoMain controller
DS1307 RTC ModuleReal-time clock source
16×2 HD44780 LCDTime and status display
Push Button KeypadUser input and configuration
BuzzerAlarm indication
DC MotorWater pump simulation
DS18B20 Temperature SensorAmbient temperature sensing
4.7kΩ ResistorPull-up resistor for DS18B20
Connecting WiresHardware interfacing
RelaySwitching
Power supplyPowering Motor
GroundGrounding

Theory

DS1307 RTC Module

The DS1307 is a low-power Real Time Clock IC that communicates using the I2C protocol. It stores:

The RTC maintains accurate time using an external crystal oscillator and battery backup.

The Arduino communicates with the RTC through:

using the Wire.h library.


I2C Communication

I2C is a synchronous serial communication protocol that uses only two wires:

The Arduino acts as the master device while the DS1307 acts as the slave device.

Advantages:


LCD Interfacing

The 16×2 LCD was interfaced in 4-bit mode using the LiquidCrystal library. The LCD continuously displays:


Keypad Control System

A 2×2 keypad arrangement was implemented using four push buttons.

Functional Buttons

ButtonFunction
MChange mode
+Increment values
-Decrement values
SSave configured values

The keypad allows:


Temperature Logging

The DS18B20 digital sensor was used for ambient temperature monitoring.

The sensor communicates using the OneWire protocol and periodically sends temperature values to the Arduino.

Temperature data is:


Circuit Connections

LCD Connections

LCD PinArduino Pin
RSD7
END6
D4D5
D5D4
D6D3
D7D2

RTC Connections

RTC PinArduino Pin
SDAA4
SCLA5
SQWA0

Keypad Connections

Keypad PinArduino Pin
Row 1D10
Row 2D11
Column 1D12
Column 2D13

Additional Connections

ComponentArduino Pin
BuzzerD9
RelayD8
Water Supply SwitchA1
DS18B20 DataA2
ComponentConnection
RelayMotor
Power SupplyRelay

Development and Code Progression

The project was developed incrementally in three major stages.


Stage 1 — Basic RTC Clock and Alarm System

The first implementation focused on RTC interfacing and user-controlled clock management.

Features Implemented

Main Functional Blocks

FunctionPurpose
readTime()Reads RTC registers
setRTCTime()Writes updated time to RTC
scanKeypad()Detects keypad inputs
drawAll()Updates LCD contents
incrementValue()Increases selected parameter
decrementValue()Decreases selected parameter

System Operation

The RTC continuously sends current time information to the Arduino. The LCD displays:

HH:MM:SS

The user can enter configuration mode using the keypad and modify:

When current time matches alarm time:


Key Learning Outcomes

This stage established:

Code progression reference:  


Stage 2 — Automatic Motor Control System

The second stage transformed the RTC system into a simple automation controller.


Objective

To automatically control a water pump based on water supply availability.


Functional Enhancements Added

New Variables Introduced

bool motorState;
unsigned long motorStartTime;
unsigned long waterLostTime;
bool waterPreviouslyPresent;

New Function Added

void handlePumpControl()

Working Logic

The water supply was simulated using a push-button input connected to pin A1.

Operating Conditions

Water ConditionMotor Action
Water availableMotor turns ON
Water unavailableOFF timer starts
10 minutes elapsedMotor turns OFF

Automation Principle

When water becomes available:

  1. motor starts automatically,
  2. runtime timer starts.

The motor turns OFF if:


System Improvements

The LCD was modified to additionally display motor state:

ON / OFF

Code progression reference:  


Stage 3 — Temperature Logging and Monitoring

The final stage integrated environmental sensing and serial logging.


Objective

To periodically record ambient temperature values for temperature prediction and monitoring purposes.  


Sensor Used

Instead of LM35 mentioned in the experiment sheet, a DS18B20 digital temperature sensor was implemented due to:


Additional Libraries Added

#include <OneWire.h>
#include <DallasTemperature.h>

New Functionalities Added


Logging Mechanism

Temperature values were logged every:

15 minutes

using RTC timestamps.

Sample Output

TIME: 00:15:00 TEMP: 23.00 C

Main Function Added

void handleTemperatureLogging()

Working Principle

The Arduino continuously:

  1. reads RTC time,
  2. acquires sensor temperature,
  3. updates LCD,
  4. checks logging interval.

At every 15-minute boundary:

This stage integrated:

Code progression was implemented incrementally through RTC interfacing, automation control, and temperature logging modules.


Problems Faced During Implementation

Several practical issues were encountered during system development.


1. Internal Input Handling Issues

Problem

The keypad initially produced:

This made:


Cause

Mechanical switch bouncing and rapid polling caused multiple detections for a single press.


Solution

Software debouncing was implemented using:

delay(40);

along with key release detection:

while(scanKeypad()==k);

This stabilized keypad operation significantly.


2. Mode Switching and Time Setting Errors

Problem

While changing modes:


Cause

The local variables and RTC registers were not refreshed immediately after writing updated time.


Solution

After saving:

  1. RTC values were re-read,
  2. display variables refreshed,
  3. mode reset correctly.

This resolved synchronization inconsistencies.


3. Motor Turning OFF Too Quickly

Problem

Initially the motor turned OFF almost immediately after switching ON.


Cause

Incorrect timer values were used:

10000 ms

which corresponds to:

10 seconds

instead of the intended longer runtime.


Solution

Timer values were modified to:

600000 ms

which corresponds to:

10 minutes

The motor then operated correctly.


4. Temperature Reading Showing −127°C

Problem

The DS18B20 sensor initially displayed:

-127°C

instead of actual temperature values.


Cause

This occurred due to:


Solution

A 4.7kΩ pull-up resistor was connected between:

After correction:


Screenshot

Final integrated system: ![Real Time Clock](./img/Real Time Clock.png)


Observations

System ModuleObservation
RTC ModuleAccurate timekeeping achieved
LCD DisplayStable real-time updates
Keypad SystemProper mode control achieved
Alarm SystemSuccessful buzzer activation
Motor AutomationCorrect timed switching observed
Temperature LoggingStable periodic logging achieved

Time Drift

Time drift refers to the gradual deviation of RTC time from actual real-world time due to oscillator inaccuracies.

In the DS1307 RTC:



Final Remarks

Across these experiments, the focus gradually shifted from simple digital I/O operations to complete embedded systems integrating sensors, displays, communication protocols, automation logic, and real-time data processing. Together, the projects demonstrate practical application of electronics, programming, data structures, and system design concepts using the Arduino ecosystem.

Conclusion

The experiment successfully demonstrated implementation of a real-time embedded monitoring and automation system using the I2C protocol and DS1307 RTC module.

The project progressively evolved from:

The experiment verified practical implementation of:

The final system demonstrated modular embedded system design and real-world integration of multiple peripherals into a unified intelligent monitoring platform.