Spring 23
Spring 23
Answer to question no 2
1. *Definition*:
- *Microprocessor*: It is the central unit of a computer system, mainly responsible for performing
computational tasks. It lacks peripheral support and requires external components (like memory and
I/O) to function.
2. *Components*:
- *Microprocessor*: Requires external components like RAM, ROM, and I/O devices for functioning.
- *Microcontroller*: Contains CPU, memory, and peripherals (I/O, timers, etc.) in a single chip.
3. *Applications*:
- *Microprocessor*: Used in systems where extensive computation and multitasking are needed, like
computers.
- *Microcontroller*: Ideal for embedded systems with specific tasks, like automotive controls, home
appliances, and remote controls.
4. *Power Consumption*:
5. *Cost*:
- *Microprocessor*: Typically more expensive due to the need for additional components.
---
### Memory Layout Diagrams for ATmega328P
1. *Program Memory (Flash Memory)*: This is non-volatile memory used to store the program code.
2. *Data Memory (SRAM)*: Volatile memory used for variables and temporary data storage.
3. *EEPROM*: Non-volatile memory used to store data that must be retained even after power-off.
These memory blocks are mapped within the microcontroller’s address space, allowing efficient access
by the CPU and peripherals.
---
### Prime and Alternate Functions of PORTB, PORTC, and PORTD on ATmega328P
1. *PORTB*:
- *Alternate Functions*:
- PB0 to PB5: Can be used as MOSI, MISO, SCK, SS for SPI communication.
- PB6, PB7: Used as crystal oscillator pins XTAL1 and XTAL2 for clock input.
2. *PORTC*:
- *Alternate Functions*:
- PC0 to PC5: Used for ADC inputs (ADC0 to ADC5) in analog-to-digital conversion.
3. *PORTD*:
- *Prime Functions*: General-purpose I/O pins (PD0 to PD7).
- *Alternate Functions*:
2(b) The ATmega328P microcontroller integrates various hardware modules designed for embedded
control applications. These include:
6. *Timers/Counters*:
7. *ADC (Analog-to-Digital Converter)* - 10-bit ADC with 6 input channels on PORTC for converting
analog signals.
10. *I²C (Two-Wire Interface)* - Also called TWI, for communication with other devices.
12. *Analog Comparator* - Compares two analog voltages and outputs a digital signal.
14. *Clock Oscillator* - Supports internal and external oscillators for the system clock.
These modules make the ATmega328P versatile for various control and automation applications.
2(c) To convert the given C++ code into assembly code for the ATmega328P, let's first understand the
code and then break it down into the corresponding assembly instructions.
cpp
byte y1 = 0x65;
byte y2 = 0x73;
byte y = y1 | y2;
- The bitwise OR operation | is performed between y1 and y2, and the result is stored in y.
---
The ATmega328P assembly code for this would use registers for y1, y2, and the result y. We will use
general-purpose registers (r16, r17, and r18 for example).
asm
mov r18, r16 ; Move the result into register r18 (which will represent y)
### Explanation:
1. **ldi r16, 0x65**: Load the value 0x65 (binary: 01100101) into register r16.
2. **ldi r17, 0x73**: Load the value 0x73 (binary: 01110011) into register r17.
3. **or r16, r17**: Perform a bitwise OR between the values in registers r16 and r17, and store the
result back in r16. The result of 01100101 | 01110011 will be 01110111 (which is 0x77).
4. **mov r18, r16**: Move the result of the OR operation from r16 to r18, which is the register
representing y.
Answer to question no 3
Here's a breakdown and explanation of each code, line by line, for each question:
---
Question 3(a)
Code Explanation:
const int buttonPin = 4; // Pin connected to SW1
void setup() {
void loop() {
1. Variables Setup:
buttonPin and ledPin store the pin numbers for the button (SW1) and LED.
ledState holds the current state of the LED (LOW = off, HIGH = on).
buttonState and lastButtonState track the current and previous states of the button.
2. setup() Function:
3. loop() Function:
if (buttonState != lastButtonState) checks if the button state has changed (pressed or released).
if (buttonState == HIGH) checks if the button is pressed. When pressed, it toggles the LED state using
ledState = !ledState; (inverts the state) and writes the new state to the LED pin.
delay(50); is a debounce delay to prevent the button from being detected multiple times due to
mechanical bouncing.
lastButtonState = buttonState; updates the previous state for the next loop.
---
Question 3(b)
Objective: Receive the string "1234" from Serial Monitor, convert it to an integer, and display it.
Code Explanation:
void setup() {
void loop() {
else {
1. Variables Setup:
index keeps track of the position in the array where the next character will be stored.
2. setup() Function:
Serial.begin(9600); initializes serial communication with a baud rate of 9600, allowing the Arduino to
communicate with the Serial Monitor.
3. loop() Function:
if (receivedChar == '\n') checks if the character is a newline ('\n'). If so, it means the user finished typing
a line.
inputString[index] = '\0'; adds a null terminator to the end of the array, converting it into a proper string.
int number = atoi(inputString); converts the string (e.g., "1234") to an integer using the atoi function.
If receivedChar is not '\n', it adds the character to inputString and increments index for the next
character.
---
Question 3(c)
Objective: Read voltage from an analog pin (A3) and display it on the Serial Monitor.
Code Explanation:
const int analogPin = A3; // Pin connected to A3
void setup() {
void loop() {
Serial.print(voltage);
1. Variables Setup:
voltage will store the calculated voltage value based on the analog reading.
2. setup() Function:
analogRead(analogPin); reads the analog value from pin A3. This value is between 0 and 1023,
representing a range from 0V to 5V.
voltage = sensorValue * (5.0 / 1023.0); converts the raw sensor value to voltage using the formula:
Dividing by 1023.0 scales the raw sensor value to the voltage range.
Serial.print() and Serial.println() display the voltage reading on the Serial Monitor.
---
These explanations cover all three sketches in detail. Let me know if there’s any part you would like
further clarification on!
Answer to question no 4
Question 4(a)
Objective: Calculate the speed of the robot car using an encoder disc.
Explanation:
1. Components in Use:
A 25-slot encoder disc is attached between an IR transmitter and receiver. The IR sensor can detect each
slot as it passes, generating a signal every time a slot moves past it.
Each signal generated represents a fraction of one full rotation of the wheel.
2. Speed Calculation:
cm.
Since there are 25 slots, each slot passing through the IR sensor corresponds to a movement of:
cm.
The microcontroller can calculate the speed by counting the number of slots detected in a given time
frame and multiplying by the distance per slot.
We will set up an interrupt service routine (ISR) for the INT1 pin, which triggers every time the IR sensor
detects a slot.
The code calculates speed based on the number of interrupts over a given time period.
Arduino Sketch:
const int encoderPin = 2; // Pin connected to INT1 (digital pin 2 on most Arduino boards)
const float distancePerSlot = 1.25664; // Distance moved per slot (in cm)
void setup() {
}
void loop() {
Serial.print("Speed: ");
Serial.print(speed);
Serial.println(" cm/s");
void countSlot() {
In loop(), the speed is calculated every second (1000 ms) by multiplying slotCount with distancePerSlot.
countSlot() is an ISR that increments slotCount each time a slot is detected by the encoder.
---
Question 4(b)
For this part, you'd typically illustrate different phases of a taxi meter's journey as line diagrams. Each
drive type can represent a phase or type of operation in a taxi meter:
This could represent the start of a journey when the taxi meter begins to charge.
In a line diagram, it would show an initial steady state, transitioning to active charging state upon
starting the trip.
Represents distance-based charging where fare increases based on the distance traveled.
In the line diagram, you would see a step-wise increase in fare as distance increases.
3. C-drive (Cruise Drive):
Represents time-based fare increment, often used when the taxi is stationary but waiting.
In the line diagram, the fare would increase over time while the distance remains constant.
Note: The actual line diagrams would illustrate these modes visually as timelines or fare increment
trends.
---
Question 4(c)
Objective: Implement LED blinking using a class-based approach, where ioDir(), onLED(), and offLED()
control the LED's behavior.
Code Explanation:
To achieve this, we’ll define a class with methods ioDir() to set the LED direction, onLED() to turn it on,
and offLED() to turn it off. This approach encapsulates the LED control within a class structure.
Arduino Sketch:
public:
void ioDir() {
void onLED() {
void offLED() {
};
void setup() {
void loop() {
2. Create an Instance:
3. In setup():
led.ioDir(); calls the ioDir() method to set the LED pin as an output.
4. In loop():
This approach encapsulates LED control in a class structure, making the code modular and reusable.
Answer to question no 5
Certainly! Let's go through each question with the code and explanations.
---
Question 5
This question requires blinking two LEDs at 1-second intervals and displaying the result of 0x23 + 0x19
on the serial monitor.
pinMode(LED1, OUTPUT);
pinMode(LED2, OUTPUT);
void loop() {
previousMillis = currentMillis;
digitalWrite(LED1, !digitalRead(LED1));
digitalWrite(LED2, !digitalRead(LED2));
Explanation:
#include <avr/pgmspace.h>
void setup() {
Serial.begin(9600);
Serial.println(retrievedData, HEX);
void loop() {
// Empty loop
Explanation:
---
For ASCII character 'A' (binary 01000001), here’s an example of code sending the data over serial.
void setup() {
Serial.begin(9600);
Serial.println(character);
void loop() {
// Empty loop
Explanation:
Character 'A' (0x41) will be sent with start bit (0), 7 data bits, parity bit (optional), and stop bit (1). No
drawing needed in code, but this represents asynchronous communication.
---
Answer to question no 6
Here’s a basic structure for two Arduino devices, one as Master and one as Slave, for reading voltage
and communicating over I2C. This requires the Wire library.
#include <Wire.h>
#define SLAVE_ADDRESS 8
#define ANALOG_PIN A3
void setup() {
Serial.begin(9600);
void loop() {
Wire.beginTransmission(SLAVE_ADDRESS);
Wire.endTransmission();
Serial.println(voltage);
delay(1000);
#include <Wire.h>
void setup() {
Serial.begin(9600);
Serial.println(voltage);
void loop() {
// Empty loop
Explanation:
The master reads an analog voltage, sends it to the slave over I2C, and the slave displays it.
---
6b) SPI Communication between Two Arduinos
This example code demonstrates SPI communication between Master and Slave Arduino for data
exchange.
// Master Code
#include <SPI.h>
void setup() {
SPI.begin();
pinMode(SS, OUTPUT);
Serial.begin(9600);
void loop() {
digitalWrite(SS, LOW);
digitalWrite(SS, HIGH);
delay(1000);
// Slave Code
#include <SPI.h>
void setup() {
pinMode(MISO, OUTPUT);
SPI.begin();
Serial.begin(9600);
}
void loop() {
if (SPI.available()) {
Serial.print("Received: ");
Serial.println(received, HEX);
Explanation:
Master sends 0x34 and the slave responds with 0xCD over SPI.
---
Answer to question no 7
#include <Servo.h>
Servo myservo;
void setup() {
Serial.begin(9600);
myservo.attach(3);
void loop() {
if (Serial.available()) {
myservo.write(angle);
Serial.println(angle);
Explanation:
---
void setup() {
TCCR1A = 0;
TCCR1B = (1 << CS12) | (1 << CS10); // Prescaler 1024
TCNT1 = 0;
Serial.begin(9600);
void loop() {
Explanation:
---
Answer to question no 8
#include <OneWire.h>
#include <DallasTemperature.h>
#define ONE_WIRE_BUS 3
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
void setup() {
Serial.begin(9600);
sensors.begin();
void loop() {
sensors.requestTemperatures();
Serial.print("Temperature: ");
Serial.println(tempC);
delay(1000);
Explanation:
---
void setup() {
Serial.begin(9600);
void loop() {
Serial.print(distance);
Serial.println(fare);
delay(1000);
Explanation:
---
Serial.begin(9600);
Serial.println(token);
void loop() {
// Empty loop
Explanation:
---
Fall 22
Let's go through each question and provide the code along with detailed explanations.
---
### Question 2
*Objective*: Establish a Software UART (SUART) communication between Arduino UNO and Arduino
NANO to send a float value (12.75) from UNO to NANO using digital pins 7 and 8.
*Explanation of Code*:
- *UNO Code*:
- We are using SoftwareSerial to create a serial communication on pins 7 (TX) and 8 (RX) as a substitute
for the hardware serial.
cpp
#include <SoftwareSerial.h>
void setup() {
void loop() {
- *NANO Code*:
- Serial.println(data); outputs the received data to the Serial Monitor on NANO, which helps in verifying
the communication.
cpp
#include <SoftwareSerial.h>
void setup() {
void loop() {
if (SUART.available()) {
2(c)
Here's an Arduino sketch for the Nano to act as an I2C slave with address `0x23`. This sketch will
respond with the data `0x5678` whenever the master requests it.
```cpp
#include <Wire.h>
void setup() {
void loop() {
void requestEvent() {
Wire.write(highByte);
Wire.write(lowByte);
```
### Explanation:
- **requestEvent:** In this function, `0x5678` is split into two bytes (high and low) and sent to the
master.
This way, when the master requests data, the slave will respond with `0x5678`.
*Objective*: Calculate the relationship between temperature \( T \) and analogRead(A1) for an LM35
sensor.
*Explanation of Solution*:
\[
V_{DT} = 0.01T
\]
- The analog reading for the ADC (assuming 5V reference and 10-bit resolution) is:
\[
\]
\[
T = \frac{\text{ADC\_Value}}{2.046}
\]
*Code for Temperature Calculation*:
cpp
void setup() {
void loop() {
Serial.print("Temperature: ");
Serial.print(temperature);
Serial.println(" °C");
---
### Question 3
*Objective*: Set up a 4-Wire SPI communication between Master (UNO) and Slave (NANO) and
exchange data (send 0x56 from Master and 0x23 from Slave).
*Explanation of Code*:
cpp
#include <SPI.h>
void setup() {
void loop() {
cpp
#include <SPI.h>
void setup() {
void loop() {
---
#### Part (b)
*Objective*: Set up an external interrupt on the ATmega328P (e.g., Arduino UNO) using the INT1 pin
and trigger an ISR on a rising edge.
*Explanation of Code*:
- attachInterrupt(digitalPinToInterrupt(2), ISR, RISING); attaches an interrupt to the INT1 pin (digital pin
2 on UNO).
- The ISR() function is called whenever a rising edge is detected on the INT1 pin.
cpp
void setup() {
void ISR() {
void loop() {
This interrupt code allows the Arduino to respond instantly to a rising edge on INT1, which can be useful
for timing-critical applications.
Let’s solve each question step-by-step:
---
3c]
*Objective*: Write code to check the TOV1 flag (Timer Overflow Flag 1) every 2 seconds and then turn
on an LED connected to a pin at the 10-second mark.
#### Explanation
1. *TOV1 Flag*:
- The TOV1 flag is set when Timer 1 overflows, which means the timer counts from 0 up to its
maximum (0xFFFF for a 16-bit timer).
2. *Solution*:
- Using a prescaler value, we can set Timer 1 to overflow approximately every 2 seconds.
- When this counter reaches 5 (2 seconds * 5 = 10 seconds), we turn on an LED connected to a specific
pin.
#### Code
cpp
void setup() {
void loop() {
*Explanation of Code*:
- TCCR1A = 0; and TCCR1B = (1 << CS12); configure Timer1 in normal mode with a 256 prescaler.
- After 5 overflows (approximately 10 seconds), we turn on the LED by setting ledPin to HIGH.
---
4c)
*Objective*: Present the connection diagram and code to control an LED's brightness with a
potentiometer.
1. *Connections*:
- *Potentiometer*:
- *LED Circuit*:
- Connect *D9* (PWM pin) on the Arduino to one end of *R1* (resistor).
#### Code
*Explanation of Code*:
- We read the potentiometer value using analogRead(A0), which gives a value between 0 and 1023.
- We map this value to a range suitable for PWM (0-255) using map() to control the LED brightness.
- analogWrite(ledPin, brightness); sets the brightness of the LED based on the mapped value.
cpp
void setup() {
}
void loop() {
*Explanation of Mapping*:
- The map(potValue, 0, 1023, 0, 255); function linearly maps the potentiometer value from its 0-1023
range to the 0-255 range, suitable for PWM brightness control.
- This makes the LED's brightness increase as you rotate the potentiometer.
This code will allow you to smoothly adjust the brightness of LED1 by rotating the potentiometer.
void setup() {
pinMode(ledPin, OUTPUT);
void loop() {
// Main loop does nothing; waiting for interrupts
ISR(INT0_vect) {
Pin Initialization: The ledPin (pin 13) is set as an output to control the LED.
Register Configuration:
Inside the ISR, we blink the LED on ledPin five times, with each blink lasting 1 second on and 1 second
off.
---
### Question 6b
*Objective*: Write initialization code to configure an Arduino Nano as an SPI slave.
To set up an Arduino Nano as an SPI slave, we need to configure the *SPI registers* to allow it to receive
data from an SPI master device. The *SPI pins* on the Nano are:
When configuring the Nano as an SPI slave, only the *MISO* pin will send data to the master, while
*MOSI, **SCK, and **SS* are inputs.
cpp
#include <SPI.h>
void setup() {
pinMode(MISO, OUTPUT);
pinMode(MOSI, INPUT);
pinMode(SCK, INPUT);
pinMode(SS, INPUT);
SPCR |= (1 << SPE); // Set SPE (SPI Enable) bit in SPCR register
void loop() {
// SPI interrupt can handle incoming data, or you can use polling in the main loop
*Explanation*:
- *Set MISO as Output*: Since MISO is the only output in an SPI slave configuration, it’s set to OUTPUT.
The other pins are set as INPUT.
- *Enable SPI as Slave*: Setting the SPE bit in the SPCR register enables SPI in slave mode.
- *Enable Interrupts (Optional)*: Setting the SPIE bit enables the SPI interrupt, which can be used to
trigger specific actions when data is received. You would need an ISR(SPI_STC_vect) function if you use
the interrupt approach.
---
### Question 6c
*Objective: Write a sketch to blink an LED on an Arduino UNO at a 1-second interval, using the **TOV1
(Timer Overflow Flag 1)* interrupt of *Timer1 (TC1)*.
To achieve this:
3. The LED will be connected to a specific pin, and it will turn on and off each time the overflow interrupt
triggers, effectively blinking at a 1-second interval.
#### Code to Blink LED with TOV1 Overflow Interrupt
cpp
const int ledPin = 13; // Pin connected to the LED (typically built-in LED on pin 13 for UNO)
void setup() {
// Configure Timer1
sei();
void loop() {
// Main code can run here (if any), but the LED toggling is handled by the interrupt
}
*Explanation*:
1. *Set Timer1 Prescaler*: The line TCCR1B = (1 << CS12) | (1 << CS10); sets a prescaler of *1024* for
Timer1.
- With a prescaler of 1024, Timer1 (16-bit) will overflow approximately every 1 second, assuming a
clock speed of 16 MHz on the Arduino UNO. (The exact overflow timing is slightly less than 1 second, but
close enough for blinking purposes.)
2. *Enable Timer1 Overflow Interrupt*: Setting TIMSK1 = (1 << TOIE1); enables the Timer1 overflow
interrupt.
4. *Global Interrupt Enable*: sei(); enables global interrupts, allowing the Timer1 overflow interrupt to
function.
This code will blink the built-in LED on pin 13 every second using the Timer1 overflow interrupt. Each
time Timer1 overflows, the TOV1 flag triggers the ISR, toggling the LED.
Question 7a
void setup() {
pinMode(led1Pin, OUTPUT);
pinMode(led2Pin, OUTPUT);
digitalWrite(led1Pin, led1State);
digitalWrite(led2Pin, led2State);
void loop() {
previousMillis = currentMillis;
// Toggle the states of both LEDs
led1State = !led1State;
led2State = !led2State;
digitalWrite(led1Pin, led1State);
digitalWrite(led2Pin, led2State);
### Question 7b
*Objective: Develop a sketch to generate a Fast PWM signal in **Mode 14* (Fast PWM mode with ICR1
as the top value) on *digital pin 10* with a frequency of 1 Hz and a duty cycle of 60%.
In *Mode 14* (Fast PWM with ICR1 as TOP) on *Timer1* of the Arduino UNO:
1. *Frequency: We control the frequency by setting the value of the **ICR1* register. The frequency \
( f \) can be calculated as:
\[
\]
2. *Duty Cycle: We set the duty cycle by adjusting the **OCR1A* value. For a duty cycle \( D \% \),
OCR1A can be calculated as:
\[
\]
Using a clock frequency of 16 MHz and a prescaler of 1024, we can calculate values for ICR1 and OCR1A
to generate a 1 Hz PWM signal with a 60% duty cycle.
cpp
void setup() {
pinMode(10, OUTPUT);
TCCR1A = (1 << COM1B1) | (1 << WGM11); // Non-inverting mode on OC1B (pin 10)
TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS12) | (1 << CS10); // Prescaler 1024
void loop() {
- TCCR1A = (1 << COM1B1) | (1 << WGM11); sets the Timer to Fast PWM, non-inverting mode.
- TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS12) | (1 << CS10); configures the Timer to use ICR1
as the top value with a prescaler of 1024.
- ICR1 = 15624; sets the PWM frequency to 1 Hz (16 MHz clock / (1024 prescaler * 1 Hz) - 1).
- OCR1B = (60 * (ICR1 + 1)) / 100; sets the duty cycle to 60%.
This will generate a 1 Hz PWM signal on pin 10 with a 60% duty cycle.
---
### Question 7c
*Objective: Define the terms **D drive, **T drive, and **C drive* in the context of a taxi cab's journey.
#### Definitions
- This represents the initial part of the journey when the taxi departs from its starting location. It
involves picking up the passenger and starting the trip. The *D Drive* typically covers the initial route,
including navigating through pickup areas and finding the shortest route to the passenger.
- The *T Drive* represents the main part of the journey where the taxi is in transit, taking the
passenger from the pickup location to the destination. This part of the journey involves following the
planned route, obeying traffic laws, and possibly adjusting the route in response to traffic conditions.
The *T Drive* focuses on reaching the destination efficiently.
These terms (D, T, and C drives) help categorize different segments of a taxi journey, each with distinct
tasks and considerations.
8b)To store data in the flash memory of an *ATmega328P* (such as on an Arduino Uno) and then read it
back, we need to understand a few limitations:
1. *Flash memory on the ATmega328P* is generally used for storing program code, not variable data.
However, we can use special functions to write specific values to certain flash locations (such as a
dedicated section of flash memory).
2. Writing to flash memory from code running on the ATmega328P is not a typical operation since flash
memory is primarily meant for program storage and is only writable under certain conditions (such as
during bootloading).
3. Direct manipulation of flash memory requires some lower-level code, including assembly, to manage
page writes.
The *EEPROM* on the ATmega328P is often used for storing small amounts of data that need to persist
even after power is removed, and it is more suitable for tasks like storing a single byte. EEPROM is easier
to work with in code compared to directly writing to flash memory.
Below, I'll provide a sketch to store 0x35 in the EEPROM and then read it back for verification.
cpp
#include <EEPROM.h>
void setup() {
Serial.begin(9600);
// Write 0x35 to EEPROM address 0
EEPROM.update(0, 0x35);
if (readValue == 0x35) {
} else {
Serial.println(readValue, HEX);
void loop() {
// Nothing to do in loop
1. *Write to EEPROM*:
- EEPROM.update(0, 0x35); writes the value 0x35 to address 0 in EEPROM. We use update instead of
write to prevent redundant writes if the value at the address is already 0x35, which can extend EEPROM
life.
3. *Verification*:
- We check if the value read from EEPROM matches 0x35. If it does, a success message is printed to the
Serial Monitor. Otherwise, it displays the read value to indicate a failure.
Directly writing to flash memory from within a running program on an ATmega328P requires
bootloader-level access, as the chip does not support self-programming in normal code execution. If you
specifically need to use flash memory, a custom bootloader or external programming tools are required,
and it goes beyond standard Arduino programming.
Using the *EEPROM* as shown above is a practical alternative when persistent storage is required.
// Define the pins for the 7-segment display segments (common cathode configuration)
0b00111111, // 0
0b00000110, // 1
0b01011011, // 2
0b01001111, // 3
0b01100110, // 4
0b01101101, // 5
0b01111101, // 6
0b00000111, // 7
0b01111111, // 8
0b01101111 // 9
};
int counter = 0;
void setup() {
pinMode(segmentPins[i], OUTPUT);
pinMode(dpPin, OUTPUT);
pinMode(upButtonPin, INPUT);
pinMode(downButtonPin, INPUT);
displayDigit(counter);
void loop() {
// Read the state of the UP and DOWN buttons
} else if (!upState) {
} else if (!downState) {
byte segments = digits[num]; // Get the segment pattern for the number
// Set each segment based on the pattern
Spring 22
#### a) Refer to Fig-2(a), create a sketch to stop Pump-1 after 30 minutes or if the high-level switch (KH)
is activated.
- This can be achieved using an Arduino sketch. The logic is to check the run time and switch status.
cpp
void setup() {
pinMode(pump1Pin, OUTPUT);
pinMode(khPin, INPUT);
isRunning = true;
void loop() {
if (isRunning) {
isRunning = false;
} else {
Part (b)
You are required to write a sketch (program) to store specific information into the EEPROM of an
ATmega328P microcontroller. The information includes:
ID: "192005001"
GPA: "3.65"
The data needs to be stored in EEPROM starting at location 0x0120, and then you need to verify it by
reading it back and displaying it on the Serial Monitor.
#include <EEPROM.h>
void setup() {
Serial.begin(9600);
EEPROM.write(addr++, name[i]);
EEPROM.write(addr++, id[i]);
EEPROM.write(addr++, gpa[i]);
addr = 0x0120;
Serial.print("Name: ");
Serial.println();
Serial.print("ID: ");
Serial.print((char)EEPROM.read(addr++));
Serial.println();
Serial.print("GPA: ");
Serial.print((char)EEPROM.read(addr++));
Serial.println();
void loop() {
// Nothing to do here
Explanation:
1. The EEPROM.write() function is used to write each character to EEPROM starting at address 0x0120.
2. After writing the data, the code reads back the stored values from the EEPROM using EEPROM.read()
and prints them to the Serial Monitor.
3. The name, ID, and GPA are stored consecutively, each taking up space in EEPROM based on the
number of characters.
Part (c)
For this part, you need to present the ATmega328P assembly instructions that would replicate the
following C++ code:
byte y = 0x35;
This instruction involves storing the value 0x35 in a memory location using the X-pointer register.
ldi r16, 0x35 ; Load the immediate value 0x35 into register r16
sts y, r16 ; Store the value of r16 into memory location 'y'
However, if you are required to use the X-pointer register specifically (which uses registers r26 and r27
in AVR), you can do it like this:
ldi r26, low(y) ; Load the low byte of address 'y' into r26
ldi r27, high(y) ; Load the high byte of address 'y' into r27
st X, r16 ; Store the value of r16 into the address pointed by X (r26:r27)
Explanation:
1. ldi (Load Immediate) loads immediate values into registers.
2. sts (Store Direct to SRAM) directly stores the value in a register to a specific address.
3. st X, r16 stores the value of r16 at the address pointed to by the X register (which is a combination of
r26 and r27).
- This involves setting up serial communication between two Arduinos (UNO and NANO).
cpp
void setup() {
Serial.begin(9600);
void loop() {
if (Serial.available()) {
cpp
String data;
void setup() {
Serial.begin(9600);
void loop() {
if (Serial.available()) {
Let's address each part of your question, starting with part *(b)* and then moving to part *(c)*.
---
The LM35 temperature sensor outputs a voltage that is linearly proportional to the temperature in
degrees Celsius. When connected to an analog input of the Arduino (like A1), you can read this voltage
using analogRead(), which gives a value between 0 and 1023 (representing 0V to 5V).
- In terms of Arduino's ADC, if \( V_{in} \) is the voltage measured, the digital value from analogRead() is:
\[
\text{ADC Value} = \frac{V_{in}}{5.0} \times 1023
\]
\[
\]
The factor 100 comes from converting the voltage to Celsius because each 10 mV represents 1°C.
Here’s the code to read the LM35 temperature and calculate the temperature in Celsius:
cpp
void setup() {
void loop() {
Serial.print("Temperature: ");
Serial.print(temperature);
Serial.println(" °C");
### Explanation:
- temperature = (sensorValue / 1023.0) * 5.0 * 100;: Converts the analog reading to voltage and then to
temperature.
---
### Part (c): I2C Communication between Master and Slave for Sending a Float Value
In this scenario:
- An Arduino (Master) will request the current value of a float variable I (representing current) from
another Arduino (Slave).
- The Slave will send the float I as four bytes to the Master over I2C.
- The Master will then convert these bytes back into a float and display it on a Serial Monitor (SM1) at a
1-second interval.
### Master Code (Arduino)
cpp
#include <Wire.h>
void setup() {
void loop() {
byte receivedBytes[4];
int index = 0;
receivedBytes[index++] = Wire.read();
float current;
Serial.println(current);
2. Wire.requestFrom(slaveAddress, 4);: Requests 4 bytes from the slave device at address 0x13.
3. while (Wire.available() && index < 4): Reads each byte sent by the slave and stores them in
receivedBytes.
4. memcpy(¤t, receivedBytes, sizeof(float));: Uses memcpy to convert the 4-byte array into a
float.
cpp
#include <Wire.h>
void setup() {
}
void loop() {
void requestEvent() {
byte floatBytes[4];
Wire.write(floatBytes[i]);
1. Wire.begin(0x13);: Initializes the Arduino as an I2C slave with the address 0x13.
4. Wire.write(floatBytes[i]);: Sends each byte of the float to the Master in response to its request.
---
### Summary:
- *Part (b)*: The code reads the LM35 temperature sensor and calculates the temperature in Celsius.
- *Part (c)*: The Master requests a float value (I) from the Slave over I2C. The Slave sends this value as 4
bytes, which the Master then reassembles into a float and displays.
This setup enables the Master to display the float value on SM1 (Serial Monitor) at a 1-second interval.
#### *4a) Suppose you have stored 0x7D and 0x6E in the SPDR registers of Master and Slave
respectively. With a proper diagram, illustrate what data will be stored in the SPDR registers after 2, 4,
and 8 clock pulses. Also build a sketch to send 0x7D to the slave and receive 0x6E from the slave on an
interrupt basis.*
*Explanation:*
The Serial Peripheral Interface (SPI) communication involves the exchange of data between a master
and a slave device. In this scenario, we are using the SPDR (SPI Data Register) to send and receive data
between two devices. When using SPI, data is shifted out of the master’s SPDR and shifted into the
slave’s SPDR, and vice versa, one bit per clock pulse.
After:
- *2 Clock Pulses*: 2 bits will have been exchanged between master and slave.
- *8 Clock Pulses*: Complete byte (8 bits) exchange will have taken place, with the master receiving 0x6E
and the slave receiving 0x7D.
*Sample Arduino Code for SPI Master (sending 0x7D and receiving 0x6E):*
cpp
#include <SPI.h>
void setup() {
ISR(SPI_STC_vect) {
void loop() {
while (!transferComplete);
transferComplete = false;
byte receivedData = SPDR; // Read data received from Slave (should be 0x6E)
*Sample Arduino Code for SPI Slave (receiving 0x7D and sending 0x6E):*
cpp
#include <SPI.h>
void setup() {
ISR(SPI_STC_vect) {
dataReceived = true;
void loop() {
while (!dataReceived);
dataReceived = false;
byte receivedData = SPDR; // Read data received from Master (should be 0x7D)
---
#### *4b) Assume LED-1 and LED-2 are connected with Dpin-8 and Dpin-9 respectively. Build a sketch to
blink LED-2 with 1s interval in MLP (Main Loop Program). When IRQ1 signal arrives, blinking LED-2 will
be interrupted and LED-1 will blink for 5 times with 2s interval. Then it will return to MLP.*
*Explanation:*
This code sets up two LEDs on an Arduino, with LED-2 blinking every second in the main loop. When an
external interrupt on pin IRQ1 (Dpin-2) occurs, LED-2 stops blinking, and LED-1 blinks 5 times with a 2-
second interval, then resumes LED-2 blinking.
*Sample Arduino Code:*
cpp
void setup() {
pinMode(led1, OUTPUT);
pinMode(led2, OUTPUT);
void loop() {
if (!interruptFlag) {
delay(1000);
digitalWrite(led2, LOW);
delay(1000);
void handleInterrupt() {
digitalWrite(led1, HIGH);
delay(2000);
digitalWrite(led1, LOW);
delay(2000);
}
To help you with these questions, I’ll break down the coding tasks and explanations for each part. Here’s
a step-by-step solution and guidance for each question:
---
### Question 5
\[
\]
where:
- \( N \) is the prescaler,
- \( TOP \) is the maximum count value (determined by ICR1 in this case for mode 14).
- Adjust \( ICR1 \) to set the top value, which changes the frequency.
2. *Send ASCII Commands*: Write code to interpret ASCII commands from the Android phone to set
servo angles.
Example code:
cpp
#include <SoftwareSerial.h>
#include <Servo.h>
Servo servo;
void setup() {
mySerial.begin(9600);
void loop() {
if (mySerial.available() > 0) {
servo.write(angle);
}
---
1. *Connect BMP280 via SPI*: Use MOSI, MISO, SCK, and CS lines.
- *Arduino* ↔ *BMP280*
---
### Question 6
Part (c)
Here's an Arduino code that uses a class to calculate the area of a rectangle given the length and width:
cpp
class Rectangle {
private:
float length;
float width;
public:
Rectangle(float l, float w) {
length = l;
width = w;
float calculateArea() {
};
void setup() {
Serial.begin(9600);
Serial.print(area);
Serial.println(" cm^2");
}
void loop() {
### Explanation:
- The Rectangle class has two private member variables (length and width).
- The calculateArea() function returns the area of the rectangle by multiplying length and width.
- In setup(), an instance of Rectangle is created with the specified dimensions, and the area is calculated
and printed to the Serial Monitor.
### Question 7
Example code:
cpp
void setup() {
pinMode(ledPin, OUTPUT);
Serial.begin(9600);
void loop() {
if (Serial.available() > 0) {
digitalWrite(ledPin, HIGH);
digitalWrite(ledPin, LOW);
2. Converts the analog signal to a digital value (10-bit resolution by default on Arduino).
Example code:
cpp
#include <Wire.h>
union {
float value;
byte bytes[4];
} floatUnion;
void setup() {
Wire.begin();
void loop() {
floatUnion.value = 15.73;
Wire.beginTransmission(0x23);
Wire.write(floatUnion.bytes, 4);
Wire.endTransmission();
delay(1000);
---
### Question 8
Example code:
cpp
#include <OneWire.h>
#include <DallasTemperature.h>
#define ONE_WIRE_BUS 2
#define PWM_PIN_LOW 5
#define PWM_PIN_HIGH 10
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
void setup() {
sensors.begin();
pinMode(PWM_PIN_LOW, OUTPUT);
pinMode(PWM_PIN_HIGH, OUTPUT);
void loop() {
sensors.requestTemperatures();
analogWrite(PWM_PIN_HIGH, 0);
} else {
analogWrite(PWM_PIN_LOW, 0);
delay(1000);
- A rising, falling, or low-level condition should trigger the interrupt, as per the configuration.
2. *TC1 Prescaler*.
---
This breakdown should help you understand each question and its corresponding solution code. Let me
know if you need further assistance with any specific part!