UNIT 3: MICROCONTROLLER & EMBEDDED SYSTEM LAB - SHORT NOTES
1.0 ADVANCED DIGITAL I/O & DISPLAY INTERFACING
1.1 Seven-Segment Display Interfacing
-
Common Anode (CA): All anode pins connected to
Vcc. Segment lights with LOW logic. -
Common Cathode (CC): All cathode pins connected to
GND. Segment lights with HIGH logic. -
Multiplexing: Connect segment lines (a-g, dp) in parallel for all displays. Individual display common pins are switched rapidly (≥ 60Hz) by microcontroller via transistors/ drivers. Creates illusion of simultaneous display.
-
Look-Up Table (LUT): Array storing 7-segment codes for digits 0-9 (and A-F). For CA display, store active-LOW codes.
// Example for Common Anode (0 = ON) const uint8_t seg_code[10] = {0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90}; -
Driver ICs (7447): BCD to 7-segment decoder/driver. Sinks current for CA displays. Reduces MCU pin usage.
[!TIP] Key Exam Point: Always verify display type (CA/CC) before writing code. A mismatched LUT will result in inverted or no display.
1.2 Liquid Crystal Display (LCD) Interfacing (16x2)
-
Controller: HD44780 (or compatible).
-
Key Pins:
RS(Register Select: 0=Command, 1=Data),RW(Read/Write: 0=Write),E(Enable pulse),D4-D7(4-bit data bus). -
4-bit vs 8-bit Mode: 4-bit mode uses only D4-D7, saving 4 I/O pins. High nibble sent first, then low nibble.
-
Initialization Sequence (4-bit mode):
-
Wait >15ms after Vcc rise.
-
Send
0x30(8-bit mode) three times with delays. -
Send
0x20(set 4-bit mode). -
Send function set (
0x28for 4-bit, 2-line, 5x8 dots). -
Display control (
0x0Cfor display ON, cursor OFF). -
Clear display (
0x01). -
Entry mode set (
0x06for increment, no shift).
-
-
Busy Flag (BF): Check bit 7 of data bus (when
RS=0,RW=1) before sending command/data. Prevents overrunning LCD controller. -
Custom Characters: Stored in CGRAM (8 characters, 5x8 pixels each). Define byte pattern for each row (5 bytes/char). Address:
0x40 + (char_num * 8).
[!TIP] Common Pitfall: Forgetting the initial delays or not checking busy flag causes erratic LCD behavior. Always use
_delay_ms()or timer-based delays in init.
2.0 ANALOG INTERFACING & SIGNAL CONDITIONING
2.1 ADC Fundamentals
-
Sampling Theorem: Sampling frequency $$\displaystyle f_s $$ must be > 2 × maximum input signal frequency $$\displaystyle f_{max} $$ ($$\displaystyle f_s > 2f_{max} $$) to avoid aliasing.
-
Quantization: Process of mapping continuous analog amplitude to discrete digital levels. Number of levels = $$\displaystyle 2^n $$ (n = resolution in bits).
-
Resolution: Smallest change in analog input that produces a change in digital output.
$$\text{Resolution} = \frac{V_{REF}}{2^n}$$
-
Key Specs:
-
INL (Integral Non-Linearity): Max deviation of actual transfer function from straight line.
-
DNL (Differential Non-Linearity): Max difference between actual step width and ideal (1 LSB).
-
2.2 On-Chip ADC Programming (AVR Example)
-
Key Registers:
-
ADMUX: Reference selection (REFS0/1), ADC channel select (MUX0-4), result adjustment (ADLAR). -
ADCSRA: Enable (ADEN), start conversion (ADSC), auto trigger (ADATE), interrupt enable (ADIE), prescaler (ADPS0-2). -
ADCL/ADCH: 10-bit result (readADCLfirst, thenADCH).
-
-
Modes:
-
Single Conversion: Start conversion, wait for
ADSCto clear or use interrupt. -
Free-Running: Continuous conversions after first start.
-
-
Sensor Interfacing (e.g., LM35): Output = 10mV/°C. Scale to ADC input (0-5V → 0-500°C). Digital value =
(ADC_Value × V_REF) / (2^10). Temperature =(ADC_Value × 500) / 1024. -
Software Techniques:
-
Averaging: Take N samples, sum, divide by N to reduce noise.
-
Calibration: Measure known reference (e.g., 1.1V internal) to correct gain error.
-
[!TIP] Baud Rate Trap: ADC prescaler must yield ADC clock between 50-200kHz for 10-bit accuracy (or 200kHz max for 8-bit). Calculate: $$\displaystyle f_{ADC} = f_{CPU} / \text{prescaler} $$.
2.3 DAC & Waveform Generation
-
R-2R Ladder: Passive resistive network. Output voltage $$\displaystyle V_o = V_{REF} \times \frac{D}{2^n} $$ (D = digital input code).
-
PWM-based DAC: Low-pass filter (RC) smooths PWM to analog. Average voltage $$\displaystyle V_{avg} = D \times V_{CC} $$ (D = duty cycle fraction).
-
Waveform Generation (Look-Up Table): Pre-calculate sample values for one period (e.g., 256 samples for sine). Store in
PROGMEM. Timer triggers sample update at fixed rate (e.g., 1kHz).// Sine LUT (8-bit, 0-255 centered at 128) const uint8_t sine_table[256] PROGMEM = {128, 131, 134, ...};
3.0 TIMER/COUNTER & PWM APPLICATIONS
3.1 Timer/Counter Deep Dive
-
Modes (AVR Timer1 - 16-bit):
-
Normal: Counts up to
TOP=0xFFFF, then overflows. Used for time delays. -
CTC (Clear Timer on Compare): Counts to
OCRxAvalue, resets, setsOCFxAflag. Precise frequency generation. -
Fast PWM: Rapidly toggles output on compare match. High frequency.
-
Phase Correct PWM: Dual-slope PWM. Lower frequency, less harmonic distortion.
-
-
Timer Calculation Formula (Prescaler = N):
$$f_{timer} = \frac{f_{clk}}{N \times (1 + TOP)}$$
For CTC: `TOP = OCRxA`. For frequency $$\displaystyle f_{out} $$:
$$OCR_{xA} = \frac{f_{clk}}{N \times f_{out}} - 1$$
-
Input Capture: Captures timer value on pin edge (e.g., measure pulse width/period).
-
Output Compare: Sets/clears/toggles OC pin on timer compare match. Basis for PWM.
3.2 PWM for Control
-
Theory: Frequency fixed by timer TOP. Duty cycle = $$\displaystyle \frac{OCR}{TOP+1} \times 100\% $$.
-
Programming (Fast PWM, 8-bit):
-
Set
WGM0bits for PWM mode. -
Set
COM0xbits for non-inverting (clear on compare) or inverting. -
Set prescaler (
CS0x). -
Write duty cycle to
OCR0x.
-
-
Applications:
-
LED Dimming: Duty cycle controls average current → brightness.
-
DC Motor Speed: PWM to motor driver (e.g., L293D). Average voltage controls speed.
-
Servo Control: Standard 50Hz (20ms period) PWM. Pulse width 1-2ms sets angle (0°-180°). Use CTC mode for precise pulse.
-
[!TIP] Critical: For servo, use CTC mode to generate 20ms period and adjust OCR for 1-2ms pulse. Fast PWM frequency too high for standard servos.
4.0 SERIAL COMMUNICATION PROTOCOLS
4.1 UART (USART)
-
Frame Format: Start bit (0) + [Data bits (5-9)] + [Parity (None/Even/Odd)] + Stop bit(s) (1 or 2).
-
Baud Rate Calculation (Asynchronous):
$$f_{baud} = \frac{f_{clk}}{8 \times (UBRR + 0.5)} \quad \text{(for double speed off)}$$
$$UBRR = \frac{f_{clk}}{16 \times f_{baud}} - 1$$
*Example:* $$\displaystyle f_{clk}=16MHz $$, $$\displaystyle f_{baud}=9600 $$ → $$\displaystyle UBRR = 103 $$ (error 0.16%).
-
Programming Steps:
-
Set baud rate (
UBRRH/L). -
Enable receiver/transmitter (
RXEN,TXENinUCSRB). -
Set frame format (
UCSRC:UCSZ1:0,UPM1:0,USBS). -
Polling: Wait for
UDREflag empty to writeUDR. Wait forRXCflag to readUDR. -
Interrupt: Enable
RXCIE/TXCIE. ISR reads/writesUDR.
-
-
Loopback Test: Connect
TXDtoRXDpin. Sent data should be received back.
4.2 SPI
-
4-Wire Interface:
MOSI(Master Out Slave In),MISO(Master In Slave Out),SCK(Clock),SS/CS(Slave Select, active LOW). -
Clock Modes (CPOL/CPHA):
| Mode | CPOL (Idle) | CPHA (Edge) | Data Sampled On | | :--- | :--- | :--- | :--- | | 0 | 0 | 0 | Rising | | 1 | 0 | 1 | Falling | | 2 | 1 | 0 | Falling | | 3 | 1 | 1 | Rising |
-
Master Programming:
-
Set
MSTR=1,SSas output. -
Set clock polarity/phase (
CPOL,CPHAinSPCR). -
Set clock frequency (
SPR0,SPR1,SPI2X). -
Enable SPI (
SPE). -
Transfer: Pull
SSLOW, write byte toSPDR, wait forSPIFflag, readSPDR, pullSSHIGH.
-
-
EEPROM (25LC040) Read Sequence:
-
SSLOW. -
Send
READopcode (0x03). -
Send 16-bit address (high byte, then low byte).
-
Read data bytes (clock generates dummy bytes).
-
SSHIGH.
-
4.3 I2C (TWI)
-
2-Wire Bus:
SDA(data),SCL(clock). Both open-drain, require pull-up resistors (~4.7kΩ). -
Key Conditions: START (
SDA↓ whileSCL↑), STOP (SDA↑ whileSCL↑). Data changes onSCLLOW. -
7-bit Addressing: MSB sent first. 8th bit = R/W (1=Read, 0=Write). After address, ACK bit from slave (0 = ACK).
-
Master Transmitter Sequence:
-
Send START.
-
Send
(Slave_Addr << 1) | 0(Write). -
Check for ACK (read
TWINT&TWCR). -
Send data byte.
-
Check ACK.
-
Send STOP.
-
-
Interfacing DS1307 RTC: Slave address
0xD0(write),0xD1(read). Registers 00h-06h for time/date. Write/read BCD values.
[!TIP] I2C Debugging: Always check for ACK after every byte. No ACK → wrong address, device not powered, or wiring error. Use logic analyzer to see START/STOP conditions.
5.0 INTERRUPT SYSTEM & LOW-POWER MODES
5.1 ISR Programming
-
External Interrupts (INT0/INT1): Triggered on edge (
ISC01:0bits) or level. Vector names:INT0_vect,INT1_vect. -
Pin Change Interrupts (PCINT): Any pin change on designated PCINT pin triggers
PCINT0_vect(for PCINT0-7), etc. Must checkPCIFRandPCICRregisters. -
ISR Best Practices:
-
Declare shared variables as
volatile. -
Keep ISR short: Set a flag, read a register, increment a counter.
-
Do not use
printfor long delays inside ISR. -
Disable interrupts (
cli()) when accessing multi-byte shared variables (e.g.,uint16_t count) in main code.
volatile uint8_t flag = 0; ISR(INT0_vect) { flag = 1; // Minimal processing } -
-
Nested Interrupts: Enable global interrupt (
sei()) inside ISR if higher priority interrupt needs to preempt. Default: interrupts disabled inside ISR.
5.2 Watchdog Timer (WDT)
-
Purpose: Reset system if software hangs (fails to "kick" WDT).
-
Sequence: 1. Write logical one to
WDEandWDCEinWDTCSR. 2. Change prescaler (WDP0-2) within 4 cycles. 3. WD starts. -
Kick Pattern:
wdt_reset();inside main loop before timeout expires. -
Timeout: ~16ms to 8s (prescaler dependent).
5.3 Power Saving Modes (AVR)
| Mode | Clocks Stopped | Wake-up Sources |
|---|---|---|
| Idle | CPU | Any interrupt |
| ADC Noise Reduction | CPU, ADC | ADC Complete, External Interrupts |
| Power-down | All clocks | External Interrupts, WDT |
| Standby | All clocks (except async timer) | External Interrupts, TWI address match |
-
Enter Sleep:
set_sleep_mode(SLEEP_MODE_XXX); sleep_enable(); sleep_mode(); sleep_disable(); -
Measurement: Use multimeter on current range. Power-down mode can reduce current to ~100nA.
6.0 SPECIAL FUNCTION REGISTERS (SFR) & MEMORY
6.1 Key SFRs (AVR I/O)
-
PORTx, PINx, DDRx:
PORTxwrites output value / enables pull-up (whenDDRx=0).PINxreads input. Read-Modify-Write Caution:PORTx ^= (1<<PIN);is safe.PORTx = PORTx | (1<<PIN);is safe.PORTx = some_value;can overwrite other bits. -
Timer/Counter:
TCCRxA/B(mode, compare output),TCNTx(counter),OCRxA/B(compare value),TIMSKx(interrupt mask),TIFRx(interrupt flags). -
USART:
UCSRxA/B/C(control/status),UDRx(data buffer). -
SPI:
SPCR(control),SPSR(status),SPDR(data). -
TWI (I2C):
TWCR(control),TWDR(data),TWAR(own address),TWAMR(address mask),TWSR(status).
6.2 Memory Organization
-
Harvard Architecture: Separate program (Flash) and data (SRAM) buses. Allows simultaneous access.
-
Memory Types:
-
Flash (Program): Non-volatile, stores code. Use
PROGMEMfor constant tables. -
SRAM (Data): Volatile, for variables. Initialized variables stored in Flash, copied to SRAM at startup.
-
EEPROM: Non-volatile, byte-addressable. Slower write (3.3ms). Use
EEMEMattribute oreeprom_*functions.
-
-
Using
PROGMEM(AVR-GCC):const uint8_t lookup_table[256] PROGMEM = { ... }; uint8_t val = pgm_read_byte(&lookup_table[index]);
7.0 SYSTEM-LEVEL INTEGRATION & APPLICATION PROJECTS
7.1 Sensor-Based Data Logger
-
Flow: Sensors (LM35 via ADC, DS1307 via I2C) → MCU → Store to EEPROM (I2C/SPI) or SD card (SPI) → UART output to PC.
-
Key Challenges: Timestamping (RTC interrupt or polling), EEPROM wear leveling (circular buffer), SD card FAT file system complexity.
7.2 Embedded Control System (PID Temperature)
-
Closed Loop:
Setpoint(user via buttons) →Error = Setpoint - Measured(LM35/ADC) → PID Algorithm →Control Output(PWM to heater via MOSFET) →Plant(heater) →Process Variable(temperature). -
PID Terms: $$\displaystyle u(t) = K_p e(t) + K_i \int e(t) dt + K_d \frac{de(t)}{dt} $$. Implement discrete form (sample time Ts).
-
Safety: WDT resets on lock-up. Hardware comparator cuts heater if temperature > limit.
7.3 Multi-Peripheral Communication Hub
-
Architecture: Interrupt-driven design.
-
UART RX interrupt → store byte in ring buffer.
-
SPI/I2C interrupts → handle data transfer completion.
-
Timer interrupt → trigger periodic sensor sampling.
-
-
State Machine: Main loop checks flags set by ISRs and executes high-level tasks (e.g.,
if(uart_cmd_ready) parse_command();).
8.0 DEBUGGING, TESTING & BEST PRACTICES
8.1 Hardware Debugging
-
Oscilloscope: Check PWM duty cycle/frequency, UART waveform (start/stop bits), SPI clock/data sync.
-
Logic Analyzer: Decode SPI/I2C/UART protocols automatically. Verify ACK/NACK, address bytes.
-
Multimeter: Measure DC voltages (sensor outputs, rail), check continuity (no shorts), measure current in sleep modes.
8.2 Software Debugging
-
Simulator/Debugger: Step through code, set breakpoints, watch SFR/variable values in real-time.
-
Status LEDs: Toggle LED at start/end of ISR, or in loop to confirm code execution.
-
UART Debug Prints:
printf("ADC=%d\r\n", value);for runtime monitoring. Use ring buffer to avoid blocking.
8.3 Embedded C Best Practices
-
volatile: Mandatory for variables modified in ISR and read in main loop (or vice versa).volatile uint32_t timer_overflow_count; -
Atomic Access: For 16-bit variable on 8-bit MCU:
cli(); uint16_t temp = big_var; sei(); -
Modular Design: Separate peripheral drivers (
lcd.c/h,spi_eeprom.c/h) from application logic. -
Configuration: Use
#defineorconfig.hfor port pins, baud rates, timer constants. Enables portability.
[!TIP] Exam Winner: Always mention
volatilewhen discussing ISR-shared variables. For multi-byte access, explicitly state disable/enable interrupts for atomicity.