IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 串口&网口&内存拷贝通讯demo by QT -> 正文阅读

[C++知识库]串口&网口&内存拷贝通讯demo by QT

功能均已在windows下经过测试

串口通讯

pro文件需要添加serialport
在这里插入图片描述
初始化代码,包括ui

QSerialPort *serial;
QString m_strComName;
int m_iBaudRate;
int m_iDataBit;
QString m_strParity;
QString m_strStopBit;
QString m_strFlowBit;
QList<QString> *m_strRecvList;


serial = new QSerialPort;
QString description;
QString manufacturer;
QString serialNumber;
//获取可以用的串口
QList<QSerialPortInfo> serialPortInfos = QSerialPortInfo::availablePorts();
//输出当前系统可以使用的串口个数
//qDebug() << "Total numbers of ports: " << serialPortInfos.count();
//将所有可以使用的串口设备添加到ComboBox中
for (const QSerialPortInfo &serialPortInfo : serialPortInfos)
{
    QStringList list;
    description = serialPortInfo.description();
    manufacturer = serialPortInfo.manufacturer();
    serialNumber = serialPortInfo.serialNumber();
    list << serialPortInfo.portName()
         << (!description.isEmpty() ? description : blankString)
         << (!manufacturer.isEmpty() ? manufacturer : blankString)
         << (!serialNumber.isEmpty() ? serialNumber : blankString)
         << serialPortInfo.systemLocation()
         << (serialPortInfo.vendorIdentifier() ? QString::number(serialPortInfo.vendorIdentifier(), 16) : blankString)
         << (serialPortInfo.productIdentifier() ? QString::number(serialPortInfo.productIdentifier(), 16) : blankString);
    ui->cbCom->addItem(list.first(), list);
}
//设置波特率
ui->cbRate->addItem(QStringLiteral("9600"), QSerialPort::Baud9600);
ui->cbRate->addItem(QStringLiteral("19200"), QSerialPort::Baud19200);
ui->cbRate->addItem(QStringLiteral("38400"), QSerialPort::Baud38400);
ui->cbRate->addItem(QStringLiteral("115200"), QSerialPort::Baud115200);
ui->cbRate->addItem(tr("Custom"));
//设置数据位
ui->cbData->addItem(QStringLiteral("5"), QSerialPort::Data5);
ui->cbData->addItem(QStringLiteral("6"), QSerialPort::Data6);
ui->cbData->addItem(QStringLiteral("7"), QSerialPort::Data7);
ui->cbData->addItem(QStringLiteral("8"), QSerialPort::Data8);
ui->cbData->setCurrentIndex(3);
//设置奇偶校验位
ui->cbParity->addItem(tr("None"), QSerialPort::NoParity);
ui->cbParity->addItem(tr("Even"), QSerialPort::EvenParity);
ui->cbParity->addItem(tr("Odd"), QSerialPort::OddParity);
ui->cbParity->addItem(tr("Mark"), QSerialPort::MarkParity);
ui->cbParity->addItem(tr("Space"), QSerialPort::SpaceParity);
//设置停止位
ui->cbStop->addItem(QStringLiteral("1"), QSerialPort::OneStop);
ui->cbStop->addItem(QStringLiteral("2"), QSerialPort::TwoStop);
//添加流控
ui->cbFlowBit->addItem(tr("None"), QSerialPort::NoFlowControl);
ui->cbFlowBit->addItem(tr("RTS/CTS"), QSerialPort::HardwareControl);
ui->cbFlowBit->addItem(tr("XON/XOFF"), QSerialPort::SoftwareControl);

功能方法

//打开串口
//设置串口名字
serial->setPortName(m_strComName);
//设置波特率
serial->setBaudRate(m_iBaudRate);
//设置数据位
switch (m_iDataBit) {
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;
}

//设置奇偶校验位
if(m_strParity=="None"){
    serial->setParity(QSerialPort::NoParity);
}
else if(m_strParity=="Even"){
    serial->setParity(QSerialPort::EvenParity);
}
else if(m_strParity=="Odd"){
    serial->setParity(QSerialPort::OddParity);
}
else if(m_strParity=="Mark"){
    serial->setParity(QSerialPort::MarkParity);
}
else if(m_strParity=="Space"){
    serial->setParity(QSerialPort::SpaceParity);
}

//设置停止位
if(m_strStopBit=="1"){
    serial->setStopBits(QSerialPort::OneStop);
}
else if(m_strStopBit=="2"){
    serial->setStopBits(QSerialPort::TwoStop);
}

//设置流控
if(m_strFlowBit=="None"){
    serial->setFlowControl(QSerialPort::NoFlowControl);
}
else if(m_strFlowBit=="RTS/CTS"){
    serial->setFlowControl(QSerialPort::HardwareControl);
}
else if(m_strFlowBit=="XON/XOFF"){
    serial->setFlowControl(QSerialPort::SoftwareControl);
}


//打开串口,成功就禁用控件
if (serial->open(QIODevice::ReadWrite))
{
    ui->cbRate->setEnabled(false);
    ui->cbData->setEnabled(false);
    ui->cbFlowBit->setEnabled(false);
    ui->cbParity->setEnabled(false);
    ui->cbCom->setEnabled(false);
    ui->cbStop->setEnabled(false);
    ui->btSend->setEnabled(true);
    //信号与槽函数关联,绑定回调处理的方法
    connect(serial, &QSerialPort::readyRead, this, &MainWindow::readData);
}

//接收回调
void MainWindow::readData()
{
    QByteArray buf;
    buf = serial->readAll();
    if (!buf.isEmpty())
    {
        QString str = ui->tbRecv->toPlainText();
        str += tr(buf);
        ui->tbRecv->clear();
        ui->tbRecv->append(str);
        m_strRecvList->append(buf);
    }
}

//发送
void MainWindow::on_btSend_clicked()
{
    serial->write(ui->tbSend->toPlainText().toLocal8Bit());
}

关闭串口

//关闭串口
//serial->clear();
serial->close();
m_strRecvList->clear();
//serial->deleteLater();
//恢复设置功能
ui->cbRate->setEnabled(true);
ui->cbData->setEnabled(true);
ui->cbFlowBit->setEnabled(true);
ui->cbParity->setEnabled(true);
ui->cbCom->setEnabled(true);
ui->cbStop->setEnabled(true);
ui->btOpenCom->setText(tr("打开串口"));
ui->btSend->setEnabled(false);

m_bIsConnect=false;

UI布局
在这里插入图片描述

网口通讯

pro文件需要添加network
在这里插入图片描述
tips:
服务器模式:
打开服务器使用QTcpServer(管理服务器),接收连接的客户端套接字用QTcpSocket
客户端模式使用QTcpSocket
初始化代码

QTcpServer *m_server;
QTcpSocket *m_socket;
bool m_bIsConnect;
QString m_strTcpIP;
int m_iTcpPort;

//创建用于服务端通信的套接字                                                      
m_server=new QTcpServer(this);                                                                                                        
//连接成功就会触发connected信号                                                
connect(m_server,&QTcpServer::newConnection,this,[=]()               
{                                                                    
    m_socket = m_server->nextPendingConnection();//接收连入的客户端                    
    ui->tbTcpRecv->setText(ui->tbTcpRecv->toPlainText()+"\n成功和客户端建立了连
    m_bIsConnect=true;                
    //接收回调
    connect(m_socket,&QTcpSocket::readyRead,this,[=]()               
    {                                                                
        QByteArray data = m_socket->readAll();                       
        QStringList list = QString(data).split('\n', QString::SkipEmp
        m_strRecvList->append(list);//加入接收列表                         
        for (int i = 0;i<list.count();i++) {                         
            ui->tbTcpRecv->append("\n接收:"+list[i]);                  
        }                                                                                                                         
    });                                                              
    connect(m_socket,&QTcpSocket::disconnected,this,[=]()            
    {                                                                
        ui->tbTcpRecv->setText(ui->tbTcpRecv->toPlainText()+"\n客户端断开了
        m_socket->close();                                           
        m_socket->deleteLater();                                     
        m_bIsConnect=false;                                          
    });                                                                                                                               
});                                                                  
      
        
//创建用于客户端通信的套接字                                                      
m_socket = new QTcpSocket;                                                                                                        
//连接成功就会触发connected信号                                                
connect(m_socket,&QTcpSocket::connected,this,[=]()                   
{                                                                    
    ui->tbTcpRecv->setText(ui->tbTcpRecv->toPlainText()+"\n与服务器连接成功!"
    m_bIsConnect=true;                                                                                                            
    //对方有数据传来就会触发readyRead信号                                         
    connect(m_socket,&QTcpSocket::readyRead,this,[=]()               
    {                                                                
        QByteArray data = m_socket->readAll();                       
        QStringList list = QString(data).split('\n', QString::SkipEmp
        m_strRecvList->append(list);//加入接收列表                         
        for (int i = 0;i<list.count();i++) {                         
            ui->tbTcpRecv->append("\n接收:"+list[i]);                  
        }                                                            
    });                                                              
    //双方断开连接后就会触发disconnected信号                                      
    connect(m_socket,&QTcpSocket::disconnected,this,[=]()            
    {                                                                
        ui->tbTcpRecv->setText(ui->tbTcpRecv->toPlainText()+"\n客户端断开了
        m_socket->close();                                           
        m_socket->deleteLater();                                     
        m_bIsConnect=false;                                                                                                    
    });                                                                                                                             
});   

连接/监听代码:

void MainWindow::on_btTcpConnect_clicked()
{
    //如果是服务器模式
    if(ui->rbServer->isChecked())
    {
        try {
            m_server->close();
        } catch (...) {
        }
        QString localhost=QHostAddress(QHostAddress::LocalHost).toString();//127.0.0.1
        QString any=QHostAddress(QHostAddress::AnyIPv4).toString();//任意端口,包括127.0.0.1和本地网络适配器的所有ip地址
        m_server->listen(QHostAddress::AnyIPv4,m_iTcpPort);
    }
    //如果是客户端模式
    else
    {
        try {
            m_server->close();
            m_socket->close();
        } catch (...) {
        }
        //发起连接请求
        m_socket->connectToHost(QHostAddress(m_strTcpIP),m_iTcpPort);
    }
}

发送代码

if(m_bIsConnect){
    m_socket->write(ui->tbTcpSend->toPlainText().toUtf8());
}

关闭代码

try {                        
    if(m_bIsConnect){        
        m_server->close();   
        m_socket->close();   
    }                                               
} catch (...) {              
}                            
m_bIsConnect=false;     

UI布局
在这里插入图片描述

内存拷贝

内存拷贝的双方软件一定要管理员模式打开,因为这是windows进程之间的通讯!!!!

这里使用C++的方式进行内存拷贝
引入头文件

#include "windows.h"
#include "winuser.h"

在使用的类中加入,否则会对windows的sendmessage,findwindow等函数报无法解析的外部符号错误,如下
在这里插入图片描述

#pragma comment  (lib, "User32.lib")

在qt中要注意发送过来的字符格式,如果是宽字符/unicode(c++的LPCSTR,LPCWSTR,LPCTSTR),就需要用fromStdWString来接收,注意这个字符串长度也不一样,是默认的2倍,c++发送端如下

CString strText:
COPYDATASTRUCT cds;
memset(&cds, 0, sizeof(cds));
cds.dwData = 0;
//发送unicode字符,大小等于字串的size*2,sizeof(TCHAR)=2
cds.cbData = (strText.GetLength() ) * sizeof(TCHAR) + 1; // +1 for the NULL
cds.lpData = (LPVOID)(LPCWSTR)(strText);

如果是短字符,1个字节为单位的ansi(c++的W2A,char*),就需要用fromStdString来接收,这个字符串的长度是默认长度,c++发送端如下

CString strText:
COPYDATASTRUCT cds;
memset(&cds, 0, sizeof(cds));
cds.dwData = 0;
//发送ansi字符,大小等于字串的size*1,sizeof(TCHAR)=2
cds.cbData = (strText.GetLength() ) * 1 + 1; // +1 for the NULL
USES_CONVERSION;
cds.lpData = (LPVOID)W2A(strText);

c++接收端如下,不同格式ansi/unicode原理同上

LRESULT CTestCommunicationDlg::OnCopyData(WPARAM wParam,LPARAM lParam)
{
	//HWND hwnd = (HWND)wParam;            // handle of sending window 
	PCOPYDATASTRUCT pcds = (PCOPYDATASTRUCT)lParam;
	LPCWSTR szNewString = (LPCWSTR)(pcds->lpData);
	m_strDataRcv = (LPCWSTR)(pcds->lpData);
	//GetDlgItem(IDC_EDIT2)->SetWindowTextW(m_strDataRcv);
	return 1L;
}

回到QT
QT查找窗口

m_MemTargetWin = ::FindWindow(NULL, ui->tbMemTargerWinName->text().toStdWString().c_str());//通过主窗口类名寻找主窗口句柄

if (NULL != m_MemTargetWin)
{
    QMessageBox::information(this,"提示","找到名为:"+ui->tbMemTargerWinName->text()+"的窗口");
}else{
    QMessageBox::warning(this,"提示","未找到名为:"+ui->tbMemTargerWinName->text()+"的窗口");
}

QT内存发送

WId wid = this->winId(); //这个窗口的winid
if (NULL != m_MemTargetWin)
{
    std::thread th([=](){ //单独启动一个线程进行数据传递
        QString command = QString("Command=ChangeCode=%1\r\n").arg(ui->tbMemSend->toPlainText());//传递的内容
        COPYDATASTRUCT data;    //使用COPYDATA的方式进行数据传递
        data.dwData = 0;
        data.cbData = command.length()*2+1;//unicode size = length*2+1;ansi size=length+1
        data.lpData = command.data();
        ::SendMessage(m_MemTargetWin, WM_COPYDATA, (WPARAM)wid, (LPARAM)&data);
    });

    th.detach();//传递结束后,进行关闭线程
}

QT接收,在头文件中重写窗口事件消息

//virtual bool nativeEvent(const QByteArray &eventType, void *message, long *result) override;//此消息不行,传过来的数据不吻合,无法解析
virtual bool nativeEventFilter(const QByteArray &eventType, void *message, long *) Q_DECL_OVERRIDE;

重写

bool MainWindow::nativeEventFilter(const QByteArray &eventType, void *message, long *result)
{
    if (eventType == "windows_generic_MSG") //windows平台
    {
        MSG* msg = reinterpret_cast<MSG*>(message);
        if (msg->message == WM_APPCOMMAND || msg->message == WM_COPYDATA)//消息类型
        {
            COPYDATASTRUCT *data ;
            data = reinterpret_cast<COPYDATASTRUCT*>(msg->lParam);
            //QString str=QString::fromStdWString((LPCWSTR)(data->lpData));//unicode过来用宽字符接收,LPCWSTR、LPCSTR或其他根据发送端而定
            QString str=QString::fromStdString((char*)(data->lpData));//ansi过来用默认字符char*接收,如果是unicode过来的用ansi接收,则只能接收到第一个字符
            // int size2 = sizeof(&data);
            //char * dest = (char*)malloc(sizeof (char)*(int)data->cbData);
            //memcpy(dest,data->lpData,(int)data->cbData);//只能接收到第一个字符

            //QTextCodec *codec = QTextCodec::codecForName("UTF-8");
            //QTextCodec::setCodecForLocale(codec);

            //char * a=(char *)(data->lpData);//只能接收到第一个字符

            //QString recevice = codec->toUnicode(a);//转码
            //QString recevice((char *)(data->lpData));//只能接收到第一个字符

            ui->tbMemRecv->append(str);
        }
    }
    return QWidget::nativeEvent(eventType, message, result);//交给Qt处理,不能少
}

UI布局
在这里插入图片描述

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-05-11 16:14:51  更:2022-05-11 16:16:13 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 19:23:12-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码