起因

最近因为个人项目需要,要将不允许联网的主机里数据库的数据发送至远程服务器。考虑到既然主机无法联网,不如用单片机作为中间人,通过串口将数据发送给单片机,再由联网的单片机将数据发送至服务器。这不就完美实现“偷数据”的操作了么!说干就干!

主机数据抓取

既然要将数据发送至单片机,那首先我得先拿到数据。由于主机是离线且最高权限状态,果断装一个python环境(这样可以先分析一波数据,将异常值与有效的数据进行区分后选择发送),通过pyserial和pymssql进行数据抓取。详细的代码就不列了,说下在过程中碰到的一个坑。

最开始由于python程序中没有设计发送截至符,所以测试时,单片机无法确定数据截至位置在哪,导致发送至远端服务器的数据都是断断续续的。而在主程序中添加截至符发送后,完美解决该问题。

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
import serial
import json
import pymssql

def get_data():
"""
"""
return(data)

#后续增加截至符的发送
def deliver_data():
myChar='#'
#设置对应串口号与通讯波特率
ser = serial.Serial(port="COM4", baudrate=115200)

# 将json格式进行转换后,发送
data=get_data()
comdata=json.dumps(data)
write_len = ser.write(comdata.encode())
ser.write(myChar.encode())
print("串口发出{}个字节。".format(write_len))
ser.close()

def main():
deliver_data()
print('传输完毕')

if __name__=='__main__':
main()

对了,由于主机无法联网而且还是windows7操作系统,其实配置python环境也格外艰难!在趟过了各种坑后,成功运行抓数据的脚本时,我的眼角都湿润了。

单片机程序编写

由于esp8266可以非常愉快的使用arduino框架进行开发,大大降低了我们这种萌新的上手难度。参考《arduino(2)–通过ESP8266模块实现串口接收数据,使用TCP协议进行局域网通信》文章,略作修改,就成功实现了串口数据的读取与发送。

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
47
48
49
50
51
52
53
54
55
56
#include "ESP8266WiFi.h"
#define led 2
const char *ssid = "wifi名称";
const char *password = "wifi密码";
const char *host = "服务器地址";
WiFiClient client;
const int tcpPort = 服务器端口;
static String comdata = "";
char myChar='#';
void setup()
{
Serial.begin(115200);
pinMode(led,OUTPUT);
delay(10);
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);//启动
//在这里检测是否成功连接到目标网络,未连接则阻塞。
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
}
//几句提示
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
void loop()
{
/******************串口接受数据************************/
while (Serial.available() > 0 ) // 串口收到字符数大于零。
{
comdata = Serial.readStringUntil(myChar);
}
/******************串口打印数据************************/
if(comdata!="")//如果接受到数据
{
client.print(comdata);//向服务器发送数据
}
comdata="";//清空数据
if (client.connected()) //尝试访问目标地址,如果连接后LED灯灭,毕竟这种事情要低调
digitalWrite(led, HIGH);
else
digitalWrite(led, LOW);

while (!client.connected())//若未连接到服务端,则客户端进行连接。
{
if (!client.connect(host, tcpPort))//实际上这一步就在连接服务端,如果连接上,该函数返回true
{
Serial.println("连接中....");
delay(500);
}
}
}

事情到了这一步,整个流程其实已经完全跑通了,也成功实现了“偷”数据。但是主机后边插一根数据线,数据线再连接到一个大大的NodeMCU开发板上。实在太不优雅了!令我完全无法接受!

上淘宝看看有没有更简约的方案。似乎简单的USB转TTL通讯板+ESP-01s就能解决这个问题。果断买来换掉原方案。

方案升级

然而,想象的很美好,这个方案却有一个致命问题,那就是通讯不稳定。导致主机的数据无法正确发送到单片机上。为此我还特地找来两台主机上分别实验了一下,其中一台能够正常通讯,另一台就一直失败。而旧方案相比之下就非常稳定,都能成功偷发数据。初步怀疑可能是新方案供电不稳定导致的,但是没有继续验证,如果有大佬懂得,麻烦告知一下,谢谢!

DIY单片机

既然现有方案无法满足我的需求,那只有一条路了!自己制作一个小巧玲珑,性能稳定的单片机。像我这样的萌新,直接开干,那肯定是不可能的了,还是得上开源硬件平台看看有没有大佬已经做过类似的项目。成功仿造一个,不就成了么!

usb-esp8266 - 嘉立创EDA开源硬件平台 (oshwhub.com)

感谢moguiliue大佬开源的项目,直接打板,开干!

铁板烧

仿造

大佬的方案确实可以!成品能够稳定运行,完美满足我的需求。不过过程中发现原设计USB公头位置的PCB会有干涉问题(不知道是不是我买的元器件不对🤦‍)。每套主板前端都要把干涉的位置用锉刀磨掉,才能焊上USB头。有点费力

而且这个方案只能满足最基本的数据通讯,没有将其他GPIO口引出,导致后续无法外接传感器或者显示屏。虽然优雅,但可玩性又差点意思。怎么办?

DIY单片机2.0

既要优雅,又要能扩展,不如参考大佬的思路,自己再从头设计一版!

新设计

自己从头设计的开发板,将原有CH340G的方案改为CH340C,省下外围晶振电路的空间,增加一个4pin母座用于引出I2C通讯。由于原设计的走线和布局很难改动了,只能重构整体。目前进度是已打板,但还未制作。希望等材料到了之后,这块自己第一次从头设计的单片机能成功运行!

2023/4/23 update:

今天终于把自己第一次设计的单片机做出来了,一切运行正常,开心~
新设计
新设计