Qt 串口编程-从入门到实战
1. Qt 串口通信流程解析
1.1 串行通信和并行通信对比
- 并行通信适合距离较短的通信,且信号容易受干扰,成本高
- 串口通讯-设备(蓝牙, wifi, gprs, gps)

1.2 Qt 串口通信具体流程
- 1. 创建 QSerialPort 对象
- 2. 配置属性(波特率, 数据位, 停止, 校验位)
- 3. 打开设备
- 4. 发送数据到串口 write
- 5. 在槽函数中读取数据(当串口有数据可读的时候会发送 readyRead 信号)
1.2.1 serialapp.pro
QT += core gui serialport
1.2.2 serialapp.h
#ifndef SERIALAPP_H
#define SERIALAPP_H#include <QWidget>
#include <QSerialPort>
#include <QSerialPortInfo>
#include <QIODevice>
#include <QByteArray>
#include <QString>
#include <QDebug>QT_BEGIN_NAMESPACE
namespace Ui { class SerialApp; }
QT_END_NAMESPACEclass SerialApp : public QWidget {Q_OBJECTpublic:SerialApp(QWidget *parent = nullptr);~SerialApp();private slots:void on_openBt_clicked();void on_sendBt_clicked();void read_data();private:Ui::SerialApp *ui;// 1、创建 QSerialPort 对象QSerialPort mSerial;
};
#endif // SERIALAPP_H
1.2.3 serialapp.cpp
#include "serialapp.h"
#include "ui_serialapp.h"SerialApp::SerialApp(QWidget *parent) : QWidget(parent), ui(new Ui::SerialApp) {ui->setupUi(this);// 2、配置设备,波特率,数据位,停止位,校验位mSerial.setPortName("COM1"); // 选择对应的端口号mSerial.setBaudRate(QSerialPort::Baud115200);mSerial.setDataBits(QSerialPort::Data8);mSerial.setStopBits(QSerialPort::OneStop);mSerial.setParity(QSerialPort::NoParity);connect(&mSerial, &QSerialPort::readyRead, this, &SerialApp::read_data);
}SerialApp::~SerialApp() {delete ui;
}// 3、打开设备 (读写)
void SerialApp::on_openBt_clicked() {if (mSerial.open(QIODevice::ReadWrite)) {qDebug() << "open success!";} else {qDebug() << "open failed!";}
}// 4、发送数据到串口 write
void SerialApp::on_sendBt_clicked() {QString data = ui->textEdit->toPlainText();mSerial.write(data.toUtf8());
}// 5、读取串口数据 read
void SerialApp::read_data() {QByteArray array = mSerial.readAll();ui->textBrowser->append(QString(array));
}
1.2.4 serialapp.ui

2. Qt 虚拟串口调试
2.1 VSPD 创建虚拟串口
-
VSPD (Virtual Serial Port Driver) 是一个虚拟串口驱动程序
- 它可以模拟多个串口设备,使得应用程序可以通过虚拟串口与物理串口设备进行通信
- 使用 VSPD 可以方便地进行串口调试、数据采集、数据转发等操作
- VSPD 还支持多种协议,例如模拟 GPS 设备、模拟调制解调器、与虚拟机通信等
-
VSPD虚拟串口软件安装及使用

2.2 SecureCRT 连接虚拟串口
- SecureCRT 是一款安全的终端模拟器,常用于远程访问服务器和网络设备
- 它可以让用户通过 SSH、Telnet、Rlogin 或者串口等协议连接到远程设备,并在本地进行命令行操作
- SecureCRT 还提供了多重会话管理、脚本编写、自动登录、加密通信等多种功能
- SecureCRT安装教程

2.3 Qt 虚拟串口实现
-
serialapp.h
#ifndef SERIALAPP_H #define SERIALAPP_H#include <QWidget> #include <QSerialPort> #include <QSerialPortInfo> #include <QIODevice> #include <QByteArray> #include <QString> #include <QDebug> #include <QList>QT_BEGIN_NAMESPACE namespace Ui { class SerialApp; } QT_END_NAMESPACEclass SerialApp : public QWidget {Q_OBJECTpublic:SerialApp(QWidget *parent = nullptr);~SerialApp();private slots:void on_openBt_clicked();void on_sendBt_clicked();void read_data();private:Ui::SerialApp *ui;// 创建 QSerialPort 对象QSerialPort mSerial; }; #endif // SERIALAPP_H -
serialapp.cpp
#include "serialapp.h" #include "ui_serialapp.h"SerialApp::SerialApp(QWidget *parent) : QWidget(parent), ui(new Ui::SerialApp) {ui->setupUi(this);// 获取当前设备上的所有串口QList<QSerialPortInfo> list = QSerialPortInfo::availablePorts();for (int i = 0; i < list.size(); i++) {ui->comboBox->addItem(list.at(i).portName());}// 配置设备,波特率,数据位,停止位,校验位//mSerial.setPortName("COM1");mSerial.setBaudRate(QSerialPort::Baud115200);mSerial.setDataBits(QSerialPort::Data8);mSerial.setStopBits(QSerialPort::OneStop);mSerial.setParity(QSerialPort::NoParity);connect(&mSerial, &QSerialPort::readyRead, this, &SerialApp::read_data); }SerialApp::~SerialApp() {delete ui; }// 打开设备 (读写) void SerialApp::on_openBt_clicked() {if (mSerial.isOpen()) {mSerial.close();}mSerial.setPortName(ui->comboBox->currentText()); // 设置端口if (mSerial.open(QIODevice::ReadWrite)) {qDebug() << "open success!";} else {qDebug() << "open failed!";} }// 发送数据到串口 write void SerialApp::on_sendBt_clicked() {QString data = ui->textEdit->toPlainText();mSerial.write(data.toUtf8()); }// 读取串口数据 read void SerialApp::read_data() {QByteArray array = mSerial.readAll();ui->textBrowser->append(QString(array)); } -
serialapp.ui

2.4 Qt 与 SecureCRT 建立虚拟串口连接

3. Qt 编写串口调试工具

3.1 serialportapp.h
#ifndef SERIALPORTAPP_H
#define SERIALPORTAPP_H#include <QWidget>
#include <QSerialPort>
#include <QSerialPortInfo>
#include <QList>
#include <QStringList>
#include <QString>
#include <QIODevice>
#include <QDebug>
#include <QByteArray>
#include <QMessageBox>
#include <QTimerEvent>
#include <QFileDialog>
#include <QFile>QT_BEGIN_NAMESPACE
namespace Ui { class SerialPortApp; }
QT_END_NAMESPACEclass SerialPortApp : public QWidget {Q_OBJECTpublic:SerialPortApp(QWidget *parent = nullptr);~SerialPortApp();void timerEvent(QTimerEvent *event);private slots:void on_openBt_clicked();void on_closeBt_clicked();void on_sendBt_clicked();void on_autoCheckBox_clicked(bool checked);void on_clearSendSizeBt_clicked();void on_sendHexCb_clicked(bool checked);void on_recvHexCb_clicked(bool checked);void read_data();void on_clearRecvSizeBt_clicked();void on_selectfileBt_clicked();void on_sendfileBt_clicked();void send_file_text(quint64 size);private:Ui::SerialPortApp *ui;QSerialPort mSerial;int timerid;qint32 sendsize;qint32 recvsize;QFile file; // 发送文件qint32 sendfilesize;
};
#endif // SERIALPORTAPP_H
3.2 serialportapp.cpp
#include "serialportapp.h"
#include "ui_serialportapp.h"SerialPortApp::SerialPortApp(QWidget *parent) : QWidget(parent), ui(new Ui::SerialPortApp) {ui->setupUi(this);// 遍历获取当前设备上的所有串口QList<QSerialPortInfo> infos = QSerialPortInfo::availablePorts();for (int i = 0; i < infos.size(); i++) {ui->comCb->addItem(infos.at(i).portName());}// 设置波特率显示QStringList list;list << "1200" << "2400" << "4800" << "9600" << "19200" << "38400" << "57600" << "115200";ui->rateCb->addItems(list);ui->rateCb->setCurrentIndex(7); // 设置默认波特率为 115200list.clear();// 设置数据位list << "5" << "6" << "7" << "8" << "-1";ui->dataCb->addItems(list);ui->dataCb->setCurrentIndex(3); // 设置默认数据位为 8list.clear();// 设置停止位list << "1" << "3" << "2" << "-1";ui->stopCb->addItems(list);list.clear();// 设置校验位list << "None" << "NULL" << "Even" << "Odd" << "Space" << "Mark";ui->priCb->addItems(list);list.clear();// 把关闭按钮设置失效ui->closeBt->setEnabled(false);// 当串口有数据可读时会发送 readyRead 信号connect(&mSerial, &QSerialPort::readyRead, this, &SerialPortApp::read_data);// 初始化发送、接收的字节数记录sendsize = recvsize = 0;
}SerialPortApp::~SerialPortApp() {delete ui;
}// 打开
void SerialPortApp::on_openBt_clicked() {// 配置端口,波特率,数据位,停止位,校验位mSerial.setPortName(ui->comCb->currentText());mSerial.setBaudRate(ui->rateCb->currentText().toInt());mSerial.setDataBits((QSerialPort::DataBits)ui->dataCb->currentText().toInt());mSerial.setStopBits((QSerialPort::StopBits)ui->stopCb->currentText().toInt());mSerial.setParity((QSerialPort::Parity)ui->priCb->currentText().toInt());// 打开设备if (mSerial.open(QIODevice::ReadWrite)) {ui->closeBt->setEnabled(true);ui->openBt->setEnabled(false);}
}// 关闭
void SerialPortApp::on_closeBt_clicked() {// 关闭设备mSerial.close();ui->closeBt->setEnabled(false);ui->openBt->setEnabled(true);
}// 手动发送数据
void SerialPortApp::on_sendBt_clicked() {QString data = ui->sendText->toPlainText();if (ui->sendHexCb->isChecked()) {// 转十六进制:data = 4142 --> 0x41 0x42QByteArray array;if (data.size() % 2 != 0) {data.insert(0, '0');}for (int i = 0; i < data.size() / 2; i++) {QString t = data.mid(2*i, 2);bool ok = false;int ihex = t.toInt(&ok, 16);array.append(ihex);}int size = mSerial.write(array); // 发送数据sendsize += size; // 累计发送的字节数} else {int size = mSerial.write(data.toUtf8()); // 发送数据sendsize += size;}// 设置显示已发送的字节数ui->sendsizelabel->setText(QString::number(sendsize));
}// 定时自动发送数据
void SerialPortApp::on_autoCheckBox_clicked(bool checked) {if (checked) {// 获取定时发送周期int ms = ui->autotimeEdit->text().toInt();if (ms < 100) {QMessageBox::warning(this, "time hint", "time should > 100ms");ui->autoCheckBox->setChecked(false);return;}// 启动定时器事件timerid = this->startTimer(ms);} else {// 关闭定时器事件this->killTimer(timerid);}
}// 定时器事件
void SerialPortApp::timerEvent(QTimerEvent *event) {on_sendBt_clicked();
}// 清空已发送的字节数
void SerialPortApp::on_clearSendSizeBt_clicked() {sendsize = 0;ui->sendText->clear();ui->sendsizelabel->setText("0");
}// 发送端:十六进制和十进制转换
void SerialPortApp::on_sendHexCb_clicked(bool checked) {if (checked) { // 十进制 --> 十六进制QString data = ui->sendText->toPlainText();QByteArray array = data.toUtf8().toHex();ui->sendText->setText(QString(array));} else { // 十六进制 --> 十进制QString data = ui->sendText->toPlainText();QByteArray array;if (data.size() % 2 != 0) {data.insert(0, '0');}for (int i = 0; i < data.size() / 2; i++) {QString t = data.mid(2*i, 2);bool ok = false;int ihex = t.toInt(&ok, 16);array.append(ihex);}ui->sendText->setText(QString(array));}
}// 接收端:十六进制和十进制转换
void SerialPortApp::on_recvHexCb_clicked(bool checked) {if (checked) { // 十进制 --> 十六进制QString data = ui->recvText->toPlainText();QByteArray array = data.toUtf8().toHex();ui->recvText->setText(QString(array));} else { // 十六进制 --> 十进制QString data = ui->recvText->toPlainText();QByteArray array;if (data.size() % 2 != 0) {data.insert(0, '0');}for (int i = 0; i < data.size() / 2; i++) {QString t = data.mid(2*i, 2);bool ok = false;int ihex = t.toInt(&ok, 16);array.append(ihex);}ui->recvText->setText(QString(array));}
}// 接收串口数据
void SerialPortApp::read_data() {// 读到的数据是一个个字节QByteArray array = mSerial.readAll();recvsize += array.size(); // 显示已接收到的字节数if (ui->recvHexCb->isChecked()) {ui->recvText->append(array.toHex());} else {ui->recvText->append(array);}// 设置显示已接收到的字节数ui->recvsizelabel->setText(QString::number(recvsize));
}// 清空已接收的字节数
void SerialPortApp::on_clearRecvSizeBt_clicked() {recvsize = 0;ui->recvText->clear();ui->recvsizelabel->setText("0");
}// 选择要发送的文件
void SerialPortApp::on_selectfileBt_clicked() {QString path = QFileDialog::getOpenFileName(this);ui->filepathEdit->setText(path);
}// 发送文件
void SerialPortApp::on_sendfileBt_clicked() {// 当数据发送完毕后会发出一个信号 &QSerialPort::bytesWritten// 每当有效载荷的数据写入到设备当前的写入通道时,就会发出这个信号connect(&mSerial, &QSerialPort::bytesWritten, this, &SerialPortApp::send_file_text);// 打开文件file.setFileName(ui->filepathEdit->text());if (!file.open(QIODevice::ReadOnly)) {return;}// 获取文件大小int filesize = file.size();ui->progressBar->setMaximum(filesize);// 设置进度条显示QByteArray array = file.read(128); // 每次读取 128 字节内容sendfilesize = mSerial.write(array);ui->progressBar->setValue(sendfilesize);
}// 循环(每 128 字节)发送文件
void SerialPortApp::send_file_text(quint64 size) {// 设置进度条显示QByteArray array = file.read(128);quint64 mSize = mSerial.write(array);sendfilesize += mSize;ui->progressBar->setValue(sendfilesize);// 判断文件是否发送完毕if (sendfilesize == ui->progressBar->maximum()) {file.close();disconnect(&mSerial, &QSerialPort::bytesWritten, this, &SerialPortApp::send_file_text);}
}
3.3 serialportapp.ui

相关文章:
Qt 串口编程-从入门到实战
1. Qt 串口通信流程解析 1.1 串行通信和并行通信对比 并行通信适合距离较短的通信,且信号容易受干扰,成本高串口通讯-设备(蓝牙, wifi, gprs, gps) 1.2 Qt 串口通信具体流程 1. 创建 QSerial…...
如何获得微软MVP徽章
要成为微软MVP,需要在特定领域成为专家,并积极参与社区,为其他人提供帮助和支持。以下是一些步骤可以帮助你成为MVP: 在特定领域成为专家:要成为MVP,需要在某个领域具有专业知识和经验。这可以通过阅读相关…...
Java架构师软件架构开发
目录 1 基于架构的软件开发导论2 ABSD架构方法论3 ABSD方法论具体实现4 ABSD金融业案例5 基于特定领域的软件架构开发导论6 DSSA领域分析7 DSSA领域设计和实现8 DSSA国际电商平台架构案例9 架构思维方法论概述10 AT方法论和案例想学习架构师构建流程请跳转:Java架构师系统架构…...
西南科技大学数字电子技术实验一(数字信号基本参数与逻辑门电路功能测试及FPGA 实现 )预习报告
手写报告稍微认真点写,80+随便有 目录 一、计算/设计过程 1、通过虚拟示波器观察和测量信号 2、通过实际电路(电阻、开关、发光二极管)模拟逻辑门电路 二、画出并填写实验指导书上的预表...
Java八股文面试全套真题【含答案】- SpringMVC篇
以下是一些关于Spring MVC语言的经典面试题以及它们的答案: 什么是Spring MVC框架?它的特点是什么? Spring MVC是基于Java的一种Web应用框架,用于开发基于MVC(模型-视图-控制器)模式的Web应用程序。它的特…...
Spring第二课响应的完全,如何理解前后端互联
目录 一、响应 Control,RestController 1.Controller的源码,代表什么意思 2.返回数据 Responsebody 3.返回HTML片段 4.返回JSON 5.那么假如我们使用集合会怎么样呢 设置状态码,虽然不影响展示,但是确实显示起来也就是401的情况。 2.我…...
html实现各种瀑布流(附源码)
文章目录 1.设计来源1.1 动态响应瀑布流1.2 分页瀑布流1.3 响应瀑布流 2.效果和源码2.1 动态效果2.2 源代码 源码下载 作者:xcLeigh 文章地址:https://blog.csdn.net/weixin_43151418/article/details/134613121 html实现各种瀑布流(附源码),…...
万字解析设计模式之责任链模式、状态模式
目录 一、责任链模式 1.1概述 1.2结构 1.3实现 1.4 优缺点 1.5应用场景 1.6源码解析 二、状态模式 2.1概述 2.2结构 2.3实现 2.4优缺点 2.5应用场景 三、责任链模式实验 任务描述 实现方式 编程要求 测试说明 四、状态模式实验 任务描述 实现方式 编程要…...
二十三种设计模式全面解析-深入探讨状态模式的高级应用技术:释放对象行为的无限可能
在软件开发中,状态管理是一个常见的挑战。当对象的行为随着内部状态的变化而变化时,有效地管理对象的状态和相应的行为变得至关重要。在这方面,状态模式提供了一种优雅而灵活的解决方案。它允许对象在运行时根据内部状态的改变而改变其行为&a…...
论文笔记--Toolformer: Language Models Can Teach Themselves to Use Tools
论文笔记--Toolformer: Language Models Can Teach Themselves to Use Tools 1. 文章简介2. 文章概括3 文章重点技术3.1 Toolformer3.2 APIs 4. 文章亮点5. 原文传送门 1. 文章简介 标题:Toolformer: Language Models Can Teach Themselves to Use Tools作者&#…...
stm32实现0.96oled图片显示,菜单功能
stm32实现0.96oled图片显示,菜单功能 功能展示简介代码介绍oled.coled.holedfont.h(字库文件)main函数 代码思路讲解 本期内容,我们将学习0.96寸oled的进阶使用,展示图片,实现菜单切换等功能,关…...
sqlite外键约束 保证数据一致性
1. 外键约束 在SQLite中,可以通过使用外键(Foreign Key)约束和CASCADE选项来实现通过外键删除相关信息。 CASCADE选项是指在主键表中删除记录时,相应的外键表中的相关记录也将被自动删除。 -- 创建主键表 CREATE TABLE Persons…...
Vue轻松入门,附带学习笔记和相关案例
目录 案例 一Vue基础 什么是Vue? 补充:mvvm框架 mvvm的组成 详解 Vue的使用方法 1.直接下载并引入 2.通过 CDN 使用 Vue 3.通过npm安装 4.使用Vue CLI创建项目 二插值表达式 什么是插值表达式? 插值表达式的缺点 解决方法 …...
【青蛙跳台阶问题 —— (三种算法)】
青蛙跳台阶问题 —— (三种算法) 一.题目介绍1.1.题目1.2.图示 二.解题思路三.题解及其相关算法3.1.递归分治法3.2.动态规划算法(Dynamic Programming)3.3.斐波那契数列法 四.注意细节 一.题目介绍 1.1.题目 一只青蛙一次可以跳上1级台阶&am…...
联想yoga AMD处理器 转接头无法电量外接显示器
第一次买AMD的处理器,当时就是为了yogaAMD这款的接口要比英特尔的接口多,没想到AMD处理器真的问题多。经常蓝屏不说,偶尔还点不亮外接显示器。遇到这种问题,不是什么驱动问题,可能你按照网上各种方法打开设备管理器→显…...
OSG粒子系统与阴影 - 阴影shadow(7)
OSG阴影 在虚拟现实仿真中,为了真实地模拟自然效果,阴影效果是不可缺少的,它对一个场景的真实性是非常重要的。在游戏或仿真中,一个高效的阴影往往能够提供非常强悍的视觉真实感。 osgShadow库 在OSG中专门定义了一个名字空间osg…...
vue3项目中使用富文本编辑器
前言 适配 Vue3 的富文本插件不多,我看了很多插件官网,也有很多写的非常棒的,有UI非常优雅让人耳目一新的,也有功能非常全面的。 如: Quill,简单易用,功能全面。editorjs,UI极其优…...
Java EE 进程线程
JavaEE 进程&线程 文章目录 JavaEE 进程&线程1. 进程1.1 概念1.2 进程管理1.3 PCB (Process Control Block) 2. 线程2.1 概念2.1 线程与进程的区别2.3 创建线程 1. 进程 1.1 概念 什么是进程? 进程是操作系统对一个正在执行的程序的一种抽象 我们可以打开…...
GPT写SQL的模版
表:profit_loss_sum_m_snapshot 计算字段:成本cost_whole求和,收入income_whole求和,收入求和-成本求和,成本目标cost_target求和,收入求和-成本目标求和 条件:日期statis_date在2023-11-01&…...
蓝桥杯官网练习题(平均)
问题描述 有一个长度为 n 的数组( n 是 10 的倍数),每个数 ai 都是区间 [0,9] 中的整数。小明发现数组里每种数出现的次数不太平均,而更改第 i 个数的代价为 bi,他想更改若干个数的值使得这 10 种数出现的次数相等…...
AI驱动的下一代云ERP:SAP Cloud ERP 2602 更新亮点小结
大家好,SAP Cloud ERP 2602版本更新了!2602的一个核心特点,是在保持标准化 SaaS 的前提下,将“嵌入式 AI 自然语言交互 Agentic AI”有机结合,让用户可以在熟悉的业务流程中,以对话方式完成信息查询、数据…...
Nucleus Co-Op:如何让单机游戏秒变本地多人分屏神器?
Nucleus Co-Op:如何让单机游戏秒变本地多人分屏神器? 【免费下载链接】nucleuscoop Starts multiple instances of a game for split-screen multiplayer gaming! 项目地址: https://gitcode.com/gh_mirrors/nu/nucleuscoop 还在为找不到合适的本…...
OpenTiny NEXT 从入门到精通·第 1 篇
OpenTiny NEXT 从入门到精通第 1 篇:启程篇——初识 OpenTiny NEXT,开启企业级智能前端之旅前端技术日新月异,Vue 2 要停止维护了,团队还在 Vue 2/3 多版本并存中挣扎;业务方希望接入 AI,前端却不知道怎么开…...
OpenClaw + Ollama 超时 500 错误排查与解决:调整上下文窗口与最大生成长度
一次因为模型参数配置不当引发的“跨设备推理慢如蜗牛”问题,最终通过降低 contextWindow 和 maxTokens 轻松搞定。背景 最近在一台轻薄本做测验, Windows 环境下折腾 OpenClaw 对接本地 Ollama 的 Qwen2.5:1.5B 模型。本以为小参数量模型跑起来毫无压力…...
OpenClaw技能推荐:百川2-13B-4bits最适合的5个办公自动化技能
OpenClaw技能推荐:百川2-13B-4bits最适合的5个办公自动化技能 1. 为什么选择百川2-13B-4bits作为办公自动化引擎 去年冬天,当我第一次尝试用OpenClaw对接各种开源模型时,发现大多数13B参数级别的模型都需要至少24GB显存。直到遇到百川2-13B…...
SEO 优化师如何处理网站收录和排名下降的问题
SEO 优化师如何处理网站收录和排名下降的问题 在数字营销中,SEO(搜索引擎优化)是一个至关重要的环节,尤其是对于那些希望在百度上获得高排名和流量的网站。即使是最优秀的SEO策略,也可能会在某些时候面临网站收录和排…...
OpenClaw多模态实践:Qwen3.5-9B解析截图中的图表数据
OpenClaw多模态实践:Qwen3.5-9B解析截图中的图表数据 1. 为什么需要自动化图表解析 科研工作中最耗时的环节之一,就是手动从论文图表中提取数据点。我曾为了一篇综述文章,花了整整三天时间从30多张折线图中抄录数据。这种重复劳动不仅效率低…...
【安全心法】别用定时器喂狗!撕碎看门狗的伪安全面具,直面“僵尸系统”的物理绞肉机
摘要:在硬实时控制系统中,硬件看门狗被奉为防止系统死机的终极神明。但无数软硬件工程师出于偷懒或对底层架构的无知,将“喂狗”动作外包给了高频的定时器中断或最高优先级的独立任务。本文将彻底摒弃代码,纯粹从系统架构的安全哲…...
深入解析CAN报文中的Motorola字节排序:MSB与LSB的实战对比
1. 从汽车仪表盘说起:为什么需要了解CAN字节排序 去年调试一辆新能源车的仪表盘时,我遇到了一个诡异现象:车速显示在80km/h时突然跳变成20km/h。排查三天后发现,问题出在CAN报文解析时搞混了Motorola的MSB和LSB排序方式。这个经历…...
别再死记硬背公式!用Python可视化理解数字基带信号功率谱(含代码)
用Python动态解析数字基带信号功率谱:从公式到视觉直觉的跨越 通信原理课程中那些晦涩的公式是否曾让你望而生畏?特别是当教授在黑板上推导数字基带信号功率谱密度时,那一连串的δ函数和Sa函数让人头晕目眩。本文将通过Python代码实现一个交互…...
