Linux外设接口全解析:UART/IIC/SPI/PWM/ADC

Linux 外设通信接口基础概念全解析:UART、IIC、SPI、PWM、ADC 等

Linux 操作系统在嵌入式开发、物联网、智能设备等领域广泛应用。无论是在开发板上调试传感器,还是在工控设备中通信控制,各种外设接口协议如 UART(串口通信)、IIC、SPI、PWM、ADC 等是常见的通信与控制方式。

本文将从基础概念、通信原理、Linux 驱动架构、用户态接口、调试方法、实践示例等角度,深入剖析这些外设接口的工作机制与实际应用。


一、UART(通用异步收发传输器)

1.1 UART 基础概念

UART(Universal Asynchronous Receiver/Transmitter)是一种异步串行通信协议,用于两点之间的数据收发,常见于 GPS 模块、蓝牙模块、串口调试等场景。

  • 异步通信:不依赖时钟线,通过起始位、停止位、校验位实现数据同步。
  • 通常包含 RX(接收)与 TX(发送)两根线。

1.2 通信参数

  • 波特率(Baud rate):如 115200、9600。
  • 数据位(Data bits):通常是 8 位。
  • 校验位(Parity):无(None)、偶校验(Even)、奇校验(Odd)。
  • 停止位(Stop bits):1 或 2。

1.3 Linux 驱动架构

Linux 中 UART 通常由 tty 驱动框架管理:

  • 内核设备节点:/dev/ttySx(传统 UART)或 /dev/ttyUSBx(USB 转串口)等。
  • 底层由 serial_core 框架管理,平台驱动需实现 uart_ops 结构体。

1.4 用户态调试方法

  • 使用 minicomscreencutecom 等工具。
  • 示例:
    sudo apt install minicom
    minicom -D /dev/ttyUSB0 -b 115200
    

1.5 实践示例(C 语言)

int fd = open("/dev/ttyS1", O_RDWR | O_NOCTTY);
struct termios tty;
tcgetattr(fd, &tty);
cfsetospeed(&tty, B115200);
cfsetispeed(&tty, B115200);
tcsetattr(fd, TCSANOW, &tty);
write(fd, "Hello UART\n", 11);

二、IIC(I²C,Inter-Integrated Circuit)

2.1 IIC 基础概念

IIC 是由 Philips 公司开发的多主多从、同步串行通信协议,常用于连接 EEPROM、温湿度传感器等低速设备。

  • 两根线:SCL(时钟)、SDA(数据)
  • 使用 7 位或 10 位地址识别设备。
  • 支持多设备挂载在同一总线上。

2.2 IIC 通信流程

  1. 主机发起 START 信号。
  2. 发地址 + R/W 位。
  3. 从设备响应 ACK。
  4. 主从数据传输。
  5. 主机发 STOP 信号结束。

2.3 Linux 驱动架构

  • 内核框架:i2c-core
  • 用户态节点:/dev/i2c-x
  • 典型驱动模型:
    • i2c_adapter:控制器驱动。
    • i2c_client:挂载的外设驱动。

2.4 用户态操作示例

  • 安装工具:sudo apt install i2c-tools
  • 扫描总线: i2cdetect -y 1
  • 读取寄存器:i2cget -y 1 0x50 0x00

2.5 C 语言示例

int fd = open("/dev/i2c-1", O_RDWR);
ioctl(fd, I2C_SLAVE, 0x50); // 设置从地址
char buf[1] = {0x00};
write(fd, buf, 1);
read(fd, buf, 1);

三、SPI(串行外设接口)

3.1 SPI 基础概念

SPI 是一种全双工、高速、同步串行通信协议,广泛用于 Flash、LCD、ADC、IMU 等设备。

  • 通信线:
    • MISO:主机接收
    • MOSI:主机发送
    • SCLK:时钟
    • CS(Chip Select):片选线

3.2 SPI 通信特点

  • 全双工:同时收发数据。
  • 主从模式:主设备控制通信。
  • 可设置模式(MODE0 ~ MODE3),定义时钟极性和相位。

3.3 Linux 驱动架构

  • 使用 spi-core 框架。
  • 设备节点:/dev/spidevX.Y
  • 驱动层通过 spi_driver 进行绑定。

3.4 用户态操作示例

  • 启用 SPI(以 Raspberry Pi 为例):sudo raspi-config
  • 查看设备:ls /dev/spidev*

3.5 C 语言示例

int fd = open("/dev/spidev0.0", O_RDWR);
uint8_t tx[] = {0x9F};
uint8_t rx[3] = {0};
struct spi_ioc_transfer tr = {
  .tx_buf = (unsigned long)tx,
  .rx_buf = (unsigned long)rx,
  .len = 1,
};
ioctl(fd, SPI_IOC_MESSAGE(1), &tr);

四、PWM(脉冲宽度调制)

4.1 PWM 基础概念

PWM(Pulse Width Modulation)是一种通过调节脉冲宽度的占空比(Duty Cycle)来控制模拟信号的方法,广泛应用于控制LED亮度、电机转速、蜂鸣器音量等场景。

  • 占空比(Duty Cycle):高电平持续时间占整个周期的比例,通常用百分比表示。
  • 周期(Period):PWM 信号一个完整的高低电平变化所用时间。
  • 极性(Polarity):PWM信号的高低电平起始状态,可为高有效或低有效。

4.2 PWM 在 Linux 中的实现

Linux 内核通过 PWM Framework 支持硬件的 PWM 控制。

  • 内核暴露的 PWM 设备一般在 /sys/class/pwm/ 下。
  • 一个 PWM 控制器对应一个 pwmchipX 目录。
  • 每个 PWM 通道以 pwmX 命名。
  • 典型文件包括:
    • export:启用某个 PWM 通道。
    • unexport:禁用 PWM 通道。
    • period:设置 PWM 周期(单位:纳秒)。
    • duty_cycle:设置占空比(单位:纳秒)。
    • enable:使能或关闭 PWM 输出。

4.3 用户态控制示例

假设系统中有一个 PWM 控制器 pwmchip0,我们要控制第 0 路 PWM:

# 导出 PWM0 通道
echo 0 > /sys/class/pwm/pwmchip0/export

# 设置周期为 1ms(1,000,000 ns)
echo 1000000 > /sys/class/pwm/pwmchip0/pwm0/period

# 设置占空比为 50%(500,000 ns)
echo 500000 > /sys/class/pwm/pwmchip0/pwm0/duty_cycle

# 使能 PWM 输出
echo 1 > /sys/class/pwm/pwmchip0/pwm0/enable
# 停止 PWM:
echo 0 > /sys/class/pwm/pwmchip0/pwm0/enable
echo 0 > /sys/class/pwm/pwmchip0/unexport

4.4 PWM 的实际应用

  • LED 亮度调节:通过改变占空比,调整 LED 的亮度,实现渐变或闪烁效果。

  • 电机转速控制:PWM 信号控制电机供电平均电压,从而控制速度。

  • 蜂鸣器音量与频率控制:通过改变周期和占空比产生不同频率和音量的声音。

4.5 代码示例(C语言)

下面是一个简单的 Linux 用户态 PWM 控制示例,演示打开 PWM 通道,设置参数,启动和关闭:

#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>

int pwm_export(int chip, int channel) {
    char path[64];
    int fd;
    snprintf(path, sizeof(path), "/sys/class/pwm/pwmchip%d/export", chip);
    fd = open(path, O_WRONLY);
    if (fd < 0) return -1;
    char buf[8];
    int len = snprintf(buf, sizeof(buf), "%d", channel);
    write(fd, buf, len);
    close(fd);
    return 0;
}

int pwm_set_period(int chip, int channel, unsigned int period_ns) {
    char path[64];
    snprintf(path, sizeof(path), "/sys/class/pwm/pwmchip%d/pwm%d/period", chip, channel);
    int fd = open(path, O_WRONLY);
    if (fd < 0) return -1;
    char buf[32];
    int len = snprintf(buf, sizeof(buf), "%u", period_ns);
    write(fd, buf, len);
    close(fd);
    return 0;
}

int pwm_set_duty_cycle(int chip, int channel, unsigned int duty_ns) {
    char path[64];
    snprintf(path, sizeof(path), "/sys/class/pwm/pwmchip%d/pwm%d/duty_cycle", chip, channel);
    int fd = open(path, O_WRONLY);
    if (fd < 0) return -1;
    char buf[32];
    int len = snprintf(buf, sizeof(buf), "%u", duty_ns);
    write(fd, buf, len);
    close(fd);
    return 0;
}

int pwm_enable(int chip, int channel, int enable) {
    char path[64];
    snprintf(path, sizeof(path), "/sys/class/pwm/pwmchip%d/pwm%d/enable", chip, channel);
    int fd = open(path, O_WRONLY);
    if (fd < 0) return -1;
    char buf[2];
    int len = snprintf(buf, sizeof(buf), "%d", enable);
    write(fd, buf, len);
    close(fd);
    return 0;
}

int main() {
    int chip = 0;
    int channel = 0;
    unsigned int period = 1000000;     // 1ms
    unsigned int duty = 500000;        // 50%

    pwm_export(chip, channel);
    pwm_set_period(chip, channel, period);
    pwm_set_duty_cycle(chip, channel, duty);
    pwm_enable(chip, channel, 1);

    printf("PWM enabled. Press Enter to stop...\n");
    getchar();

    pwm_enable(chip, channel, 0);

    return 0;
}

以上就是 Linux 下 PWM 基础概念及简单操作介绍,掌握这些内容可以帮助你快速在嵌入式项目中实现硬件控制和调节。

五、ADC(模拟转数字转换器)

5.1 ADC 基础概念

ADC(Analog-to-Digital Converter)将连续模拟信号转换为数字信号,在传感器数据读取中非常常见。

  • 分辨率:如 10bit、12bit、16bit。
  • 电压范围:03.3V,05V 等。
  • 常见用途:温度、光照、电压检测。

5.2 Linux 驱动架构

  • 使用 iio 框架(Industrial I/O)。
  • 用户节点:/sys/bus/iio/devices/iio:deviceX/in_voltageY_raw

5.3 用户态读取示例

cat /sys/bus/iio/devices/iio:device0/in_voltage0_raw

5.4 实践应用

  • 温度传感器读取。

  • 电池电压监测。

六、调试技巧与开发建议

6.1 设备树配置

  • 嵌入式平台多数使用 Device Tree 配置外设信息,确保:

  • 节点启用(status = “okay”)。

  • 正确的 pinmux 和中断号。

  • 驱动兼容字符串匹配成功。

6.2 日志调试

  • 使用 dmesg | grep 命令查看驱动加载和设备初始化信息。

  • 查看中断分配情况:

cat /proc/interrupts

6.3 权限问题

  • 设备文件权限不足时,建议使用 sudo 运行命令。

  • 也可以通过 udev 规则给设备节点设置合适权限,避免频繁使用 sudo。

七、总结

接口通信方式特点应用场景
UART异步串口简单稳定调试口、蓝牙、GPS
IIC同步串口多从支持EEPROM、传感器
SPI同步串口高速全双工LCD、Flash、IMU
PWM模拟控制占空比调制电机、LED、蜂鸣器
ADC模拟采集分辨率控制电压、电流、温度

Linux 提供了统一且强大的外设抽象接口,使得在各种平台上开发变得规范和高效。掌握这些外设的基本概念与 Linux 实现机制,对于驱动开发、系统集成乃至上层应用开发都有极大的帮助。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值