GuideEmbedded SystemsPeripherals and Interfaces

Interfacing with Peripherals

A comprehensive guide to interfacing with various peripherals in embedded systems, including sensors, displays, and communication interfaces.

Interfacing with Peripherals

Interfacing with peripherals is a crucial aspect of embedded systems development. This guide covers common peripherals, communication protocols, and best practices for hardware interfacing.

Common Peripherals

Input Devices

Buttons and Switches

  • Types: Push buttons, toggle switches, rotary encoders
  • Interfacing: Digital input with pull-up/pull-down resistors
  • Debouncing: Software or hardware techniques to handle switch bounce

Example Button Interface:

// Button with pull-up resistor
#define BUTTON_PIN PB0
#define BUTTON_PORT PORTB
#define BUTTON_DDR DDRB
 
void button_init() {
    // Set button pin as input with pull-up
    BUTTON_DDR &= ~(1 << BUTTON_PIN);
    BUTTON_PORT |= (1 << BUTTON_PIN);
}
 
bool button_pressed() {
    // Return true if button is pressed (LOW due to pull-up)
    return !(BUTTON_PORT & (1 << BUTTON_PIN));
}

Sensors

  • Analog Sensors: Temperature, light, pressure
  • Digital Sensors: Accelerometers, gyroscopes, GPS
  • Interfacing Methods: ADC, I2C, SPI, UART

Example Temperature Sensor (LM35) Interface:

// ADC initialization for temperature sensor
void adc_init() {
    // Set reference voltage to AVCC and select ADC0
    ADMUX = (1 << REFS0);
    
    // Enable ADC and set prescaler
    ADCSRA = (1 << ADEN) | (1 << ADPS2) | (1 << ADPS1);
}
 
// Read temperature in Celsius
float read_temperature() {
    // Start conversion
    ADCSRA |= (1 << ADSC);
    
    // Wait for conversion to complete
    while (ADCSRA & (1 << ADSC));
    
    // Convert ADC value to temperature (LM35: 10mV/°C)
    return (ADC * 5.0 / 1024.0) * 100.0;
}

Output Devices

LEDs

  • Types: Single-color, RGB, 7-segment displays
  • Interfacing: Digital output, PWM for brightness control
  • Current Limiting: Series resistors or constant current drivers

Example LED Control:

// LED with PWM control
#define LED_PIN PB1
#define LED_PORT PORTB
#define LED_DDR DDRB
 
void led_init() {
    // Set LED pin as output
    LED_DDR |= (1 << LED_PIN);
    
    // Configure PWM
    // (PWM configuration code would go here)
}
 
void set_brightness(uint8_t brightness) {
    // Set PWM duty cycle
    OCR1A = brightness;
}

Displays

  • Types: LCD, OLED, e-ink
  • Interfacing: Parallel, I2C, SPI
  • Graphics Libraries: Often provided by manufacturer

Example OLED Display (SSD1306) Interface:

// I2C initialization for OLED display
void oled_init() {
    // Initialize I2C
    // (I2C initialization code would go here)
    
    // Initialize display
    // (Display initialization commands would go here)
}
 
void oled_clear() {
    // Clear display buffer
    // (Clear display commands would go here)
}
 
void oled_draw_text(const char* text) {
    // Draw text on display
    // (Text drawing commands would go here)
}

Communication Protocols

I2C (Inter-Integrated Circuit)

  • Features: Two-wire interface, multiple devices
  • Speed: Standard (100 kHz), Fast (400 kHz), Fast Plus (1 MHz)
  • Applications: Sensors, EEPROM, RTC

Example I2C Communication:

// I2C initialization
void i2c_init() {
    // Set clock frequency
    TWBR = 72; // 100kHz with 8MHz clock
    
    // Enable I2C
    TWCR = (1 << TWEN);
}
 
// Write data to I2C device
void i2c_write(uint8_t device_addr, uint8_t reg_addr, uint8_t data) {
    // Start condition
    TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN);
    while (!(TWCR & (1 << TWINT)));
    
    // Send device address
    TWDR = device_addr << 1;
    TWCR = (1 << TWINT) | (1 << TWEN);
    while (!(TWCR & (1 << TWINT)));
    
    // Send register address
    TWDR = reg_addr;
    TWCR = (1 << TWINT) | (1 << TWEN);
    while (!(TWCR & (1 << TWINT)));
    
    // Send data
    TWDR = data;
    TWCR = (1 << TWINT) | (1 << TWEN);
    while (!(TWCR & (1 << TWINT)));
    
    // Stop condition
    TWCR = (1 << TWINT) | (1 << TWSTO) | (1 << TWEN);
}

SPI (Serial Peripheral Interface)

  • Features: Full-duplex, high-speed, simple protocol
  • Signals: MOSI, MISO, SCK, CS
  • Applications: Flash memory, ADCs, DACs

Example SPI Communication:

// SPI initialization
void spi_init() {
    // Set MOSI, SCK as output
    DDRB |= (1 << MOSI) | (1 << SCK);
    
    // Enable SPI, Master mode, clock rate fck/16
    SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR0);
}
 
// Send and receive data via SPI
uint8_t spi_transfer(uint8_t data) {
    // Start transmission
    SPDR = data;
    
    // Wait for transmission complete
    while (!(SPSR & (1 << SPIF)));
    
    // Return received data
    return SPDR;
}

UART (Universal Asynchronous Receiver/Transmitter)

  • Features: Asynchronous, full-duplex
  • Configuration: Baud rate, data bits, stop bits, parity
  • Applications: Debug output, GPS modules, Bluetooth

Example UART Communication:

// UART initialization
void uart_init(uint16_t baud) {
    // Set baud rate
    uint16_t ubrr = F_CPU / 16 / baud - 1;
    UBRR0H = (uint8_t)(ubrr >> 8);
    UBRR0L = (uint8_t)ubrr;
    
    // Enable transmitter and receiver
    UCSR0B = (1 << TXEN0) | (1 << RXEN0);
    
    // Set frame format: 8 data bits, 1 stop bit
    UCSR0C = (1 << UCSZ01) | (1 << UCSZ00);
}
 
// Send character via UART
void uart_send(char data) {
    // Wait for empty transmit buffer
    while (!(UCSR0A & (1 << UDRE0)));
    
    // Put data into buffer
    UDR0 = data;
}
 
// Receive character via UART
char uart_receive() {
    // Wait for data to be received
    while (!(UCSR0A & (1 << RXC0)));
    
    // Get and return received data
    return UDR0;
}

Best Practices for Peripheral Interfacing

1. Hardware Design

  • Use appropriate voltage levels
  • Include protection circuits
  • Consider power requirements
  • Follow manufacturer guidelines

2. Software Design

  • Use modular code structure
  • Implement error handling
  • Document pin assignments
  • Use clear naming conventions

3. Testing and Debugging

  • Use logic analyzers
  • Implement debug output
  • Test with different conditions
  • Verify timing requirements

4. Documentation

  • Document pin connections
  • Specify communication parameters
  • Include timing diagrams
  • Note any special requirements

Example Project: Weather Station

Here's a simple example of a weather station using multiple peripherals:

#include <avr/io.h>
#include <util/delay.h>
 
// Function declarations
void init_peripherals();
float read_temperature();
float read_humidity();
void update_display(float temp, float humidity);
void log_data(float temp, float humidity);
 
int main() {
    // Initialize all peripherals
    init_peripherals();
    
    while (1) {
        // Read sensors
        float temperature = read_temperature();
        float humidity = read_humidity();
        
        // Update display
        update_display(temperature, humidity);
        
        // Log data
        log_data(temperature, humidity);
        
        // Wait before next reading
        _delay_ms(5000);
    }
    
    return 0;
}
 
// Initialize all peripherals
void init_peripherals() {
    // Initialize I2C for sensors
    i2c_init();
    
    // Initialize SPI for display
    spi_init();
    
    // Initialize UART for logging
    uart_init(9600);
    
    // Initialize buttons
    button_init();
}
 
// Read temperature from sensor
float read_temperature() {
    // Read temperature from I2C sensor
    // (Temperature reading code would go here)
    return 25.0; // Placeholder
}
 
// Read humidity from sensor
float read_humidity() {
    // Read humidity from I2C sensor
    // (Humidity reading code would go here)
    return 60.0; // Placeholder
}
 
// Update OLED display
void update_display(float temp, float humidity) {
    // Clear display
    oled_clear();
    
    // Draw temperature
    char temp_str[16];
    sprintf(temp_str, "Temp: %.1f C", temp);
    oled_draw_text(temp_str);
    
    // Draw humidity
    char hum_str[16];
    sprintf(hum_str, "Hum: %.1f %%", humidity);
    oled_draw_text(hum_str);
}
 
// Log data via UART
void log_data(float temp, float humidity) {
    char log_str[32];
    sprintf(log_str, "T:%.1f,H:%.1f\r\n", temp, humidity);
    
    for (int i = 0; log_str[i] != '\0'; i++) {
        uart_send(log_str[i]);
    }
}

Next Steps

Now that you understand peripheral interfacing, you can explore: