利用回调函数实现DLL与Qt主程序的数据交互,进一步实现对Qt主程序中的信号触发 |
您所在的位置:网站首页 › qt数据交互 › 利用回调函数实现DLL与Qt主程序的数据交互,进一步实现对Qt主程序中的信号触发 |
Qt并没有提供串口通讯的接口,为了实现Qt程序的串口通讯,多数开发者都采用了一个第三方接口win_qextserialport。这个接口是完全基于Qt类库的,很容易就可以把它加载到自己的程序里边。但在实际应用过程中,发现了一个奇怪的现象: 我的上位机程序是要通过控制串口(USB转的)来实现与下位机的通讯,经过测试,在相同的设置下,上位机程序和串口调试软件能够正常通讯,下位机和串口调试软件也能够正常通讯。按理说,这个时候上下位机也就应该能够正常地通讯了,但事实却很残酷:它们无法沟通,下位机接不到上位机的数据,上位机也接不到下位机的数据,----无论我如何调节相关设置、重新开关机,都无济于事。 我不知道win_qextserialport到底怎么了,实在无暇去深究。因为时间比较紧,我不得不尽早尝试新的串口通讯接口。 最直接的就是调用Windows API了,但那一堆堆冗长的接口函数实在繁琐。幸运的是有个大牛发布了一个C++串口通讯程序接口(CnComm.h头文件源代码,最新版是1.5),非常方便。因为它需要在VC下编译,所以我必须把它打包成DLL然后提供给Qt主程序调用。到这里,我面临很多的问题: 1 大牛的接口是C++的,Qt可以容易地实现对DLL里的函数的调用,但如何调用Dll里的类? 2 我需要在串口接收到数据后,把数据传回主程序,并马上在Qt主程序里释放一个信号(signal),以通知主程序处理。如何实现? 3 DLL里根本不知道Qt主程序里的相关的类,更不知道Qt中的emit为何物,怎么传递Qt主程序里的类给他?
最后是通过回调函数来实现的。 回调函数,就是把一个函数A的指针传递给另一个函数B,由函数B再调用函数A,这样就可以实现模块间的交互操作。如果再把函数A的指针传递给函数B的同时,也把相关的参数一起传递给函数B,那么就可以实现模块间的数据交互。 例如: int sumit(int x, int y){ return x + y ;} void testit(int a, int b, int (*func)(int, int)){ QString strs = QString::number(func(a,b)); qDebug(strs.toAscii());}
可以这样调用: testit(1,2,sumit);打印输出值:3
下面是DLL与Qt主程序的主要实现代码: 1 DLL代码 #include "CnComm.h"class communicate; //Qt中类的前向声明,通知DLL这是一个类typedef void(*Emit)(communicate*, char*, int); //函数指针类型定义 class HRComm : public CnComm { private: Emit emitSignal ; //信号释放函数的指针, 用于指向回调函数 communicate * pComm; //Qt中类实例的指针,指向Qt主程序中的类实例,作回调函数的实参,以便在Qt主程序中进行信号释放 char *pDataBuffer; //接收数据缓存指针 int iLength; //接收到的字节数 void OnReceive() //重载接收函数 { int dataLen = Read(pDataBuffer, iLength); //读取串口数据,返回实际接收的数据字节数 emitSignal(pComm,pDataBuffer,dataLen); //回调在此发生!传数据到到Qt主程序中,并把释放信号的类实例指针回传。 } public: void SetSignal(communicate* commn, char *pData, int len, Emit func); //设置类参数, 把Qt主程序里的函数指针和其参数传到该串口通讯类中};
void HRComm::SetSignal(communicate *commn, char *pData, int len, Emit func){ pDataBuffer = pData; iLength = len; emitSignal = func; //传递Qt主程序里的函数(回调函数)指针 pComm = commn; //传递Qt主程序里的类实例指针}
HRComm hrComm; //实例化一个串口通讯类
bool openPort(int port, int baudrate) { return hrComm.Open(port, baudrate);} void closePort(void){ hrComm.Close();} void sendData(char *buff, int len){ hrComm.Write(buff, len);} void setReceiveSignal( communicate *commn,char *pData, int len, Emit pFunc) { hrComm.SetSignal(commn, pData, len, pFunc);}
Qt主程序通过调用openPort、closePort、sendData和setReceiveSignal分别实现打开串口、关闭串口、发送数据和回调函数传递。
2 Qt 主程序主要实现代码 1)communicate.h #ifndef COMMUNICATE_H#define COMMUNICATE_H#include "win_qextserialport.h"#include class Signal;class QString;class QByteArray;class QLibrary; class communicate: public QObject{ Q_OBJECTpublic: QLibrary *lib; int iDataLen; char *pData; communicate(QWidget *parent = 0); Win_QextSerialPort *myCom; int iPortNumber; void Connect(void); bool b_checked; void Open(int portNumber); bool TestPort(int portNumber); void SetSignalEmit(char *data, int len); signals: void signalData(char *pData, int len);public slots: void Close(void); void GotData(char *pData, int len); }; #endif // COMMUNICATE_H
2)communicate.cpp #include "communicate.h"#include "data.h"#include #include typedef bool(*OpenPort)(int, int);typedef void(*ClosePort)(void);typedef void(*SendData)(char*, int);typedef void(*SetSignal)(communicate*, char*, int, void(*pf)(communicate*, char*, int)); //回调函数。C++中,类成员函数不可以作回调函数,要不然就不用这么麻烦把communicate *comm传来传去了。void SetIt(communicate *comm, char *data, int len) { qDebug("GOT DATA!"); QByteArray * bytes = new QByteArray; for (int i=0; iappend(*(data+i)); qDebug(bytes->toHex()); comm->SetSignalEmit(data, len); comm->b_checked = true;}
void communicate::Connect(void){ connect(myCom, SIGNAL(readyRead()),this,SLOT(readCom()));} communicate::communicate(QWidget *parent){ b_checked = false; strpc = SUNG_ID_CODE; iDataLen = 1024; pData = new char[1024]; lib = new QLibrary("CommuModual.dll"); if(lib->load()) { qDebug("dll is loaded"); } else qDebug("dll loading failed."); connect(this, SIGNAL(signalData(char*,int)),this, SLOT(GotData(char*,int))); } void communicate::GotData(char*,int){ b_checked = true;}
void communicate::SetSignalEmit(char *data, int len){ emit this->signalData(data, len);} void communicate::Open(int portNumber){ OpenPort openPort = (OpenPort)lib->resolve("openPort"); if (openPort) { qDebug("openPort loaded"); if(openPort(portNumber,115200)) qDebug("port opened"); else qDebug("port opening failed."); } else qDebug("openPort loading failed"); } bool communicate::TestPort(int portNumber){ iPortNumber = portNumber; SetSignal setSignal = (SetSignal)lib->resolve("setReceiveSignal"); if (setSignal) { qDebug("SetReceiveSignal loaded"); setSignal(this,this->pData, this->iDataLen,SetIt); //设置信号与回传 qDebug("Signal is set"); } Open(portNumber); //打开串口 SendData sendData = (SendData)lib->resolve("sendData"); if (sendData) { qDebug("sendData loaded"); QString strtemp = SUNG_ID_CODE; int len = strtemp.count(); char *dt = new char[len+3]; *dt = 0xFF; *(dt+1) = INST_ID_CODE; for (int i=0; i qDebug("closePort loaded"); closePort(); qDebug("port is closed"); } else qDebug("closePort loading failed"); delete lib; lib = NULL; }
3)main.cpp #include "communicate.h" void main(int argc, char *argv[]){ communicate commn; commn.TestPort(13); //测试:打开串口13,设置回调函数、数据传输参数 while(!commn.b_checked) ;} |
今日新闻 |
点击排行 |
|
推荐新闻 |
图片新闻 |
|
专题文章 |
CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭 |