Course: CCIT4064 Microcontrollers (MCU) | Assignment: 2
Instruction set: Intel MCS-51 (Assembly) / Arduino Sketch (C/C++) unless otherwise stated


Section A – Multiple Choice (10 Marks)

Q1 — Bitwise AND Result in Accumulator

MOV A, #55H
AND A, #0FH       ; note: in MCS-51, this instruction is written ANL A, #0FH

Step-by-step:

Binary Hex
A 0101 0101 55H
Mask 0000 1111 0FH
AND result 0000 0101 05H

Bitwise AND keeps only the bits where both operands have a 1. The mask 0FH zeros out the upper nibble and passes through the lower nibble.

Answer: A) 05H


Q2 — EA Pin and External ROM

The EA (External Access) pin controls whether the CPU starts fetching from internal or external program memory.

EA state CPU Behaviour
EA = HIGH Fetch from internal ROM first (0000H–0FFFH for 4 KB), then switch to external ROM for addresses ≥ 1000H
EA = LOW Fetch all code from external ROM, bypassing internal ROM entirely

With a 6 KB firmware image on a classic 8051 (4 KB internal): - EA = HIGH → first 4 KB from internal, remaining 2 KB from external ROM - EA = LOW → all 6 KB fetched from external ROM

Answer: B)
With EA = HIGH, the CPU fetches the first 4 KB from internal ROM and the remaining 2 KB from external; with EA = LOW, the CPU fetches all 6 KB from external.


Q3 — Infinite Loop with DJNZ?

LOOP: MOV R0, #01H    ; R0 = 1
      DJNZ R0, LOOP   ; R0-- → R0 = 0; since R0 = 0, do NOT jump

DJNZ decrements first, then checks. Starting from R0 = 1: - After decrement: R0 = 0 → condition is false → no jump

The loop body executes exactly once and falls through.

Answer: B) No


Q4 — What is Directly Executed by CPU Hardware?

Language Requires Translation?
C Compiled to machine code
Assembly Assembled (translated) to machine code
Machine Code Executed directly by CPU
Java Compiled to bytecode; interpreted or JIT-compiled

The CPU's hardware decode unit understands only binary machine code (opcodes + operands). All other languages must be translated before execution.

Answer: C) Machine code


Q5 — Indirect Addressing Mode in MCS-51

Instruction Addressing Mode
MOV A, 30H Direct — uses the value at memory address 30H
MOV A, #30H Immediate — uses the literal value 30H
MOV A, @R1 Indirect — R1 holds the address; fetches from that address
MOV A, R1 Register — uses the value in register R1 directly

The @ symbol denotes indirect (pointer-based) addressing.

Answer: C) MOV A, @R1


Q6 — Number of Machine Cycles for the Nested Loop

BACK: MOV R6, #200    ; 1 MC — resets R6 to 200 every iteration!
      MOV R5, #200    ; 1 MC
HERE: DJNZ R5, HERE   ; 2 MC each
      DJNZ R6, BACK   ; 2 MC each
      END

Key observation: The label BACK is placed before MOV R6, #200. Each time DJNZ R6, BACK jumps, it resets R6 back to 200 before decrementing it on the next pass. R6 never actually counts down to zero — it is perpetually reloaded to 200.

This creates a truly infinite loop.

Answer: D) Infinite


Q7 — Limitations of YG1006 in Industrial Flame Detection

Evaluating each statement against the principles of professional flame detection:

Statement Analysis Valid?
I — Industrial detectors rely on narrow-band spectral discrimination (e.g., CO₂ emission at ~4.4 µm) TRUE — professional systems target specific combustion wavelengths
II — Temporal pattern analysis distinguishes flames from steady IR sources TRUE — flames flicker at characteristic frequencies; hot objects do not
III — Multi-sensor fusion improves immunity to environmental interference TRUE — combining UV, IR, and other sensors reduces false alarms
IV — YG1006's primary limitation is insufficient IR sensitivity FALSE — YG1006 is sensitive to IR; the limitation is its broadband response (no spectral discrimination), not sensitivity

Statements I, II, and III are all valid reasons; Statement IV is incorrect.

Answer: B) I, II and III only


Q8 — Arduino UNO Q LPDDR4 Memory Device

Hint from question: Refer to https://docs.arduino.cc/hardware/uno-q/

Based on the Arduino UNO Q hardware documentation and reference design, the board uses a Micron LPDDR4 device.

Answer: B) Model: MT53E512M32D1; Package: 200-ball TFBGA

(Verify against the official schematic/BOM at the Arduino documentation page if needed.)


Q9 — Which MCU Executes MCS-51 Code Fastest?

The effective machine cycle rate = Clock Frequency ÷ Clocks per Machine Cycle:

Option Clock Clocks/MC Machine Cycles per Second
A — Intel 8051 12.0 MHz 12 1,000,000 MC/s
B — Company B 6.0 MHz 6 1,000,000 MC/s
C — Company C 8.0 MHz 4 2,000,000 MC/s
D — Company D 24.0 MHz 1 24,000,000 MC/s

Company D's MCU executes 24 million machine cycles per second — 24× faster than options A and B, and 12× faster than option C.

Answer: D) Company D's 8051-variant MCU running at 24.0000 MHz (1 clock per machine cycle)


Q10 — Which Ports Form the 16-bit Address Bus?

In the Intel 8051:

Port Function
P0 Lower address byte A0–A7 (multiplexed with data bus D0–D7)
P1 General-purpose I/O
P2 Upper address byte A8–A15
P3 Special functions (serial, interrupts, timers)

The 16-bit address bus is formed by P0 (low byte) and P2 (high byte). None of the options A–C list this correct pair.

Answer: D) None of the above
(The correct answer is P0 and P2, which is not listed.)


Section A Answer Key

Q1 Q2 Q3 Q4 Q5 Q6 Q7 Q8 Q9 Q10
A B B C C D B B D D

Section B – Short Questions (30 Marks)


B1 — Modern MCS-51 vs. Traditional 8051 Performance

(a) Slowest Instructions in Traditional MCS-51 and Their Clock Cycles (1 Mark)

The slowest instructions in the standard MCS-51 instruction set are:

  • MUL AB (Multiply Accumulator by B)
  • DIV AB (Divide Accumulator by B)

Both require 4 machine cycles.

On a traditional MCS-51, one machine cycle = 12 oscillator (clock) periods.

Clock cycles required: 4 × 12 = 48 oscillator periods (clock cycles)


(b) Execution Time on Traditional MCS-51 at 30 MHz (2 Marks)

$$t = \frac{\text{Clock cycles}}{\text{Frequency}} = \frac{48}{30{,}000{,}000 \text{ Hz}} = 1.6 \, \mu\text{s}$$

Execution time = 1.6 µs


(c) Clock Cycles on EFM8UB1 (CIP-51 Core) with Prefetch ON (1 Mark)

The CIP-51 core used in the EFM8UB1 is a pipelined, enhanced 8051-compatible core. Unlike the traditional 8051 (which requires 12 clocks per machine cycle), CIP-51 executes most instructions in 1–2 system clock cycles.

According to the EFM8UB1 Reference Manual, with Prefetch Engine ON, MUL AB and DIV AB execute in:

4 system clock cycles (compared to 48 on the traditional 8051)


(d) Execution Time on EFM8UB1 at 30 MHz (2 Marks)

$$t = \frac{4}{30{,}000{,}000 \text{ Hz}} = 0.133 \, \mu\text{s} \approx 133 \, \text{ns}$$

Execution time = ~133 ns


(e) Minimum Performance Improvement Factor at 30 MHz (1 Mark)

$$\text{Improvement} = \frac{t_{\text{traditional}}}{t_{\text{EFM8UB1}}} = \frac{1.6\,\mu\text{s}}{0.133\,\mu\text{s}} = \frac{48 \text{ clocks}}{4 \text{ clocks}} = 12\times$$

EFM8UB1 is at least 12× faster than the traditional MCS-51 for the same instruction at the same clock frequency.


B2 — 8051 Assembly Program (4 Marks)

Task recap: - (a) Load A with 80H - (b) Load R0 with 64H (labelled Q1Lable) - (c) Multiply A by 128; result: high byte → B, low byte → A - (d) Add R0 to A - (e) Move A to low byte of DPTR (DPL, address 82H) - (f) Move B to high byte of DPTR (DPH, address 83H)

Remark: Per the problem statement, all SFR accesses (except A/ACC) must use direct hex addresses.
SFR addresses: B = 0F0H, DPL = 82H, DPH = 83H

        ORG  0000H
        MOV  A, #80H          ; (a) A = 80H (= 128 decimal)
Q1Lable:MOV R0, #64H          ; (b) R0 = 64H (= 100 decimal)
        MOV  0F0H, #80H       ; Load B (SFR 0F0H) with 80H (= 128) for MUL
        MUL  AB               ; (c) A × B = 80H × 80H = 4000H; B=40H, A=00H
        ADD  A, R0            ; (d) A = 00H + 64H = 64H
        MOV  82H, A           ; (e) DPL (82H) = A = 64H
        MOV  83H, 0F0H        ; (f) DPH (83H) = B (0F0H) = 40H
        END

Step-by-step trace:

Step Instruction Result
(a) MOV A, #80H A = 80H (128)
(b) MOV R0, #64H R0 = 64H (100)
Pre-MUL MOV 0F0H, #80H B = 80H (128)
(c) MUL AB 128 × 128 = 16384 = 4000H → B = 40H, A = 00H
(d) ADD A, R0 A = 00H + 64H = 64H
(e) MOV 82H, A DPL = 64H
(f) MOV 83H, 0F0H DPH = 40H

Total: 9 lines (including ORG and END) — within the 10-line limit.


B3 — Address Indicated by DPTR (2 Marks)

From the trace in B2:

Register Value
DPH (high byte) 40H
DPL (low byte) 64H

$$\text{DPTR} = \text{DPH} \times 256 + \text{DPL} = 0x40 \times 256 + 0x64 = 16384 + 100 = 16484$$

DPTR = 4064H (hexadecimal) = 16484 (decimal)

Derivation: - A = 80H = 128 - B = 80H = 128 (loaded before MUL) - MUL AB: 128 × 128 = 16384 = 4000H → B = 40H, A = 00H - ADD A, R0: 00H + 64H = 64H - DPH = 40H, DPL = 64HDPTR = 4064H


B4 — ADDB Subroutine: B ← B + R0 (5 Marks)

Requirements: - Add R0 to B; store result in B - Preserve original A (ACC) and PSW - Start at address 0100H - Use RAM addresses 30H and 31H for temporary storage - Must be within 10 lines

        ORG  0100H
ADDB:   MOV  30H, A      ; Save original A to temp storage at 30H
        MOV  31H, PSW    ; Save original PSW (flags) to temp at 31H
        MOV  A, B        ; Load B into A (so we can use ADD instruction)
        ADD  A, R0       ; A = B + R0 (result of the addition)
        MOV  B, A        ; Store result back into B
        MOV  PSW, 31H    ; Restore original PSW (preserves all flags)
        MOV  A, 30H      ; Restore original A
        RET              ; Return from subroutine
        END

Explanation of each line:

Line Instruction Purpose
1 ORG 0100H Locate subroutine at address 0100H
2 MOV 30H, A Back up accumulator — we need A for arithmetic
3 MOV 31H, PSW Back up all flags (CY, AC, OV, P, RS0, RS1)
4 MOV A, B Copy B into A — ADD only operates on accumulator
5 ADD A, R0 Perform B + R0, result in A (this modifies flags)
6 MOV B, A Write the result back to B
7 MOV PSW, 31H Restore original PSW — undoes flag changes from ADD
8 MOV A, 30H Restore original accumulator
9 RET Return to caller

Total: 9 lines (including ORG and END) — within the 10-line limit.

Key design decision: The PSW is restored after writing to B but before restoring A. This ensures the ADD result is safely stored in B before any register/flag state changes are reversed. The caller sees B updated but A and all flags unchanged.


B5 — Addition of AAH + 88H with Flag Analysis (4 Marks)

Instructions:

MOV A, #AAH
ADD A, #88H

Step 1 — Convert to Binary

  AAH = 1010 1010
+ 88H = 1000 1000

Step 2 — Perform Binary Addition (bit by bit with carries)

Carry:  1  1  0  0  1  0  0  0  0
        ─  ─  ─  ─  ─  ─  ─  ─  ─
        1  0  1  0  1  0  1  0    ← AAH
     +  1  0  0  0  1  0  0  0    ← 88H
        ─────────────────────────
 CY→1   0  0  1  1  0  0  1  0    ← Result = 32H

Lower nibble (bits 3–0):

  1010  (A, lower nibble)
+ 1000  (8, lower nibble)
──────
 10010  → lower nibble result = 0010, carry-out (AC) = 1

Upper nibble (bits 7–4) with carry-in = 1:

  1010  (A, upper nibble)
+ 1000  (8, upper nibble)
+ 0001  (carry-in from lower nibble)
──────
 10011  → upper nibble result = 0011, carry-out (CY) = 1

Step 3 — Result

Binary Hex
Full result 0011 0010 32H
Verification 170 + 136 = 306 = 256 + 50 → overflow with remainder 50 = 32H

Step 4 — Flag Status

Flag Name Condition Value
CY Carry Carry out of bit 7 1 (carry occurred)
AC Auxiliary Carry Carry out of bit 3 into bit 4 1 (carry from lower to upper nibble)
P Parity Even/Odd count of 1s in result Count 1s in 0011 0010: bits 1, 4, 5 = 3 ones → odd → P = 1

Summary

Result (Binary) Result (Hex) CY AC P
0011 0010 32H 1 1 1

B6 — Arduino LED Brightness Control (8 Marks total)

(a) Simplified Schematic Diagram (3 Marks)

Arduino UNO R3
┌──────────────────────────────┐
│                              │
│  5V ──────────────┐          │
│                   │          │
│               [POT 10kΩ]     │
│              ┌────┤ wiper    │
│              │    └──────────┼──── GND
│              │               │
│  A0 ─────────┘ (analog in)  │
│                              │
│  Pin 9 (PWM) ──[220Ω]──┤►├──┼──── GND
│              resistor    LED │
│                              │
└──────────────────────────────┘

Wiring connections:

Component Connection
Potentiometer — left terminal Arduino 5V
Potentiometer — right terminal Arduino GND
Potentiometer — wiper (middle) Arduino A0 (analog input)
LED — anode (+) Arduino Pin 9 (PWM) via 220 Ω resistor
LED — cathode (−) Arduino GND

Why Pin 9? The LED brightness is controlled via PWM (Pulse Width Modulation) using analogWrite(). On the UNO R3, PWM-capable pins are: 3, 5, 6, 9, 10, 11. Pin 9 is a common choice.

Why a resistor? The current-limiting resistor (220 Ω typical) prevents excessive current from damaging the LED. With 5 V and a ~2 V LED forward voltage:
$$I = \frac{5V - 2V}{220\,\Omega} \approx 13.6\,\text{mA}$$


(b) Complete Arduino Sketch (5 Marks)

const int POT_PIN = A0;   // Potentiometer connected to analog pin A0
const int LED_PIN = 9;    // LED connected to PWM-capable pin 9

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

void loop() {
  // --- Analog Input Reading ---
  int analogValue = analogRead(POT_PIN);   // 0 to 1023

  // --- Level Conversion ---
  int level;
  if (analogValue <= 200) {
    level = 0;
  } else if (analogValue <= 400) {
    level = 1;
  } else if (analogValue <= 600) {
    level = 2;
  } else if (analogValue <= 800) {
    level = 3;
  } else {
    level = 4;
  }

  // --- Serial Monitor Output ---
  Serial.print("Analog Input: ");
  Serial.print(analogValue);
  Serial.print("; Level: ");
  Serial.println(level);

  // --- LED Brightness Control via PWM ---
  // analogWrite range: 0 (off) to 255 (full brightness)
  int pwmValue;
  switch (level) {
    case 0: pwmValue = 0;   break;  // OFF
    case 1: pwmValue = 64;  break;  // ~1/4 intensity  (64/255 ≈ 25%)
    case 2: pwmValue = 128; break;  // ~1/2 intensity  (128/255 ≈ 50%)
    case 3: pwmValue = 191; break;  // ~3/4 intensity  (191/255 ≈ 75%)
    case 4: pwmValue = 255; break;  // Full intensity  (255/255 = 100%)
    default: pwmValue = 0;  break;
  }
  analogWrite(LED_PIN, pwmValue);

  delay(100);   // Small delay to avoid flooding Serial Monitor
}

Key concepts explained:

Concept Explanation
analogRead() Reads 10-bit ADC value (0–1023) proportional to voltage at A0 (0–5 V)
analogWrite() Outputs 8-bit PWM signal (0–255); duty cycle controls perceived LED brightness
Level mapping Five discrete levels map the 1024-step ADC range into rough quarters
PWM values 0 = 0%, 64 ≈ 25%, 128 ≈ 50%, 191 ≈ 75%, 255 = 100% duty cycle
Serial.begin(9600) Initialises UART at 9600 baud for Serial Monitor output

Level-to-PWM mapping table:

Level Analog Input Range PWM Value LED Brightness
0 0 – 200 0 OFF
1 201 – 400 64 1/4 (≈ 25%)
2 401 – 600 128 1/2 (≈ 50%)
3 601 – 800 191 3/4 (≈ 75%)
4 801 – 1023 255 Full (100%)

Quick Reference: Key 8051 Facts

Topic Value
Machine cycle (traditional 8051) 12 clock periods
Longest instructions (MUL, DIV) 4 machine cycles = 48 clock periods
Internal RAM 128 bytes (00H–7FH)
SFR space 80H–FFH
B register SFR address F0H
PSW SFR address D0H
DPL (DPTR low) SFR address 82H
DPH (DPTR high) SFR address 83H
PWM pins on Arduino UNO R3 3, 5, 6, 9, 10, 11
analogRead() range 0–1023 (10-bit ADC)
analogWrite() range 0–255 (8-bit PWM)