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 = 64H → DPTR = 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) |