MCU Solution
MCU Solution
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.
- *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.
---
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:
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;
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
---
Question 3(a)
Code Explanation:
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
Question 3(b)
Objective: Receive the string "1234" from Serial Monitor, convert it to an integer, and display it.
Code Explanation:
void loop() {
if (Serial.available()) { // Check if data is available to read
char receivedChar = Serial.read(); // Read a character from Serial Monitor
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
void countSlot() {
slotCount++; // Increment slot count whenever the interrupt occurs
}
Question 4(b)
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.
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
}
};
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
This question requires blinking two LEDs at 1-second intervals and displaying the result of 0x23
+ 0x19 on the serial monitor.
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;
5b)
5c)
Answer to question no 6
6a)
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();
void setup() {
Wire.begin(8); // Join I2C bus with address 8
Wire.onReceive(receiveEvent); // Register event
Serial.begin(9600);
}
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.
Answer to question no 7
7a)
#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
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:
2. **Clock Frequency**: The driving clock frequency for TC1 is determined by the system clock
(sysClk) divided by a prescaler (N).
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.
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
#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);
}
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);
}
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
cpp
#include <Wire.h>
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;
### Question 3
*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
}
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
}
void loop() {
Serial.println(receivedData); // Print received data to Serial Monitor
delay(1000); // Wait 1 second before printing again
}
---
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
}
void loop() {
// Main code runs here
}
4c)
*Objective*: Present the connection diagram and code to control an LED's brightness with a
potentiometer.
#### 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);
void loop() {
// Main loop does nothing; waiting for interrupts
}
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>
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...");
if (error == 0) {
Serial.println("Data sent successfully!");
} else {
Serial.print("Error in transmission, error code: ");
Serial.println(error);
}
#include <SPI.h>
void setup() {
// Set MISO as OUTPUT, others as INPUT
pinMode(MISO, OUTPUT);
pinMode(MOSI, INPUT);
pinMode(SCK, INPUT);
pinMode(SS, INPUT);
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
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
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.
cpp
void setup() {
// Set pin 10 as output
pinMode(10, OUTPUT);
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
void setup() {
// Initialize the segment pins as outputs
for (int i = 0; i < 7; i++) {
pinMode(segmentPins[i], OUTPUT);
}
pinMode(dpPin, OUTPUT);
void loop() {
// Read the state of the UP and DOWN buttons
bool upState = digitalRead(upButtonPin);
bool downState = digitalRead(downButtonPin);
#### 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.
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>
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;
cpp
#include <Wire.h>
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
#### *4a)
cpp
#include <SPI.h>
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
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>
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
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
---
Example code:
cpp
#include <SoftwareSerial.h>
#include <Servo.h>
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);
}
}
}
---
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.
---
### 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;
}
void setup() {
// Start Serial communication
Serial.begin(9600);
void loop() {
// Nothing needed in loop
}
### Question 7
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);
}
}
}
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();
float tempC = sensors.getTempCByIndex(0);