树莓派串口实战:用Python脚本控制LED,告别枯燥的Hello World

树莓派作为一款功能强大的微型计算机,在物联网和智能家居领域有着广泛的应用。而串口通信作为嵌入式系统中最基础也最可靠的通信方式之一,往往被初学者用来完成简单的"Hello World"测试。但今天,我们要突破这个局限,将串口通信与实际的硬件控制结合起来,打造一个真正实用的项目——通过PC端发送字符远程控制树莓派上的LED灯。

这个项目非常适合那些已经掌握了树莓派基础操作,想要进一步探索物联网开发的爱好者。不同于传统的串口教程,我们将直接从项目需求出发,通过完整的代码示例和详细的接线说明,带你体验串口通信在实际应用中的魅力。

1. 项目准备与环境搭建

在开始编码之前,我们需要确保树莓派的串口功能已经正确配置。树莓派默认将串口分配给蓝牙模块使用,因此需要先进行一些调整。

首先通过SSH或终端登录树莓派,执行以下命令更新系统:

sudo apt update && sudo apt upgrade -y

接下来配置串口。运行raspi-config工具:

sudo raspi-config

在菜单中选择:

  1. Interface Options
  2. Serial Port
  3. 当询问"Would you like a login shell to be accessible over serial?"时选择 No
  4. 当询问"Would you like the serial port hardware to be enabled?"时选择 Yes

完成配置后重启树莓派:

sudo reboot

重启后,我们需要安装必要的Python库:

sudo apt install python3-serial python3-rpi.gpio -y

验证串口是否可用:

ls -l /dev/serial*

正常情况下应该看到类似这样的输出:

lrwxrwxrwx 1 root root 7 Aug 1 10:00 /dev/serial0 -> ttyAMA0
lrwxrwxrwx 1 root root 5 Aug 1 10:00 /dev/serial1 -> ttyS0

提示:不同版本的树莓派串口设备名称可能有所不同,较新的型号通常使用ttyAMA0作为主串口。

2. 硬件连接与电路设计

本项目需要以下硬件组件:

  • 树莓派(任何型号)
  • LED灯(任意颜色)
  • 220Ω电阻
  • 面包板和跳线
  • USB转TTL串口模块(如CH340、CP2102等)

电路连接步骤如下:

  1. 将LED的正极(长脚)通过220Ω电阻连接到树莓派的GPIO 26(物理引脚37)
  2. 将LED的负极(短脚)连接到树莓派的GND(物理引脚39)
  3. 将USB转TTL模块的TX连接到树莓派的RX(GPIO 15,物理引脚10)
  4. 将USB转TTL模块的RX连接到树莓派的TX(GPIO 14,物理引脚8)
  5. 将USB转TTL模块的GND连接到树莓派的GND(物理引脚6)

连接示意图如下:

树莓派引脚 连接目标 说明
GPIO 26 LED+ 通过220Ω电阻
GND LED- LED负极
GPIO 15 TTL-RX 树莓派接收
GPIO 14 TTL-TX 树莓派发送
GND TTL-GND 共地

注意:务必确保USB转TTL模块的工作电压是3.3V,5V电平可能会损坏树莓派的GPIO口。

3. Python控制脚本开发

现在我们来编写核心的Python脚本,实现串口通信和LED控制功能。创建一个新文件 led_control.py

#!/usr/bin/env python3
import serial
import RPi.GPIO as GPIO
from time import sleep

# GPIO配置
LED_PIN = 26
GPIO.setmode(GPIO.BCM)
GPIO.setup(LED_PIN, GPIO.OUT)

# 串口配置
ser = serial.Serial(
    port='/dev/ttyAMA0',
    baudrate=9600,
    parity=serial.PARITY_NONE,
    stopbits=serial.STOPBITS_ONE,
    bytesize=serial.EIGHTBITS,
    timeout=1
)

print("串口LED控制程序已启动,等待指令...")

try:
    while True:
        if ser.in_waiting > 0:
            command = ser.read().decode('utf-8').strip()
            
            if command == 'a':
                GPIO.output(LED_PIN, GPIO.HIGH)
                ser.write(b"LED已开启\n")
                print("收到指令:开启LED")
            elif command == 'b':
                GPIO.output(LED_PIN, GPIO.LOW)
                ser.write(b"LED已关闭\n")
                print("收到指令:关闭LED")
            elif command == 's':
                status = "开" if GPIO.input(LED_PIN) else "关"
                ser.write(f"当前LED状态: {status}\n".encode())
            else:
                ser.write(b"未知指令,请发送a(开)或b(关)\n")

except KeyboardInterrupt:
    print("\n程序终止")
finally:
    ser.close()
    GPIO.cleanup()

这段代码实现了以下功能:

  • 初始化GPIO 26为输出模式
  • 配置串口通信参数(9600波特率,8数据位,无校验位)
  • 循环监听串口输入
  • 根据接收到的字符执行相应操作:
    • 'a':开启LED
    • 'b':关闭LED
    • 's':查询LED状态
  • 通过串口返回操作结果

给脚本添加执行权限:

chmod +x led_control.py

运行脚本:

./led_control.py

4. PC端测试与高级功能扩展

在PC端,我们可以使用任何串口调试工具(如Putty、Tera Term或Arduino IDE的串口监视器)与树莓派通信。确保选择正确的COM端口和9600波特率。

基本测试流程:

  1. 打开串口调试工具
  2. 发送字符'a',观察LED是否点亮
  3. 发送字符'b',观察LED是否熄灭
  4. 发送字符's',查看当前LED状态

如果想进一步扩展功能,可以考虑以下方向:

  1. 多LED控制
# 定义多个LED引脚
LED_PINS = {'red': 26, 'green': 19, 'blue': 13}

# 初始化所有LED
for pin in LED_PINS.values():
    GPIO.setup(pin, GPIO.OUT)

# 修改命令解析逻辑
if command.startswith('led'):
    _, color, action = command.split()
    pin = LED_PINS.get(color)
    if pin:
        GPIO.output(pin, GPIO.HIGH if action == 'on' else GPIO.LOW)
  1. PWM调光控制
# 初始化PWM
pwm = GPIO.PWM(LED_PIN, 100)  # 100Hz频率
pwm.start(0)  # 初始亮度0%

# 添加亮度控制命令
elif command.isdigit():
    brightness = int(command)
    if 0 <= brightness <= 100:
        pwm.ChangeDutyCycle(brightness)
  1. 安全验证
# 添加简单密码验证
PASSWORD = "1234"

if not authenticated:
    if command == PASSWORD:
        authenticated = True
        ser.write(b"认证成功\n")
    else:
        ser.write(b"需要密码认证\n")
        continue
  1. 日志记录
import datetime

def log_action(action):
    with open('led_control.log', 'a') as f:
        timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        f.write(f"{timestamp} - {action}\n")

# 在每次操作后调用
log_action(f"LED turned {'on' if state else 'off'}")

5. 常见问题排查与优化建议

在实际项目中,可能会遇到各种问题。以下是几个常见问题及其解决方案:

问题1:串口无法通信

  • 检查接线是否正确(TX-RX交叉连接)
  • 确认USB转TTL模块驱动已安装
  • 尝试不同的波特率
  • 检查树莓派串口是否被其他进程占用:
    lsof /dev/ttyAMA0
    

问题2:LED不亮

  • 检查LED极性是否正确
  • 用万用表测量GPIO口输出电压
  • 尝试更换GPIO口

问题3:串口数据乱码

  • 确保双方波特率设置一致
  • 检查地线是否连接良好
  • 尝试降低波特率(如从115200降到9600)

性能优化建议:

  1. 添加异常处理增强稳定性:
try:
    ser.write(response)
except serial.SerialTimeoutException:
    print("串口写入超时")
  1. 使用线程提高响应速度:
from threading import Thread

def read_serial():
    while running:
        if ser.in_waiting:
            process_command(ser.read())

Thread(target=read_serial).start()
  1. 实现命令队列处理:
import queue

command_queue = queue.Queue()

def worker():
    while True:
        command = command_queue.get()
        # 处理命令
        command_queue.task_done()

这个项目虽然简单,但涵盖了物联网开发的几个核心要素:硬件控制、通信协议和软件逻辑。通过扩展功能,你可以将其发展为一个完整的智能家居控制系统,比如添加温度传感器、继电器控制家电等。

更多推荐