Arduino仿真の痛

不要心血来潮做硬件仿真,会变得不幸。


前言

如果你学的不是软工而是计算机,那么你的遇到大作业可以变得多种多样!

我在开学前看这个硬件课设的大纲时,里面有一些软硬结合的项目,看上去都是以软件系统的形式作为最终呈现,所以我一个软件人早早地就看准了大纲中的一个偏软件的选题,但是新冠疫情完美诠释了什么叫做『天不遂人愿』——像上半年的操作系统课设一样——题目又被改了:4个Arduino编程,1个纯软件编码查看器,还有一个明确了不给高分的加法器模拟,直接把家里蹲的我从万事俱备整成不知所措,不过想到队友都在校,主动权必然是队友掌握,我也就不管选什么题了。

不得不说队友真是非常amazing啊,过了几天领到Arduino UNO开发板直接开始研究,两天之后硬件功能已经实现了,我当然不好意思腆着脸坐等项目完成,想着能否参与一下软件功能的实现,想不到有个大坑正等着我。

仿真环境搭建

  1. 我们需要下载安装Proteus和Arduino IDE。
  2. 然后根据网上收集到的一些教程[1][2][3]逐步搭建仿真环境。

坑:

问题出在测试虚拟串口连接时,无论如何都搜不到两个串口,自然也无法看到串口助手中显示出信息了。

一开始我还以为是代码的问题或者是配置的问题,但不管怎么尝试就是读不到串口,就差重启电脑了。

巧了。

搜到一个VMware的串口问题[4],里面说虚拟机不支持热插拔,要重启电脑,事到如今也顾不得浏览器开着几十个窗口了,反正之后可以恢复,重启就重启吧。然后

好了。

可以读到串口了。

挺好。

随后根据课设的要求模拟了测试体温的程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <LiquidCrystal.h>

LiquidCrystal lcd(13, 12, 11, 10, 9, 8); // 根据电路连接情况设置

void setup() {
Serial.begin(9600);
lcd.begin(16, 2);
}

void loop() {
long rand = random(359, 420);
float output = rand / 10.0;
lcd.setCursor(0, 0);
lcd.println(output);
Serial.println(output);
delay(1000);
}

软件与串口通信

秉持着『非必要不学新语言』的一贯原则,C#上位机必然不是我的首选,机缘巧合下发现了Node.js下有一个SerialPort[5],加之我正好在学前端,遂大喜,这样就可以基于Node.js搭建一个简陋的前后端来提供友好的交互。

SerialPort的文档写得其实一般,所以在借助另寻的文档[6]后比较顺利地写了一个能够读取串口数据并进行判断体温的逻辑:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
// main.mjs
import { SerialPort } from 'serialport';
import { log } from 'console';

const SERIAL_PATH = 'COM2'; // 端口号
const TEMPERATURE_THRESHOLD = 37.3; // 体温阈值

const serialPort = new SerialPort({
path: SERIAL_PATH,
baudRate: 9600, // 波特率
autoOpen: true,
});

// serialPort.write('Hello Arduino!');

let serialInputList = [];
serialPort.on("readable", () => {
let serialInput = serialPort.read();

if (serialInput.toString('hex') !== '0a') {
if (serialInput.toString('hex') !== '0d') {
serialInputList.push(serialInput);
}
} else {
let serialBuffer = Buffer.concat(serialInputList);
let temperature = parseFloat(serialBuffer.toString());

if (isTemperatureSafe(temperature)) {
log(temperature.toFixed(1), '°C');
} else {
log('\t\t', temperature.toFixed(1), '°C, WARNING!');
}

serialInputList = [];
}
});

// =====================================================================

function isTemperatureSafe(temperature) {
if (temperature <= TEMPERATURE_THRESHOLD) {
return true;
} else {
return false;
}
}

串口发送来的数据被Node.js接收后实际上是十六进制的Buffer类型,而在每一行数据的的行尾也都包含了换行符“0A 0D”,所以在读取数据的过程中需要对Buffer收到的每一位数据都做好检查。


参考资料

[1].Arduino UNO Library for Proteus V2.0

[2].【教程】Proteus仿真Arduino,串口打印hello

[3].Arduino与Protues串口通信

[4].vmware虚拟机检测不到vspd虚拟串口问题

[5].SerialPort Usage

[6].JS知识点归纳 : serialport.js串口使用


Arduino仿真の痛
https://skycurtain.github.io/2022/11/29/arduino-simulation-and-serial-port-communication/
作者
Skycurtain
发布于
2022年11月29日
许可协议