描述
<h1>VFD电脑性能监控器+USB扩展与TF读卡器</h1>
<p><img src="//image.lceda.cn/oshwhub/db6f66b521ab41e497c4e382af98fc63.jpg" alt="IMG_0080.jpg"></p>
<h2>1. 项目功能介绍</h2>
<p>手里弄到一批Futaba的16x2点阵屏,于是乎物尽其用做个小桌搭,但是现在社区里做VFD时钟的太多。我自己也做了很多钟,在做钟就有点搞笑了....
那么就加点不一样的功能,我希望他可以具有链接电脑的能力使其进行赋能一些特性</p>
<ol>
<li>USB HUB扩展集线器</li>
<li>SD/TF卡读卡器</li>
<li>温湿度传感器</li>
<li>可显示日期时间</li>
<li>配套上位机,随意传输显示内容
<ol>
<li>实时网速上下行</li>
<li>CPU/内存使用率</li>
<li>自定义文字</li>
</ol></li>
</ol>
<h2>2. 项目属性</h2>
<p>项目为首次公开,未参与任何活动、未向任何组织公布</p>
<h2>3. 开源协议</h2>
<p>CC BY-NC-SA 3.0(创意共享署名-非商业性-相同方式共享 3.0)是一种创意共享许可证,允许用户在特定条件下使用和分享作品。以下是该许可证的主要规定:</p>
<p>署名(Attribution):用户在使用作品时必须给予适当的署名,提供许可证的链接,并说明是否对作品进行了修改。这一要求确保原作者得到应有的认可。</p>
<p>非商业性(NonCommercial):该许可证禁止将作品用于商业目的。用户只能在非商业的环境中使用和分享作品。</p>
<p>相同方式共享(ShareAlike):如果用户对作品进行了改编或衍生创作,必须在相同的许可证下分享这些新作品。这意味着新作品也必须遵循相同的使用条款。</p>
<p>无附加限制(No additional restrictions):用户不得施加法律条款或技术措施,限制他人使用该许可证所允许的权利。</p>
<h2>3. 硬件设计</h2>
<p><img src="//image.lceda.cn/oshwhub/306a47e97fe443469d2da3badf6f335e.png" alt="容器 1.png"></p>
<h3>3.1 VFD屏幕驱动</h3>
<p>由于屏幕是集成驱动的,所以在设计电路的时候只需要关心:满足灯丝需求、满足SPI通讯的电平要求即可。
屏幕高压输入41V使用LGS6302B5这款升压芯片实现
灯丝实测使用直流供电效果几乎看不出,采用LDO ME6211C33M5G-N 3.3V供电降压</p>
<p><img src="//image.lceda.cn/oshwhub/0df1a351f8b84764b0ef72abb3b15a44.png" alt="image.png"></p>
<h3>3.2 集成外设</h3>
<p>使用了集成ESP32-C3 模组为主控,构建自动下载电路方便调试。
整体中,从Type-C接口进行供电,当连接电脑的时候D+和D-数据线首先接入SL2.1A一款USB扩展IC,从其中扩展出4路HUB接口,其中一路固定连接到CH340C,剩下的3路其中一路给到TF读卡器IC使用,剩下的两路分别是扩展USB-A和Type-C接口。</p>
<p><img src="//image.lceda.cn/oshwhub/e3ee9bc3aafe45f39b0cfe50c80a72f7.png" alt="image.png"></p>
<p><strong>实时时钟</strong>
实时时钟采用高精度IC:RX8025T-UB,这款IC采用的i2c通讯,后备电池使用可充电电池设计,即上电后则开始充电,掉电后开始放电保持时钟不断走时。 使用两颗二极管构建简易供电选择器</p>
<p><img src="//image.lceda.cn/oshwhub/c7588c9363774feeb01f6b22ed07effd.png" alt="image.png"></p>
<h2>4.软件开发</h2>
<p>软件部分分为两个部分</p>
<ol>
<li>ESP32 PlatformIO</li>
<li>PyQt6 上位机</li>
</ol>
<h3>目录结构</h3>
<p><img src="//image.lceda.cn/oshwhub/0770aeaeeb2d4e73983424b7b3f66ce2.png" alt="image.png"></p>
<h3>4.1 ESP32 PlatfromIO</h3>
<p><img src="//image.lceda.cn/oshwhub/64cbb66cad194b53bbd6d68a2432bb9e.png" alt="主流程.png"></p>
<p><img src="//image.lceda.cn/oshwhub/d3dce4df47154f0295baef8a74e7bfd6.png" alt="消息处理流程.png"></p>
<p><strong>部分核心代码:</strong></p>
<pre><code class="language-c++">#ifndef __CONTROLLER_H
#define __CONTROLLER_H
#include "command.h"
#define DEFAULT_SEPARATOR ";"
typedef enum {
CT_VFD_VAL_BRIGHTNESS = 0x00, // VFD亮度调整
CT_VFD_AC_EN = 0x01, // VFD供电使能
CT_VFD_AC_CLEAR = 0x02, // VFD内容清空
CT_VFD_VAL_INPUT_0 = 0x03, // VFD输入0行
CT_VFD_VAL_INPUT_1 = 0x04, // VFD输入1行
CT_DATGETIME_VAL_SET = 0x10, // 日期时间设置
CT_DISPLAY_VAL_TYPE = 0x11, // 显示内容
} control_type;
typedef enum {
CDIS_DATETIME = 0, // 显示日期时间,温湿度
CDIS_CUSTOM = 1, // 显示自定义内容
} control_display;
typedef void (*ControllerReceiveAction)(control_type, cmd_action_t*);
typedef void (*ControllerReceiveValue)(control_type, cmd_value_t*);
class Controller {
public:
bool checkHeart() { return util.checkHeartIsSurvive(); }
void init(ControllerReceiveValue valueCb,
ControllerReceiveAction actionCb) {
receiveValue = valueCb;
receiveAction = actionCb;
// 默认显示时间
current_display_type = CDIS_DATETIME;
}
void decoder(const char* buf) {
util.decode(buf);
if (util.getCmdValue() != NULL) {
cmd_value_t* val = util.getCmdValue();
int number =
(int)strtol(val->key, NULL, 16); // 16进制字符串转换为整数
if (number == CT_VFD_VAL_BRIGHTNESS ||
number == CT_VFD_VAL_INPUT_0 || number == CT_VFD_VAL_INPUT_1 ||
number == CT_DATGETIME_VAL_SET ||
number == CT_DISPLAY_VAL_TYPE) {
receiveValue((control_type)number, val);
}
} else if (util.getCmdAction() != NULL) {
cmd_action_t* ac = util.getCmdAction();
int number =
(int)strtol(ac->key, NULL, 16); // 16进制字符串转换为整数
if (number == CT_VFD_AC_EN || number == CT_VFD_AC_CLEAR) {
receiveAction((control_type)number, ac);
}
}
}
/**
* 返回当前的显示内容类型
*/
control_display getCurrentDispType() { return current_display_type; }
void setCurrentDispType(control_display t) { current_display_type = t; }
private:
control_display current_display_type;
CommandUtil util;
ControllerReceiveValue receiveValue;
ControllerReceiveAction receiveAction;
};
#endif</code></pre>
<h3>4.2 Python PyQt6 上位机</h3>
<p><img src="//image.lceda.cn/oshwhub/273f967b899e454f9f71f1393f400fed.png" alt="image.png"></p>
<p><img src="//image.lceda.cn/oshwhub/b53d662a72e5463fb66fb53a180a33a8.png" alt="image.png"></p>
<p><strong>部分核心代码</strong></p>
<pre><code class="language-python">def task_heart():
"""
定时发送心跳数据
:return:
"""
while True:
time.sleep(4)
send_message(f"CMD:HEART")
def search_serial_list():
global serial_port_lists
serial_port_lists = serial.tools.list_ports.comports()
for port in serial_port_lists:
print(f"端口: {port.device}, 描述: {port.description}")
def connect_serial(port_item: ListPortInfo):
global serial_connect_state, serial_connect
if serial_connect_state:
return
try:
serial_connect = serial.Serial(port=port_item.name, baudrate=115200, bytesize=8, timeout=2,
stopbits=serial.STOPBITS_ONE)
except serial.SerialException as e:
serial_connect = None
print("串口被占用,打开失败")
show_dialog_message("错误", "串口被占用,打开失败", QMessageBox.Icon.Critical)
return
if serial_connect.is_open:
print(f"成功连接到 {serial_connect.name}")
serial_connect_state = True
else:
serial_connect_state = False
print("连接失败")
def disconnect_serial():
global serial_connect, serial_connect_state
if serial_connect_state and serial_connect is not None:
serial_connect_state = False
serial_connect.close()
serial_connect = None
print("串口关闭成功")
def send_message(msg):
"""
串口发送字符串数据
:param msg: 字符串数据
:return:
"""
if serial_connect_state:
with lock:
serial_connect.write(f"{msg}\n".encode())
def vfd_clear():
"""
清空VFD的内容显示
:return:
"""
send_message(f"CMD:ACTION:0x02:1")
def receive_message():
if serial_connect_state and serial_connect.in_waiting > 0:
received_data = serial_connect.readline()
if received_data:
print(f"接收: {received_data.decode('utf-8')}")
</code></pre>
<h2>5. 大赛LOGO验证</h2>
<p><img src="//image.lceda.cn/oshwhub/1a014317a8e84890aea21fbe167dfa87.jpg" alt="IMG_0075.jpg"></p>
<h2>6. 组装</h2>
<p><img src="//image.lceda.cn/oshwhub/c52790224f6f445aaaf0638e0f6efc36.jpg" alt="IMG_0077.jpg"></p>
<p><img src="//image.lceda.cn/oshwhub/abf9f45891cb4e65b52f8af5ec50f891.jpg" alt="IMG_0078.jpg"></p>
<p><img src="//image.lceda.cn/oshwhub/924454e7d3ac4485a3662ff060e9cf90.jpg" alt="IMG_0079.jpg"></p>
<p><img src="//image.lceda.cn/oshwhub/0c10b9e7cf3b4c449f4a99694528f309.jpg" alt="IMG_0082.jpg"></p>
<h2>7. 视频演示</h2>
<p><a href="https://www.bilibili.com/video/BV152xceQEYi/" target="_blank">https://www.bilibili.com/video/BV152xceQEYi/</a></p>
<h2>8. 源码</h2>
<p><a href="https://github.com/ccy-studio/CCY-VFD-162SD17INK1D28" target="_blank">https://github.com/ccy-studio/CCY-VFD-162SD17INK1D28</a></p>
<h2>9. BOOM</h2>
<p>具体使用元器件以及数量可在下发BOOM表格内直接购买。
屏幕需要特定采购,请加群联系我咨询购买。 数量不多先到先来</p>
评论(3)