[XDU] 2025秋A测 全代码全流程题解
题目:距离测控仿真系统
功能: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前端,挺方便的,直接就能跑起来。在自己的环境里面装上pyside6和pyserial应该就能跑起来。
三、跑起来
下载Virtual Serial Port Driver。打开,把两个串口Pair起来。要打开Proteus模拟看占用了哪个串口,就是单片机对应的串口,这里主包的是COM1和COM2。保持模拟运行和串口pair,运行上位机软件,选择对应的串口,就可以自己玩了。Enjoy!
更多推荐



所有评论(0)