QT串口接收数据并进行波形显示(含源码)

news2024/11/18 14:50:07

**使用QT在串口调试助手基础上实现波形显示(含源码)

评论比较多留言需要源码的,逐个发邮箱比较麻烦也不能及时回复,现将源码上传至链接(无需积分下载)https://download.csdn.net/download/m0_51294753/87743394,下载不下来可以私信我留邮箱。

一、前言

背景:使用ADS1255对模拟信号进行采样,并将转换的数据通过串口发送给电脑,使用QT编写上位机软件接收串口数据并实现采样波形的显示。因为没有具体的需求,只是进行简单测试,程序不尽完善,简单记录一下过程,方便刚接触的同伴一起学习。

二、测试效果

界面是在串口助手基础上改的,具有串口调试助手的基本功能,加了一个折线图显示,但是重新整理了上次串口的程序,显示效果如下:

20230302_104834

在这里插入图片描述

采样的板子设计的不太好,模拟输入端开路时本底噪声基本在0.6mV左右,设计输入电压是±2.5V。采用的串口输入,波特率为1500000,输入的数据具有固定的格式,数据输入形式如下:

在这里插入图片描述
三、实现过程遇到的问题

使用QT的serialport 和 charts库,简单过程不再说明,源程序在文末给出,下面简述一下我在实现中遇到的问题:

1.串口的定时扫描和串口名更新

原本只在程序开始时进行串口扫描,但随后发现如果设备在程序运行后就检测不到串口,串口如果被占用也得不到更新。通过定时器和关联槽函数来定时(500ms)扫描串口,但是串口禁用那行代码还没整明白是怎么回事(有知道的欢迎在评论区告诉我),具体实现看源代码。

for(int i = 0;i<portStringList.size();i++)
{
    serial->setPortName(portStringList[i]);
    if(serial->open(QIODevice::ReadWrite))
        ui->comboSerialPort->addItem(portStringList.at(i));
    else
    {
        ui->comboSerialPort->addItem(portStringList.at(i) + "(不可用)");
        ui->comboSerialPort->setItemData(i,(QVariant)0,Qt::UserRole-1);     //串口禁用??
    }
    serial->close();
}

2.图表显示的内容需要移动,类似示波器的显示波形

对于横坐标,我是通过固定横坐标时间的宽度,改变横坐标的坐标范围来实现的,比如数据输出速率为10,固定横坐标只显示50个点,则设置横坐标宽度为5。

    t += 0.1;
    qreal value = valueStr.toDouble();
    serices0->append(t,value);
    if(t>50)
        axisX->setRange(t-50,t);

对于纵坐标,通过一个链表把图表显示的50个数据存储起来,再用类似队列的方式先入先出的方式更新队列,找出队列的最大值和最小值更新纵坐标的坐标范围

    if(listvalue.size()<=500)
        listvalue.push_front(value);
    else
    {
        listvalue.pop_back();
        listvalue.push_front(value);
    }
    qreal minvalue = *std::min_element(listvalue.begin(),listvalue.end());
    qreal maxvalue = *std::max_element(listvalue.begin(),listvalue.end());
    axisY->setRange(minvalue-0.00001,maxvalue+0.00001);

3.把数据从发送的字符串中截取出来显示

没想到太好的办法,目前是需要注意发送字符串的形式,按着字符串形式更改程序,比如下位机发送的类型是value:0.0000000V,可以利用字符串截取函数把中间的数据单独拿出来,因为我下位机发送的数据宽度固定,所以我是使用mid()函数直接截取,如果长度 不一致,也可以用split()函数将数据与文本割裂开。

    receiveBuff = serial->readAll();
    receiveBytes += receiveBuff.length();
    QByteArray valueStr;
    valueStr = receiveBuff.mid(QString("value:").size(),QString("-0.000000").size());

4.设置坐标轴的问题

给图表中序列赋坐标轴的时候常用到这样一段代码

chart->setAxisX(axisX,serices0);
chart->setAxisY(axisY,serices0);

但一般都会警告该代码已过时,推荐使用addAxis()函数替代,于是改成

chart->addAxis((QAbstractAxis*)axisX,Qt::AlignBottom);
chart->addAxis((QAbstractAxis*)axisY,Qt::AlignLeft);

黄色警告消失了,编译也没有错误,但是运行起来坐标轴有些许问题,还没明白怎么回事。

四、程序代码

1.pro项目文件,主要是添加两行核心库和资源文件

QT       += core gui
QT       += serialport
QT       += charts

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++11

# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
    main.cpp \
    mainwindow.cpp

HEADERS += \
    mainwindow.h

FORMS += \
    mainwindow.ui

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

RESOURCES += \
    res.qrc

2.ui设计文件,按照自己需求布局,给控件命名
在这里插入图片描述
3.h文件,一些变量和函数声明

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QtCharts>
#include <QSerialPort>
#include <QSerialPortInfo>
#include <QStringList>
#include <QMessageBox>
#include <QFileDialog>
#include <QList>

using namespace QtCharts;

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private:
    Ui::MainWindow *ui;

private:
    qreal t;
    QChart *chart;
    QLineSeries *serices0;
    QValueAxis *axisX,*axisY;
    QSerialPort *serial;                        //串口端口
    QStringList portStringList;                 //端口链表
    QTimer *timer;                              //定时器
    QByteArray sendBuff,receiveBuff;            //发送、接收缓存区
    long int sendBytes,receiveBytes;            //发送、接收字节数
    QList <qreal>  listvalue;

    void InitSerialPort();
    void InitChart();

private slots:
    void serialPort_readyRead();
    void portTimerEvent();

    void on_btnOpenSerial_clicked();
    void on_btnSend_clicked();
    void on_btnClearRevBuff_clicked();
    void on_btnSaveFile_clicked();
    void on_btnOpenFile_clicked();
    void on_btnClearSendBuff_clicked();
    void on_btnResetCount_clicked();
    void on_chkFixedSend_clicked();
    void on_lineEditTime_editingFinished();
    void on_textEditRev_textChanged();
};
#endif // MAINWINDOW_H

4.c文件,函数功能实现

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    t = 0;
    sendBytes = 0;
    receiveBytes = 0;

    chart = new QChart();
    serices0 = new QLineSeries();
    axisX = new QValueAxis();
    axisY = new QValueAxis();
    timer = new QTimer();
    serial = new QSerialPort(this);
    QTimer *portTimer = new QTimer(this);
    connect(portTimer,SIGNAL(timeout()),this,SLOT(portTimerEvent()));
    connect(serial,SIGNAL(readyRead()),this,SLOT(serialPort_readyRead()));

    InitSerialPort();
    InitChart();

    portTimer->start(500);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::InitSerialPort()
{
    ui->comboSerialPort->clear();
    portStringList.clear();
    foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts())
        portStringList += info.portName();
    for(int i = 0;i<portStringList.size();i++)
    {
        serial->setPortName(portStringList[i]);
        if(serial->open(QIODevice::ReadWrite))
            ui->comboSerialPort->addItem(portStringList.at(i));
        else
        {
            ui->comboSerialPort->addItem(portStringList.at(i) + "(不可用)");
            ui->comboSerialPort->setItemData(i,(QVariant)0,Qt::UserRole-1);     //串口禁用??
        }
        serial->close();
    }
    ui->comboBaudRate->setCurrentIndex(5);
    ui->comboDataBits->setCurrentIndex(3);
    ui->comboParity->setCurrentIndex(2);
    ui->comboStop->setCurrentIndex(0);

    ui->btnSend->setEnabled(false);
    ui->chkFixedSend->setEnabled(false);
    ui->lineEditTime->setEnabled(false);

    ui->lineEditTime->setText("1000");
    ui->radioTextReceive->setChecked(Qt::Checked);
    ui->radioTextSend->setChecked(Qt::Checked);
}

void MainWindow::InitChart()
{
    ui->chartView->setChart(chart);
    QMargins mgs(5,5,5,5);
    chart->setMargins(mgs);
    chart->setTitle("数据曲线");

    //创建折线序列
    serices0->setName("时间-电压曲线");
    chart->addSeries(serices0);

    //创建坐标轴
    axisX->setRange(0,5);
    axisX->setTitleText("time(secs)");

    axisY->setRange(-2,2);
    axisY->setTitleText("value");

    chart->setAxisX(axisX,serices0);
    chart->setAxisY(axisY,serices0);

   //chart->addAxis((QAbstractAxis*)axisX,Qt::AlignBottom);
   //chart->addAxis((QAbstractAxis*)axisY,Qt::AlignLeft);
}

void MainWindow::serialPort_readyRead()
{
    QByteArray lastStr;
    if(!ui->radioStopReceive->isChecked())
    {
        lastStr = ui->textEditRev->toPlainText().toUtf8();
        receiveBuff = serial->readAll();
        receiveBytes += receiveBuff.length();

        QByteArray valueStr;
        valueStr = receiveBuff.mid(QString("value:").size(),QString("-0.000000").size());

        t += 0.1;
        qreal value = valueStr.toDouble();
        serices0->append(t,value);

        if(t>50)
            axisX->setRange(t-50,t);

        if(listvalue.size()<=500)
            listvalue.push_front(value);
        else
        {
            listvalue.pop_back();
            listvalue.push_front(value);
        }
        qreal minvalue = *std::min_element(listvalue.begin(),listvalue.end());
        qreal maxvalue = *std::max_element(listvalue.begin(),listvalue.end());
        axisY->setRange(minvalue-0.00001,maxvalue+0.00001);


        ui->labRevBytesCount->setText(QString::number(receiveBytes));

        if(ui->radioHexReceive->isChecked())
        {
            receiveBuff = receiveBuff.toHex().toUpper();
            int length = receiveBuff.length();
            for(int i = 0;i<=length/2;i++)
                receiveBuff.insert((2+3*i), QByteArray(" "));
        }
        lastStr = lastStr.append(receiveBuff);
        ui->textEditRev->setText(lastStr);
    }
    else
        serial->clear(QSerialPort::Input);
}

void MainWindow::portTimerEvent()
{
    QStringList newPortStringList;
    newPortStringList.clear();
    foreach(const QSerialPortInfo &info,QSerialPortInfo::availablePorts())
        newPortStringList += info.portName();
    if(newPortStringList.size() != portStringList.size())
    {
        portStringList = newPortStringList;
        ui->comboSerialPort->clear();
        ui->comboSerialPort->addItems(portStringList);
    }
}


void MainWindow::on_btnOpenSerial_clicked()
{
    if(ui->btnOpenSerial->text() == QString("打开串口"))
    {
        //串口设置
        serial->setPortName(ui->comboSerialPort->currentText());
        serial->setBaudRate(ui->comboBaudRate->currentText().toInt());
        switch(ui->comboDataBits->currentText().toInt())
        {
        case 5: serial->setDataBits(QSerialPort::Data5);break;
        case 6: serial->setDataBits(QSerialPort::Data6);break;
        case 7: serial->setDataBits(QSerialPort::Data7);break;
        case 8: serial->setDataBits(QSerialPort::Data8);break;
        default: serial->setDataBits(QSerialPort::UnknownDataBits);
        }
        switch(ui->comboParity->currentIndex())
        {
        case 0: serial->setParity(QSerialPort::EvenParity);break;
        case 1: serial->setParity(QSerialPort::MarkParity);break;
        case 2: serial->setParity(QSerialPort::NoParity);break;
        case 3: serial->setParity(QSerialPort::OddParity);break;
        default: serial->setParity(QSerialPort::UnknownParity);
        }
        switch (ui->comboStop->currentIndex())
        {
        case 0: serial->setStopBits(QSerialPort::OneStop);break;
        case 1: serial->setStopBits(QSerialPort::OneAndHalfStop);break;
        case 2: serial->setStopBits(QSerialPort::TwoStop);break;
        default: serial->setStopBits(QSerialPort::UnknownStopBits);
        }

        serial->setFlowControl(QSerialPort::NoFlowControl);

        if(!serial->open(QIODevice::ReadWrite))
        {
            QMessageBox::warning(this,"提示","无法打开串口",QMessageBox::Ok);
            return;
        }

        ui->comboSerialPort->setEnabled(false);
        ui->comboBaudRate->setEnabled(false);
        ui->comboDataBits->setEnabled(false);
        ui->comboParity->setEnabled(false);
        ui->comboStop->setEnabled(false);

        ui->btnSend->setEnabled(true);
        ui->chkFixedSend->setEnabled(true);
        ui->lineEditTime->setEnabled(true);
        ui->btnOpenSerial->setText("关闭串口");
    }
    else
    {
        serial->close();

        ui->comboSerialPort->setEnabled(true);
        ui->comboBaudRate->setEnabled(true);
        ui->comboDataBits->setEnabled(true);
        ui->comboParity->setEnabled(true);
        ui->comboStop->setEnabled(true);

        ui->btnSend->setEnabled(false);
        ui->chkFixedSend->setEnabled(false);
        ui->lineEditTime->setEnabled(false);
        ui->btnOpenSerial->setText("打开串口");
    }
}


void MainWindow::on_btnSend_clicked()
{
    sendBuff = ui->textEditSend->toPlainText().toUtf8();
    if(ui->radioHexSend->isChecked())
        sendBuff = QByteArray::fromHex(sendBuff);
    if(ui->chkLineFeed->isChecked())
        sendBuff += '\n';
    serial->write(sendBuff);
    sendBytes += sendBuff.length();
    ui->labSendBytesCount->setText(QString::number(sendBytes));
    ui->textEditSend->moveCursor(QTextCursor::End);
}


void MainWindow::on_btnClearRevBuff_clicked()
{
    ui->textEditRev->clear();
}


void MainWindow::on_btnSaveFile_clicked()
{
    QString curPath = QDir::currentPath();
    QString dlgTilte = "保存文件";
    QString filter = "文本文件(*.txt);;所有文件(*.*)";
    QString fileName = QFileDialog::getSaveFileName(this,dlgTilte,curPath,filter);
    if(fileName.isEmpty())
        return;
    QFile file(fileName);
    if(!file.open(QIODevice::ReadWrite | QIODevice::Text))
        QMessageBox::warning(this,"文档编辑器",tr("无法写入文件 %1:\n%2").arg(fileName,file.errorString()));
    QTextStream stream(&file);
    stream.setAutoDetectUnicode(true);
    stream<<ui->textEditRev->toPlainText().toUtf8();
    file.close();
}


void MainWindow::on_btnOpenFile_clicked()
{
    QString curPath = QDir::currentPath();
    QString dlgTilte = "打开文件";
    QString filter = "文本文件(*.txt);;所有文件(*.*)";
    QString fileName = QFileDialog::getOpenFileName(this,dlgTilte,curPath,filter);
    if(fileName.isEmpty())
        return;
    QFile file(fileName);
    if(!file.open(QIODevice::ReadWrite | QIODevice::Text))
        QMessageBox::warning(this,"文档编辑器",tr("无法读取文件 %1:\n%2").arg(fileName,file.errorString()));
    ui->textEditSend->setText(file.readAll());
    file.close();
}


void MainWindow::on_btnClearSendBuff_clicked()
{
    ui->textEditSend->clear();
}


void MainWindow::on_btnResetCount_clicked()
{
    receiveBytes = 0;
    sendBytes = 0;
    ui->labRevBytesCount->setText(QString::number(receiveBytes));
    ui->labSendBytesCount->setText(QString::number(sendBytes));
}


void MainWindow::on_chkFixedSend_clicked()
{
    if(ui->chkFixedSend->isChecked())
    {
        int fixedTime = ui->lineEditTime->text().toInt();
        timer->start(fixedTime);
        connect(timer,SIGNAL(timeout()),this,SLOT(on_btnSend_clicked()));
    }
    else
    {
        timer->stop();
    }
}


void MainWindow::on_lineEditTime_editingFinished()
{
    on_chkFixedSend_clicked();
}


void MainWindow::on_textEditRev_textChanged()
{
    ui->textEditRev->moveCursor(QTextCursor::End);
}

程序基本框架和上一篇发文的基于QT5实现串口调试助手没太大区别,只是修改了一下控件的命名便于理解,把上次冗余的部分代码变简洁一下,加入了图表。程序需要自行理解修改一下才能运行,否则下位机发来的数据与此次字符串格式不一致会使程序发生错误或强制退出。刚入门还存在诸多问题,请各位见谅。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1112919.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Jupyter Notebook 设置黑色背景主题

Jupyter Notebook 设置黑色背景主题 # 包安装 pip install jupyterthemes -i https://mirrors.aliyun.com/pypi/simple pip install --upgrade jupyterthemes # 查看可用主题 jt -l # monokai暗背景&#xff0c;-f(字体) -fs(字体大小) -cellw(占屏比或宽度) -ofs(输出段的字…

自己DIY一个模拟多按钮电路

普通按键电路原理&#xff1a; 一般使用的按键原理图如下图所示&#xff0c;由按键、上拉电阻和消抖滤波电容组成。按键断开时KeyIin1处电压被上拉到5V&#xff0c;当按键闭合时把KeyIin1电压拉到0V&#xff0c;与按键并联的电容起到滤除按键按下与弹起时的高频信号。 如果在电…

让uniGUI支持https

今天在专家的帮助下&#xff0c;成功的让uniGUI支持https了。 首先&#xff0c;去申请个**的证书。我同事去阿里申请的&#xff0c;申请回是一个zip文件&#xff0c;里面有两个文件&#xff0c;一个扩展是per&#xff0c;一个key 然后&#xff0c;把这两个证书文件放到uniGUI…

【LeetCode】48. 旋转图像

1 问题 给定一个 n n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。 你必须在 原地 旋转图像&#xff0c;这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,2,3],[4,5,6],[7,8…

京东数据平台(京东数据分析)2023年9月京东冰箱行业品牌销售排行榜!

鲸参谋监测的京东平台9月份冰箱市场销售数据已出炉&#xff01; 9月份&#xff0c;大家电行业整体下滑&#xff0c;而冰箱作为大家电市场中的重点品类&#xff0c;受行业趋势变动的影响&#xff0c;冰箱销售市场也同样下滑。鲸参谋数据显示&#xff0c;9月在京东平台上&#xf…

浏览器下载打开java文件 出现一般异常错误提示你的安全设置已阻止自签名应用程序

环境&#xff1a; win10专业版 谷歌浏览器 问题描述&#xff1a; 浏览器下载打开java文件 提示你的安全设置已阻止自签名应用程序 解决方案&#xff1a; 1.打开控制&#xff0c;面板找到java 找到安全 &#xff0c; 将安全级别调至“中” 2.把例外站点也添加一下 3.重启…

总结关于计算机msvcp120.dll丢失的解决方法

在计算机的使用过程中&#xff0c;我们可能会遇到各种各样的问题&#xff0c;其中之一就是“msvcp120.dll文件丢失”。这是一个非常常见的问题&#xff0c;可能会影响到许多软件的正常运行。本文将详细介绍6种不同的解决方法&#xff0c;帮助大家解决这个问题。 首先&#xff…

No valid NAT64 prefix

As an AI language model, I do not have access to your network configuration or settings. However, in general, the error message “No valid NAT64 prefix” indicates that there is a problem with the configuration of IPv6 to IPv4 translation. NAT64 is a mech…

深度剖析数据在计算机内存中的存储

本章重点 1.计算机中数据类型详细介绍 2.整形在内存中的存储方式 3.大小端字节序介绍以及判断方法 1. 数据类型详细介绍 C语言中我们学习的内置类型数据有以下几种。 类型数据类型名称占用内存空间字节char 字符数据类型 1short 短整型 2int 整形 4long 长整型 4long long …

09 创建型模式-建造者模式

1.建造者模式介绍&#xff1a; 建造者模式 (builder pattern), 也被称为生成器模式 , 是一种创建型设计模式 定义: 将一个复杂对象的构建与表示分离&#xff0c;使得同样的构建过程可以创建不 同的表示。 2.建造者模式要解决的问题 建造者模式可以将部件和其组装过程分开&am…

SLAM从入门到精通(构建自己的slam包)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 我们学习了很多的开源包&#xff0c;比如hector、gmapping。但其实我们也可以自己编写一个slam包。这么做最大的好处&#xff0c;主要还是可以帮助…

【会议征稿通知】第三届大数据经济与数字化管理国际学术会议(BDEDM 2024)

2024 3rd International Conference on Big Data Economy and Digital Management 第三届大数据经济与数字化管理国际学术会议&#xff08;BDEDM 2024&#xff09; 第三届大数据经济与数字化管理国际学术会议&#xff08;BDEDM 2024&#xff09;将于2024年1月12-14日于宁波召…

分布式Trace:横跨几十个分布式组件的慢请求要如何排查?

目录 前言 一、问题的出现&#xff1f; 二、一体化架构中的慢请求排查如何做 三、分布式 Trace原理 四、如何来做分布式 Trace 前言 在分布式服务架构下&#xff0c;一个 Web 请求从网关流入&#xff0c;有可能会调用多个服务对请求进行处理&#xff0c;拿到最终结果。这个…

AGI热门方向:国内前五!AI智能体TARS-RPA-Agent落地,实在智能打造人手一个智能助理

早在 1950 年代&#xff0c;Alan Turing 就将「智能」的概念扩展到了人工实体&#xff0c;并提出了著名的图灵测试。这些人工智能实体通常被称为 —— 代理&#xff08;Agent&#xff09;。 代理这一概念起源于哲学&#xff0c;描述了一种拥有欲望、信念、意图以及采取行动能力…

SystemVerilog Assertions应用指南 Chapter1.33 在蕴含中使用 if/else

SVA允许在使用蕴含的属性的后续算子中使用“if/else”语句。 属性 p_if_else检査如果信号“ start”的下降沿被检测到,就是个有效开始,接着一个时钟周期后,信号“a”或者信号“b”为高。在现行算子成功匹配时,后续算子有两个可能的路径。 1.如果信号“a”为高,…

javaEE - 2(11000字详解多线程)

一&#xff1a;多线程带来的的风险-线程安全 线程安全的概念&#xff1a;如果多线程环境下代码运行的结果是符合我们预期的&#xff0c;即在单线程环境应该的结果&#xff0c;则说这个程序是线程安全的。 当多个线程同时访问共享资源时&#xff0c;就会产生线程安全的风险&am…

PHP的学习入门建议

学习入门PHP的步骤如下&#xff1a; 确定学习PHP的目的和需求&#xff0c;例如是为了开发网站还是为了与数据库交互等。学习PHP的基础语法和程序结构&#xff0c;包括变量、数据类型、循环、条件等。学习PHP的面向对象编程&#xff08;OOP&#xff09;概念和技术。学习与MySQL…

1811_spacemacs从v.0.200.13升级到v.0.200.14的几点变化感受

全部学习汇总&#xff1a; GreyZhang/editors_skills: Summary for some common editor skills I used. (github.com) 安装了全新的spacemacs的配置&#xff0c;查看了一下版本是v.0.200.14。在此之前&#xff0c;我使用的版本是v.0.200.13。现在还没有在这个配置上完成我所有的…

win32汇编-使用子程序

当程序中相同功能的一段代码用得比较频繁时&#xff0c;可以将它分离出来写成一个子程序&#xff0c;在主程序中用call指令来调用它。这样可以不用重复写相同的代码&#xff0c; 仅仅用call指令就可以完成多次同样的工作了。Win 32汇编中的子程序也采用堆栈来传递参数&#xff…

【小黑嵌入式系统第四课】嵌入式系统硬件平台(二)——I/O设备、通信设备(UARTUSB蓝牙)、其他(电源时钟复位中断)

上一课&#xff1a; 【小黑嵌入式系统第三课】嵌入式系统硬件平台&#xff08;一&#xff09;——概述、总线、存储设备&#xff08;RAM&ROM&FLASH) 文章目录 一、I/O设备1. 定时器/计数器2. ADC和DAC3. 人机接口设备3.1 键盘3.2 LCD显示器3.3 触摸屏 二、通信设备1. 通…