0% found this document useful (0 votes)
18 views

MCU Solution

cZcZc

Uploaded by

ayonpc590
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
18 views

MCU Solution

cZcZc

Uploaded by

ayonpc590
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 73

SPRING 23

Answer to question no 2

2a) ### Differences between Microprocessor and Microcontroller

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.
- *Microcontroller*: It is a compact integrated circuit designed for specific control
applications. It combines a processor with internal memory (RAM, ROM) and peripherals,
making it a complete, self-contained system.

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*:
- *Microprocessor*: Generally higher as it’s designed for high-performance tasks.
- *Microcontroller*: Lower, optimized for applications needing power efficiency.

5. *Cost*:
- *Microprocessor*: Typically more expensive due to the need for additional components.
- *Microcontroller*: Generally cost-effective as it integrates multiple components in one chip.

---

### Memory Layout Diagrams for ATmega328P

The ATmega328P Microcontroller has several distinct memory blocks:

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*:
- *Prime Functions*: General-purpose I/O pins (PB0 to PB7).
- *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*:
- *Prime Functions*: General-purpose I/O pins (PC0 to PC6).
- *Alternate Functions*:
- PC0 to PC5: Used for ADC inputs (ADC0 to ADC5) in analog-to-digital conversion.
- PC6: RESET pin, also used for resetting the microcontroller.

3. *PORTD*:
- *Prime Functions*: General-purpose I/O pins (PD0 to PD7).
- *Alternate Functions*:
- PD0, PD1: UART communication (RXD, TXD).
- PD2, PD3: External interrupt pins (INT0, INT1).
- PD5, PD6: Used for PWM output (OC0B, OC0A).
- PD7: PWM output (OC2).
2(b) The ATmega328P microcontroller integrates various hardware modules designed for
embedded control applications. These include:

1. *CPU (Central Processing Unit)* - The core processing unit.


2. *Flash Memory* - 32 KB of program memory.
3. *SRAM (Static RAM)* - 2 KB of data memory for temporary storage.
4. *EEPROM (Electrically Erasable Programmable Read-Only Memory)* - 1 KB for non-volatile
data storage.
5. *I/O Ports (PORTB, PORTC, PORTD)* - Configurable general-purpose input/output pins.
6. *Timers/Counters*:
- Timer/Counter0: 8-bit timer with PWM capability.
- Timer/Counter1: 16-bit timer with PWM capability.
- Timer/Counter2: 8-bit timer with PWM capability.
7. *ADC (Analog-to-Digital Converter)* - 10-bit ADC with 6 input channels on PORTC for
converting analog signals.
8. *USART (Universal Synchronous/Asynchronous Receiver Transmitter)* - Serial
communication module.
9. *SPI (Serial Peripheral Interface)* - Synchronous serial communication.
10. *I²C (Two-Wire Interface)* - Also called TWI, for communication with other devices.
11. *Watchdog Timer* - Used to reset the system in case of a malfunction.
12. *Analog Comparator* - Compares two analog voltages and outputs a digital signal.
13. *Interrupt System* - Provides internal and external interrupt handling.
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)
### C++ Code:

cpp
byte y1 = 0x65;
byte y2 = 0x73;
byte y = y1 | y2;

In this C++ code:


- y1 is assigned the value 0x65 (which is 01100101 in binary).
- y2 is assigned the value 0x73 (which is 01110011 in binary).
- The bitwise OR operation | is performed between y1 and y2, and the result is stored in y.
---

### ATmega328P Assembly Code:

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
; Load immediate values into registers
ldi r16, 0x65 ; Load y1 (0x65) into register r16
ldi r17, 0x73 ; Load y2 (0x73) into register r17

; Perform bitwise OR operation


or r16, r17 ; Perform r16 = r16 | r17

; Store the result in y (using r16)


mov r18, r16 ; Move the result into register r18 (which will represent y)
The final result of y will be 0x77 after the bitwise OR operation.
Answer to question no 3
Here's a breakdown and explanation of each code, line by line, for each question:

---

Question 3(a)

Objective: Toggle an LED state every time a button is pressed or released.

Code Explanation:

const int buttonPin = 4; // Pin connected to SW1


const int ledPin = 5; // Pin connected to LED
int ledState = LOW; // Current state of the LED (initially off)
int buttonState; // Current state of the button
int lastButtonState = LOW; // Previous state of the button (initially off)

void setup() {
pinMode(buttonPin, INPUT); // Set buttonPin (SW1) as an input
pinMode(ledPin, OUTPUT); // Set ledPin as an output
}

void loop() {
buttonState = digitalRead(buttonPin); // Read the current button state

if (buttonState != lastButtonState) { // Check if button state has changed


if (buttonState == HIGH) { // If button is pressed (HIGH state)
ledState = !ledState; // Toggle the LED state
digitalWrite(ledPin, ledState); // Set the LED to the new state
}
delay(50); // Short delay to debounce button
}

lastButtonState = buttonState; // Update lastButtonState to current


}

Question 3(b)

Objective: Receive the string "1234" from Serial Monitor, convert it to an integer, and display it.

Code Explanation:

char inputString[5]; // Array to hold input string, 5 to include null terminator


int index = 0; // Index for filling inputString
void setup() {
Serial.begin(9600); // Initialize serial communication at 9600 baud rate
}

void loop() {
if (Serial.available()) { // Check if data is available to read
char receivedChar = Serial.read(); // Read a character from Serial Monitor

if (receivedChar == '\n') { // Check if the character is newline


inputString[index] = '\0'; // Null-terminate the string
int number = atoi(inputString); // Convert the string to an integer
Serial.print("Received number: ");
Serial.println(number); // Display the number
index = 0; // Reset index for next input
}
else {
inputString[index++] = receivedChar; // Store received character in array
}
}
}

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
float voltage = 0.0; // Variable to store the measured voltage

void setup() {
Serial.begin(9600); // Initialize serial communication at 9600 baud rate
}

void loop() {
int sensorValue = analogRead(analogPin); // Read analog value from A3
voltage = sensorValue * (5.0 / 1023.0); // Convert to voltage
Serial.print("Voltage at A3: ");
Serial.print(voltage);
Serial.println(" V"); // Display voltage
delay(1000); // Update every second
}
Answer to question no 4
Here's a solution and explanation for each part of Question 4:
Question 4(a)
Objective: Calculate the speed of the robot car using an encoder disc.
Arduino Sketch:

const int encoderPin = 2; // Pin connected to INT1 (digital pin 2 on most Arduino boards)
volatile int slotCount = 0; // Variable to count slots detected
const float distancePerSlot = 1.25664; // Distance moved per slot (in cm)
unsigned long prevTime = 0; // Time of the last calculation

void setup() {
pinMode(encoderPin, INPUT); // Set encoder pin as input
attachInterrupt(digitalPinToInterrupt(encoderPin), countSlot, RISING); // Trigger ISR on rising
edge
Serial.begin(9600); // Initialize serial communication
}

void loop() {
unsigned long currentTime = millis(); // Get current time
if (currentTime - prevTime >= 1000) { // Calculate every 1 second
noInterrupts(); // Disable interrupts to safely access slotCount
int count = slotCount;
slotCount = 0; // Reset slot count for the next period
interrupts(); // Re-enable interrupts

float speed = count * distancePerSlot; // Calculate speed in cm/s


Serial.print("Speed: ");
Serial.print(speed);
Serial.println(" cm/s");

prevTime = currentTime; // Update time for the next calculation


}
}

void countSlot() {
slotCount++; // Increment slot count whenever the interrupt occurs
}

Question 4(b)

Objective: Define T-drive, D-drive, and C-drive journeys of a Taxi Meter.


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:

1. T-drive (Trip Drive):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.

2. D-drive (Distance Drive):

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.
Arduino Sketch:
#define LED 13 // LED connected to digital pin 13
class LEDControl {
public:
void ioDir() {
pinMode(LED, OUTPUT); // Set LED pin as output
}
void onLED() {
digitalWrite(LED, HIGH); // Turn LED on
}
void offLED() {
digitalWrite(LED, LOW); // Turn LED off
}
};

LEDControl led; // Create an instance of LEDControl

void setup() {
led.ioDir(); // Set LED direction as output
}

void loop() {
led.onLED(); // Turn LED on
delay(1000); // Wait for 1 second
led.offLED(); // Turn LED off
delay(1000); // Wait for 1 second
}

Answer to question no 5
Question 5

5a) Concurrent Blinking and Addition Display

This question requires blinking two LEDs at 1-second intervals and displaying the result of 0x23
+ 0x19 on the serial monitor.

const int LED1 = 4; // Pin for LED1


const int LED2 = 5; // Pin for LED2

unsigned long previousMillis = 0;


const long interval = 1000; // 1 second interval

void setup() {
pinMode(LED1, OUTPUT);
pinMode(LED2, OUTPUT);
Serial.begin(9600); // Initialize serial for displaying results
}
void loop() {
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis;

// Toggle LED states


digitalWrite(LED1, !digitalRead(LED1));
digitalWrite(LED2, !digitalRead(LED2));
}

// Display result of 0x23 + 0x19


int result = 0x23 + 0x19;
Serial.print("Result of 0x23 + 0x19 = ");
Serial.println(result, HEX); // Display in hexadecimal format
}

5b)
5c)

Answer to question no 6
6a)

// Master Code (Nano-1)


#include <Wire.h>
#define SLAVE_ADDRESS 8
#define ANALOG_PIN A3

void setup() {
Wire.begin(); // Join I2C bus as master
Serial.begin(9600);
}
void loop() {
int voltage = analogRead(ANALOG_PIN); // Read voltage
Wire.beginTransmission(SLAVE_ADDRESS);
Wire.write(voltage >> 8); // Send high byte
Wire.write(voltage & 0xFF); // Send low byte
Wire.endTransmission();

Serial.print("Voltage sent: ");


Serial.println(voltage);
delay(1000);
}

// Slave Code (Nano-2)


#include <Wire.h>

void setup() {
Wire.begin(8); // Join I2C bus with address 8
Wire.onReceive(receiveEvent); // Register event
Serial.begin(9600);
}

void receiveEvent(int bytes) {


int voltage = Wire.read() << 8 | Wire.read(); // Receive 2 bytes
Serial.print("Voltage received: ");
Serial.println(voltage);
}
void loop() {
// Empty loop
}

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);
SPI.transfer(0x34); // Send 0x34 to Slave
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()) {
int received = SPI.transfer(0xCD); // Send 0xCD to Master
Serial.print("Received: ");
Serial.println(received, HEX);
}
}
6(c)

### Explanation
The ATmega328P microcontroller can perform multiple tasks, such as reading sensor data,
controlling outputs, and more. However, it may occasionally need to respond to certain events,
like a button press, a timer overflow, or an external signal, immediately. Interrupts enable this
immediate response.

When an interrupt occurs:


1. The microcontroller pauses its current

Answer to question no 7
7a)

Control SG-90 Servo with HC-05 Bluetooth

Using Bluetooth to control a servo, based on received angle commands:

#include <Servo.h>
Servo myservo;

void setup() {
Serial.begin(9600);
myservo.attach(3);
}

void loop() {
if (Serial.available()) {
int angle = Serial.parseInt();
myservo.write(angle);
Serial.print("Servo angle set to: ");
Serial.println(angle);
}
}
7b) Generate a 4-Second Timer with TOV1 Polling

This code sets up a timer interrupt every 4 seconds using Timer1.


void setup() {
TCCR1A = 0;
TCCR1B = (1 << CS12) | (1 << CS10); // Prescaler 1024
TCNT1 = 0;
Serial.begin(9600);
}

void loop() {
if (TIFR1 & (1 << TOV1)) { // Check overflow flag
TIFR1 |= (1 << TOV1); // Clear flag
Serial.println("4 seconds passed");
}
}

(c)
Here’s a summary of the working principles for generating a Fast PWM signal in Mode-14
Operation of Timer/Counter 1 (TC1) in single-slope mode:

1. **Counting Mechanism**: TC1 starts counting up from 0 (BOTTOM).

2. **Clock Frequency**: The driving clock frequency for TC1 is determined by the system clock
(sysClk) divided by a prescaler (N).

3. **Non-inverting Mode Setup**:


- Initially, the output pin (DPin-9 or OC1A) is set to HIGH.
- When TC1's count matches the value in the compare register OCR1A (at Point-P in the
figure), OC1A goes LOW.
4. **Counting and Resetting**:
- TC1 continues to count up after Point-P.
- When the counter reaches the value in ICR1 (at Point-R), it resets to zero.

5. **Output Signal**:
- After resetting, DPin-9 (OC1A) goes HIGH again, starting the next PWM cycle.
- This cycle creates a pulse-width modulated (PWM) signal with a frequency determined by
the counting and reset actions.

6. **Automatic Flag Generation**:


- Flags are automatically set at specific points in the cycle:
- **OCF1A** at Point-P (when TC1 equals OCR1A).
- **OCF1B** at Point-Q.
- **ICF1** and **TOV1** at Point-R (when TC1 equals ICR1 and resets).

This setup effectively creates a Fast PWM signal, where the duty cycle is controlled by the value
in OCR1A.
Answer to question no 8
8a) DS18B20 Temperature Reading

Example code to read temperature from a DS18B20 sensor.


#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();
float tempC = sensors.getTempCByIndex(0);
Serial.print("Temperature: ");
Serial.println(tempC);
delay(1000);
}

8b) Taxi Meter Fare Calculation

This code calculates fare based on the problem’s requirements.


float calculateFare(float distance) {
if (distance <= 2.0) return 40.0;
return 40.0 + (distance - 2.0) * 12.0;
}

void setup() {
Serial.begin(9600);
}

void loop() {
float distance = 5.0; // Example distance
float fare = calculateFare(distance);
Serial.print("Total fare for ");
Serial.print(distance);
Serial.print(" km: Tk ");
Serial.println(fare);
delay(1000);
}

8c) Extract Tokens Using strtok

void setup() {
Serial.begin(9600);
char myData[] = "1234, Forum, 37.54";
char *token = strtok(myData, ", ");
while (token != NULL) {
Serial.println(token);
token = strtok(NULL, ", ");
}
}

void loop() {
// Empty loop
}
Fall 22
### Question 2

#### Part (a)


*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.

// Code for Arduino UNO


#include <SoftwareSerial.h>
SoftwareSerial SUART(7, 8); // Define SUART on pins 7 (RX) and 8 (TX)
void setup() {
SUART.begin(9600); // Initialize SUART at 9600 baud rate
}
void loop() {
float data = 12.75;
SUART.println(data); // Send the float value 12.75 to NANO
delay(1000); // Wait 1 second before sending again
}

#### Part (b)


Part(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>

const uint8_t SLAVE_ADDRESS = 0x23; // I2C address of the Nano


const uint16_t DATA_TO_SEND = 0x5678; // Data to send to the master

void setup() {
Wire.begin(SLAVE_ADDRESS); // Initialize the I2C as a slave with address 0x23
Wire.onRequest(requestEvent); // Register the request event handler
}

void loop() {
// Nothing to do in the main loop
}
void requestEvent() {
// Split 0x5678 into two bytes
uint8_t highByte = (DATA_TO_SEND >> 8) & 0xFF;
uint8_t lowByte = DATA_TO_SEND & 0xFF;

// Send two bytes


Wire.write(highByte);
Wire.write(lowByte);
}

### Question 3

#### Part (a)


*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
// Code for Arduino UNO as SPI Master
#include <SPI.h>

void setup() {
SPI.begin(); // Start SPI in master mode
pinMode(SS, OUTPUT); // Set SS pin as output
Serial.begin(9600); // Initialize Serial Monitor
}

void loop() {
digitalWrite(SS, LOW); // Enable slave
SPI.transfer(0x56); // Send data 0x56 to slave
digitalWrite(SS, HIGH); // Disable slave
delay(1000); // Wait 1 second before next transfer
}

2. *NANO (Slave) Code*:


- The NANO is set as an SPI slave.
- The SPI.attachInterrupt(); enables an interrupt service routine (ISR) on data reception.
- Inside the ISR, SPDR holds the received data, and we set SPDR = 0x23; to send 0x23 back to
the master.

cpp
// Code for Arduino NANO as SPI Slave
#include <SPI.h>
volatile byte receivedData;

void setup() {
SPI.begin(); // Start SPI in slave mode
pinMode(MISO, OUTPUT); // Set MISO as output for slave mode
SPCR |= _BV(SPE); // Enable SPI in slave mode
SPI.attachInterrupt(); // Enable SPI interrupt
Serial.begin(9600); // Initialize Serial Monitor
}

ISR(SPI_STC_vect) { // SPI interrupt service routine


receivedData = SPDR; // Read received data
SPDR = 0x23; // Prepare data to send back
}

void loop() {
Serial.println(receivedData); // Print received data to Serial Monitor
delay(1000); // Wait 1 second before printing again
}

---

#### 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*:

// Code for external interrupt on INT1 (pin 2 on Arduino UNO)


void setup() {
pinMode(2, INPUT); // Configure pin 2 as input for INT1
attachInterrupt(digitalPinToInterrupt(2), ISR, RISING); // Trigger ISR on rising edge
Serial.begin(9600); // Initialize Serial Monitor
}

void ISR() {
Serial.println("Rising Edge Interrupt Triggered!"); // Print message when interrupt occurs
}

void loop() {
// Main loop code continues to run until an interrupt occurs
}
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.

#### Code

cpp
const int ledPin = 9; // Pin connected to the LED
int overflowCounter = 0; // Counter to keep track of overflows
void setup() {
pinMode(ledPin, OUTPUT); // Set LED pin as output
TCCR1A = 0; // Set Timer1 to Normal mode
TCCR1B = (1 << CS12); // Set prescaler to 256
TCNT1 = 0; // Initialize Timer1 counter to 0
TIMSK1 = (1 << TOIE1); // Enable Timer1 overflow interrupt
sei(); // Enable global interrupts
}

ISR(TIMER1_OVF_vect) { // Timer1 overflow interrupt service routine


overflowCounter++; // Increment overflow counter
if (overflowCounter >= 5) { // 5 overflows ~ 10 seconds
digitalWrite(ledPin, HIGH); // Turn on LED
}
}

void loop() {
// Main code runs here
}

4c)
*Objective*: Present the connection diagram and code to control an LED's brightness with a
potentiometer.

#### Connection Diagram

#### Code

cpp
const int potPin = A0; // Pin connected to the potentiometer
const int ledPin = 9; // Pin connected to the LED through a resistor

void setup() {
pinMode(ledPin, OUTPUT); // Set LED pin as output
}

void loop() {
int potValue = analogRead(potPin); // Read potentiometer value (0-1023)
int brightness = map(potValue, 0, 1023, 0, 255); // Map to PWM range (0-255)
analogWrite(ledPin, brightness); // Set LED brightness
delay(10); // Short delay for stability
}
6(a)// Pin definition
const int ledPin = 13; // LED connected to digital pin 13

void setup() {
// Initialize LED pin as an output
pinMode(ledPin, OUTPUT);

// Configure INT0 to trigger on the rising edge


EICRA |= (1 << ISC01) | (1 << ISC00); // Rising edge on INT0
EIMSK |= (1 << INT0); // Enable INT0 interrupt
sei(); // Enable global interrupts
}

void loop() {
// Main loop does nothing; waiting for interrupts
}

// Interrupt Service Routine (ISR) for INT0


ISR(INT0_vect) {
// Blink LED 5 times with 1-second interval
for (int i = 0; i < 5; i++) {
digitalWrite(ledPin, HIGH); // Turn LED on
delay(1000); // Wait for 1 second
digitalWrite(ledPin, LOW); // Turn LED off
delay(1000); // Wait for 1 second
}
}

5(b)
Here's a basic sketch in Arduino for initiating communication with an I2C slave at address 0x57
and then sending the data items 0x23, 0x23, and the ASCII character "d":
cpp
#include <Wire.h>

#define SLAVE_ADDRESS 0x57

void setup() {
Wire.begin(); // Join the I2C bus as master
Serial.begin(9600); // Start serial communication at 9600 bps
}

void loop() {
Serial.println("Sending data to I2C slave...");

Wire.beginTransmission(SLAVE_ADDRESS); // Start communication with slave

Wire.write(0x23); // Send first byte: 0x23


Wire.write(0x23); // Send second byte: 0x23
Wire.write('d'); // Send ASCII character 'd'

uint8_t error = Wire.endTransmission(); // End transmission and get error code

if (error == 0) {
Serial.println("Data sent successfully!");
} else {
Serial.print("Error in transmission, error code: ");
Serial.println(error);
}

delay(1000); // Delay for a second before next transmission


}
.
### Question 6b

*Objective*: Write initialization code to configure an Arduino Nano as an SPI slave.

#include <SPI.h>

void setup() {
// Set MISO as OUTPUT, others as INPUT
pinMode(MISO, OUTPUT);
pinMode(MOSI, INPUT);
pinMode(SCK, INPUT);
pinMode(SS, INPUT);

// Enable SPI as Slave


SPCR |= (1 << SPE); // Set SPE (SPI Enable) bit in SPCR register

// Optional: Enable SPI Interrupt


SPCR |= (1 << SPIE); // Enable SPI interrupt if required
}

void loop() {
// SPI interrupt can handle incoming data, or you can use polling in the main loop
}

### Question 6c

*Objective: Write a sketch to blink an LED on an Arduino UNO at a 1-second interval, using the

#### 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() {
pinMode(ledPin, OUTPUT); // Set the LED pin as output

// Configure Timer1
TCCR1A = 0; // Set Timer1 to Normal mode
TCCR1B = (1 << CS12) | (1 << CS10); // Set prescaler to 1024
TCNT1 = 0; // Initialize Timer1 counter to 0

// Enable Timer1 overflow interrupt


TIMSK1 = (1 << TOIE1);

// Enable global interrupts


sei();
}
ISR(TIMER1_OVF_vect) { // Timer1 overflow interrupt service routine
digitalWrite(ledPin, !digitalRead(ledPin)); // Toggle LED
TCNT1 = 0; // Reset Timer1 counter for precise timing
}

void loop() {
// Main code can run here (if any), but the LED toggling is handled by the interrupt
}

### 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:

\[
f = \frac{{\text{clock speed}}}{{\text{prescaler} \times (ICR1 + 1)}}
\]

2.

#### Code to Generate PWM Signal

cpp
void setup() {
// Set pin 10 as output
pinMode(10, OUTPUT);

// Set Timer1 to Fast PWM Mode 14 with ICR1 as TOP


TCCR1A = (1 << COM1B1) | (1 << WGM11); // Non-inverting mode on OC1B (pin 10)
TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS12) | (1 << CS10); // Prescaler 1024

// Set the top value for 1 Hz frequency


ICR1 = 15624; // ICR1 = (16,000,000 / (1024 * 1)) - 1

// Set OCR1B for 60% duty cycle


OCR1B = (60 * (ICR1 + 1)) / 100; // 60% of 15624
}
void loop() {
// Nothing in the loop, PWM signal is handled by Timer1
}

8(a)
8(c) // Define the pins for the UP and DOWN buttons
const int upButtonPin = 10; // UP button connected to digital pin 10
const int downButtonPin = 11; // DOWN button connected to digital pin 11

// Define the pins for the 7-segment display segments (common cathode configuration)
const int segmentPins[] = {2, 3, 4, 5, 6, 7, 8}; // Pins for segments a to g
const int dpPin = 9; // Decimal point pin

// 7-segment display digit patterns for numbers 0-9


const byte digits[10] = {
0b00111111, // 0
0b00000110, // 1
0b01011011, // 2
0b01001111, // 3
0b01100110, // 4
0b01101101, // 5
0b01111101, // 6
0b00000111, // 7
0b01111111, // 8
0b01101111 // 9
};

// Variable to store the current counter value


int counter = 0;

// Variables to handle button states and debounce


bool upButtonPressed = false;
bool downButtonPressed = false;

void setup() {
// Initialize the segment pins as outputs
for (int i = 0; i < 7; i++) {
pinMode(segmentPins[i], OUTPUT);
}
pinMode(dpPin, OUTPUT);

// Initialize the button pins as inputs with internal pull-down resistors


pinMode(upButtonPin, INPUT);
pinMode(downButtonPin, INPUT);
// Set the initial display
displayDigit(counter);
}

void loop() {
// Read the state of the UP and DOWN buttons
bool upState = digitalRead(upButtonPin);
bool downState = digitalRead(downButtonPin);

// Check if the UP button is pressed


if (upState && !upButtonPressed) {
upButtonPressed = true; // Record that the button was pressed
counter++; // Increment the counter
if (counter > 9) counter = 0; // Wrap around to 0 if counter exceeds 9
displayDigit(counter); // Update the 7-segment display
} else if (!upState) {
upButtonPressed = false; // Reset the button state if not pressed
}

// Check if the DOWN button is pressed


if (downState && !downButtonPressed) {
downButtonPressed = true; // Record that the button was pressed
counter--; // Decrement the counter
if (counter < 0) counter = 9; // Wrap around to 9 if counter goes below 0
displayDigit(counter); // Update the 7-segment display
} else if (!downState) {
downButtonPressed = false; // Reset the button state if not pressed
}
}

// Function to display a digit on the 7-segment display


void displayDigit(int num) {
byte segments = digits[num]; // Get the segment pattern for the number

// Set each segment based on the pattern


for (int i = 0; i < 7; i++) {
digitalWrite(segmentPins[i], (segments >> i) & 0x01);
}
}
Spring 22
### *Question 2:*

#### 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.

Sample Arduino code:


cpp
const int pump1Pin = 8; // Pump-1 control pin
const int khPin = 7; // High-Level Switch KH pin
unsigned long startTime;
bool isRunning = false;

void setup() {
pinMode(pump1Pin, OUTPUT);
pinMode(khPin, INPUT);
startTime = millis(); // Start timer
isRunning = true;
}

void loop() {
if (isRunning) {
// Stop pump after 30 minutes or if KH is activated
if ((millis() - startTime >= 1800000) || digitalRead(khPin) == HIGH) {
digitalWrite(pump1Pin, LOW); // Stop Pump-1
isRunning = false;
} else {
digitalWrite(pump1Pin, HIGH); // Keep Pump-1 running
}
}
}

Part (b)
### *Question 3:*

---

### Part (c): I2C Communication between Master and Slave for Sending a Float Value
### Master Code (Arduino)

cpp
#include <Wire.h>

const int slaveAddress = 0x13; // I2C address of the slave

void setup() {
Serial.begin(9600); // Start Serial communication for SM1
Wire.begin(); // Join the I2C bus as Master
}

void loop() {
Wire.requestFrom(slaveAddress, 4); // Request 4 bytes from the slave

byte receivedBytes[4];
int index = 0;

// Receive the 4 bytes from the slave


while (Wire.available() && index < 4) {
receivedBytes[index++] = Wire.read();
}

// Convert received bytes back to a float


float current;
memcpy(&current, receivedBytes, sizeof(float));
// Print the current to the Serial Monitor
Serial.print("Current (I): ");
Serial.println(current);

delay(1000); // Wait 1 second before requesting again


}

### Slave Code (Arduino)

cpp
#include <Wire.h>

float I = 1.23; // Example current value

void setup() {
Wire.begin(0x13); // Join the I2C bus as Slave with address 0x13
Wire.onRequest(requestEvent); // Register event for Master requests
}

void loop() {
// The loop can contain code to update `I` as required
// For simplicity, we're keeping I constant
}
// This function is called when the Master requests data
void requestEvent() {
byte floatBytes[4];
memcpy(floatBytes, &I, sizeof(float)); // Convert float I to 4 bytes

// Send each byte to the Master


for (int i = 0; i < 4; i++) {
Wire.write(floatBytes[i]);
}
}

#### *4a)
cpp
#include <SPI.h>

volatile bool transferComplete = false;

void setup() {
SPI.begin(); // Initialize SPI as Master
SPCR |= _BV(SPIE); // Enable SPI interrupt
SPI.attachInterrupt(); // Attach interrupt
}

ISR(SPI_STC_vect) {
transferComplete = true; // Flag when transfer is complete
}

void loop() {
byte dataToSend = 0x7D; // Data to send to Slave
SPDR = dataToSend; // Start transmission by writing to SPDR

// Wait for transfer to complete


while (!transferComplete);
transferComplete = false;

byte receivedData = SPDR; // Read data received from Slave (should be 0x6E)
// Process received data as needed
delay(1000); // Delay before next transmission
}
*Sample Arduino Code for SPI Slave (receiving 0x7D and sending 0x6E):*
cpp
#include <SPI.h>

volatile bool dataReceived = false;

void setup() {
pinMode(MISO, OUTPUT); // Set MISO as output for Slave mode
SPCR |= _BV(SPE); // Enable SPI in Slave mode
SPCR |= _BV(SPIE); // Enable SPI interrupt
}

ISR(SPI_STC_vect) {
dataReceived = true;
}

void loop() {
byte dataToSend = 0x6E; // Data to send back to Master
SPDR = dataToSend; // Load data into SPDR to send

// Wait until data is received


while (!dataReceived);
dataReceived = false;

byte receivedData = SPDR; // Read data received from Master (should be 0x7D)
// Process received data as needed
}

---

#### *4b)
*Sample Arduino Code:*
cpp
const int led1 = 8; // LED-1 on Dpin-8
const int led2 = 9; // LED-2 on Dpin-9
volatile bool interruptFlag = false;

void setup() {
pinMode(led1, OUTPUT);
pinMode(led2, OUTPUT);
attachInterrupt(digitalPinToInterrupt(2), handleInterrupt, RISING); // Set up IRQ1 interrupt on
Dpin-2
}

void loop() {
if (!interruptFlag) {
digitalWrite(led2, HIGH); // Blink LED-2
delay(1000);
digitalWrite(led2, LOW);
delay(1000);
}
}

void handleInterrupt() {
interruptFlag = true; // Set interrupt flag to stop LED-2 blinking
for (int i = 0; i < 5; i++) { // Blink LED-1 5 times with 2s interval
digitalWrite(led1, HIGH);
delay(2000);
digitalWrite(led1, LOW);
delay(2000);
}
interruptFlag = false; // Clear interrupt flag, resume LED-2 blinking
}
### Question 5

#### Part (a): Fast PWM Frequency Calculation

To compute the frequency of the Fast PWM:

1. *Equation for PWM Frequency*:


\[
f_{PWM} = \frac{f_{clk}}{N \times (1 + TOP)}
\]
where:
- \( f_{clk} \) is the clock frequency,
- \( N \) is the prescaler,
- \( TOP \) is the maximum count value (determined by ICR1 in this case for mode 14).

2. *Changing Frequency and Duty Cycle*:


- Adjust \( ICR1 \) to set the top value, which changes the frequency.
- Adjust the value in OCR1A or OCR1B to modify the duty cycle.

---

#### Part (b): Servo Control with ASCII Commands

To control an SG-90 Servo through Bluetooth:

1. *Setup Bluetooth Communication*: Use SoftwareSerial on pins 10 and 11 for Bluetooth


communication.
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>

SoftwareSerial mySerial(10, 11); // RX, TX


Servo servo;

void setup() {
mySerial.begin(9600);
servo.attach(5); // Servo on DPin-5
}

void loop() {
if (mySerial.available() > 0) {
int angle = mySerial.parseInt();
if (angle >= 0 && angle <= 180) {
servo.write(angle);
}
}
}

---

#### Part (c): SPI Connection for BMP280 Sensor

1. *Connect BMP280 via SPI*: Use MOSI, MISO, SCK, and CS lines.
2. *Use a Level Shifter*: Connect 5V from Arduino to 3.3V for BMP280.

SPI Connection Example:


- *Arduino* ↔ *BMP280*
- MOSI (D11) ↔ SDI
- MISO (D12) ↔ SDO
- SCK (D13) ↔ SCK
- CS (D10) ↔ CSB (chip select)

---

### 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
// Define a class for Rectangle
class Rectangle {
private:
float length;
float width;

public:
// Constructor to initialize the length and width
Rectangle(float l, float w) {
length = l;
width = w;
}

// Method to calculate the area


float calculateArea() {
return length * width;
}
};

void setup() {
// Start Serial communication
Serial.begin(9600);

// Create a Rectangle object with length=25 cm and width=15 cm


Rectangle myRectangle(25.0, 15.0);
// Calculate and print the area
float area = myRectangle.calculateArea();
Serial.print("The area of the rectangle is: ");
Serial.print(area);
Serial.println(" cm^2");
}

void loop() {
// Nothing needed in loop
}

### Question 7

#### Part (a): LED Control through Serial

Use Serial input to turn on/off an LED.


Example code:
cpp
const int ledPin = 13;

void setup() {
pinMode(ledPin, OUTPUT);
Serial.begin(9600);
}

void loop() {
if (Serial.available() > 0) {
String command = Serial.readString();
if (command == "Turn ON L") {
digitalWrite(ledPin, HIGH);
} else if (command == "Turn OFF L") {
digitalWrite(ledPin, LOW);
}
}
}

#### Part (b): Background Tasks for analogRead(A1)

1. The ADC reads the voltage on pin A1.


2. Converts the analog signal to a digital value (10-bit resolution by default on Arduino).
#### Part (c): Float to Byte Array using Union

Convert a float to a 4-byte array and send it over I2C.

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

#### Part (a): Temperature Control for PWM

1. *Read Temperature*: Use DS18B20 to get temperature.


2. *Set PWM Output*:
- If temperature < 15°C, PWM on Dpin-5.
- Else, PWM on Dpin-10.

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();
float tempC = sensors.getTempCByIndex(0);

if (tempC < 15) {


analogWrite(PWM_PIN_LOW, 128); // 50% duty cycle
analogWrite(PWM_PIN_HIGH, 0);
} else {
analogWrite(PWM_PIN_LOW, 0);
analogWrite(PWM_PIN_HIGH, 128); // 50% duty cycle
}
delay(1000);
}
#### Part (b): INT0 Conditions

For the INT0 flag to generate an interrupt:


- The interrupt must be enabled.
- A rising, falling, or low-level condition should trigger the interrupt, as per the configuration.

You might also like