题目:距离测控仿真系统

功能:Arduino UNO(Atmega328P)通过串行接口组件与上位机 PC 进行双向
通信,PC 上位机软件向 Arduino UNO 发送学生自己的学号,Arduino UNO 收到
后向 PC 机发送当前的距离值,并且在 LCD 上显示学生的学号、当前的距离值。
PC 上位机软件显示收到的距离值。
Arduino UNO 控制驱动直流电机,当距离值等于或低于预定的距离((20+
学号末位数)cm)时,启动直流电机转动;当距离值高于预定的距离((20+学
号末位数)cm)时,直流电机停止转动。同时,实时距离值在 LCD 和 PC 上位
机软件显示。如:学生学号末位数为 5,手动减少距离值等于或小于设定的距离
25 cm(20+5=25)时,驱动直流电机开始转动。
LCD 第一行显示 ID:学号,第二行显示 DIST:距离值
必须自行编写 PC 上位机软件,实现 PC 与 Arduino 的双向数据传输及管理控制。
编程语言不限。
上位机软件 GUI 界面 Title 显示学生自己的学号和姓名;需要有发送窗口显示发
送的学号;有接收窗口显示接收到的距离值;GUI 界面上需要有串口选择和串
口打开关闭功能。

题目和前几年基本类似,感谢宗门大能留下的解答,主包也是一早上快速上手,读完这篇解答相信你也可以。


〇、会用到的软件

Arduino IDE
VSPD
Proteus(自己找吧
逆天A测,什么软件都不给,鼓励正版化说是


一、单片机部分

这里使用Arduino IDE来处理代码,会自动下载对应的工具链和库,一键编译很方便。

// sketch_2025fall_atest.ino
#include <Wire.h>
#include <LiquidCrystal.h>
#include <hcsr04.h>

// 定义引脚和常量
const int MOTOR_PIN = 8;
const int SR04_TR = 6;
const int SR04_ECHO = 7;
const int LCD_RS = 12;
const int LCD_E = 11;
const int LCD_D0 = 5;
const int LCD_D1 = 4;
const int LCD_D2 = 3;
const int LCD_D3 = 2;
const int LCD_COL = 16;
const int LCD_ROW = 2;
const int BAUD = 9600;
const int MOTOR_OFFSET = 20;

HCSR04 hcsr04(SR04_TR, SR04_ECHO);  // 初始化距离传感器
LiquidCrystal lcd(LCD_RS, LCD_E, LCD_D0, LCD_D1, LCD_D2, LCD_D3);  // 初始化 LCD

String idString = "";
int idLength, lastDigit, motorThreshold=0;
float distance=0.0;

void lcdDisplay() { // 显示学号和距离
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("ID: ");
  lcd.print(idString);
  lcd.setCursor(0, 1);
  lcd.print("DIST: ");
  lcd.print(distance);
}

void motorControl() {
  if (distance < motorThreshold) {
    digitalWrite(MOTOR_PIN, HIGH);  // 启动电机
  } else {
    digitalWrite(MOTOR_PIN, LOW);  // 停止电机
  }
}

void setup() {
  Serial.begin(BAUD);           // 初始化串口
  lcd.begin(LCD_COL, LCD_ROW);  // 初始化 LCD 显示
  pinMode(MOTOR_PIN, OUTPUT);   // 设置电机引脚为输出模式
}

void loop() {
  if (Serial.available() > 0) {  // 检查是否有串口输入
    while (Serial.available() > 0) {
      idString += (char)Serial.read();
      delay(10);
    }
    lcd.print(idString);
    idLength = idString.length();
    lastDigit = idString.substring(idLength - 3, idLength - 2).toInt();   // 提取学号的末位数字
  }
  distance = hcsr04.distanceInMillimeters()/10.0;  // 获取距离,单位为厘米
  motorThreshold = lastDigit + MOTOR_OFFSET;

  lcdDisplay();
  motorControl();
  Serial.print(distance);
  delay(1000);  // 等待一秒
}


打开详细输出,方便找到输出固件位置。然后点击左上角√按钮Verify。根据输出路径可以找到固件。
主包这里使用了everything直接搜索固件后缀。

在这里插入图片描述
把固件复制到方便的位置,打开proteus,双击arduino板子,把固件换成自己编译的。
在这里插入图片描述
至此单片机部分结束。在proteus中启动模拟可以看到有结果但不多。


二、上位机部分

import serial
import serial.tools.list_ports
import PySide6.QtCore

from PySide6.QtWidgets import (
    QApplication, QWidget, QVBoxLayout, QHBoxLayout, QLabel,
    QLineEdit, QPushButton, QTextEdit, QComboBox
)

class SerialApp(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("114514 哈基米")  # 学号和姓名

        # 串口选择
        self.port_combo = QComboBox()
        self.refresh_ports()

        self.open_btn = QPushButton("打开串口")
        self.close_btn = QPushButton("关闭串口")
        self.close_btn.setEnabled(False)

        # 发送窗口
        self.send_label = QLabel("发送学号:")
        self.send_edit = QLineEdit("1919810")
        self.send_btn = QPushButton("发送")

        # 接收窗口
        self.recv_label = QLabel("接收距离值:")
        self.recv_text = QTextEdit()
        self.recv_text.setReadOnly(True)

        # 布局
        port_layout = QVBoxLayout()
        port_layout.addWidget(QLabel("串口选择:"))
        port_layout.addWidget(self.port_combo)
        port_layout.addWidget(self.open_btn)
        port_layout.addWidget(self.close_btn)

        send_layout = QVBoxLayout()
        send_layout.addWidget(self.send_label)
        send_layout.addWidget(self.send_edit)
        send_layout.addWidget(self.send_btn)

        recv_layout = QVBoxLayout()
        recv_layout.addWidget(self.recv_label)
        recv_layout.addWidget(self.recv_text)

        main_layout = QVBoxLayout()
        main_layout.addLayout(port_layout)
        main_layout.addLayout(send_layout)
        main_layout.addLayout(recv_layout)
        self.setLayout(main_layout)

        # 串口对象
        self.ser = None

        # 信号连接
        self.open_btn.clicked.connect(self.open_serial)
        self.close_btn.clicked.connect(self.close_serial)
        self.send_btn.clicked.connect(self.send_data)

        # 定时器用于接收数据
        self.timer = PySide6.QtCore.QTimer()
        self.timer.timeout.connect(self.read_serial)

    def refresh_ports(self):
        self.port_combo.clear()
        ports = serial.tools.list_ports.comports()
        for port in ports:
            self.port_combo.addItem(port.device)

    def open_serial(self):
        port = self.port_combo.currentText()
        try:
            self.ser = serial.Serial(port, 9600, timeout=0.1)
            self.open_btn.setEnabled(False)
            self.close_btn.setEnabled(True)
            self.timer.start(100)
        except Exception as e:
            self.recv_text.append(f"串口打开失败: {e}")

    def close_serial(self):
        if self.ser and self.ser.is_open:
            self.ser.close()
        self.open_btn.setEnabled(True)
        self.close_btn.setEnabled(False)
        self.timer.stop()

    def send_data(self):
        if self.ser and self.ser.is_open:
            data = self.send_edit.text()
            self.ser.write(data.encode())
            self.recv_text.append(f"已发送学号: {data}")
        else:
            self.recv_text.append("串口未打开,无法发送。")

    def read_serial(self):
        if self.ser and self.ser.is_open:
            try:
                line = self.ser.readline().decode().strip()
                if line:
                    self.recv_text.append(f"接收到距离值: {line}")
            except Exception as e:
                self.recv_text.append(f"接收错误: {e}")

def run_app():
    app = QApplication([])
    window = SerialApp()
    window.show()
    app.exec()


def main():
    run_app()

if __name__ == "__main__":
    main()

这里直接让gpt写了pyside前端,挺方便的,直接就能跑起来。在自己的环境里面装上pyside6pyserial应该就能跑起来。


三、跑起来

下载Virtual Serial Port Driver。打开,把两个串口Pair起来。要打开Proteus模拟看占用了哪个串口,就是单片机对应的串口,这里主包的是COM1和COM2。保持模拟运行和串口pair,运行上位机软件,选择对应的串口,就可以自己玩了。Enjoy!

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐