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_OBJECT

public:

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; i

bytes->append(*(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

*(dt+i+2) = strtemp.at(i).toAscii();

*(dt+len+2) = 0xFF;

sendData(dt,len+3);

qDebug('data is sent');

Sleep(20);

delete []dt;

dt = NULL;

}

else

qDebug('sendData loading failed');

return b_checked;

}

void communicate::Close()

{

ClosePort closePort = (ClosePort)lib->resolve('closePort');

if (closePort)

{

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)

;

}

mysql触发器信号给qt_利用回调函数实现DLL与Qt主程序的数据交互,进一步实现对Qt主程序中的信号触发 - zcabcd123的专栏 - 博客频道 - CSDN.NET...相关推荐

  1. SAE利用storge上传文件 - myskies的专栏 - 博客频道 - CSDN.NET

    SAE利用storge上传文件 - myskies的专栏 - 博客频道 - CSDN.NET SAE利用storge上传文件

  2. c语言中shmget相关函数,共享内存函数(shmget、shmat、shmdt、shmctl)及其范例 - guoping16的专栏 - 博客频道 - CSDN...

    2014年4月2日共享内存函数(shmget.shmat.shmdt.shmctl)及其范例 - guoping16的专栏 - 博客频道 - http://doc.xuehai.net 登录 | 注册 ...

  3. 编写字符串反转函数 - 小小外星人的技术博客 - 博客频道 - CSDN.NET

    编写字符串反转函数 - 小小外星人的技术博客 - 博客频道 - CSDN.NET 编写字符串反转函数 分类: 笔试面试题 2010-11-07 20:47 863人阅读 评论(0) 收藏 举报 首先用 ...

  4. linux开机启动mysql脚本,ubuntu linux下mysql开机自启动 - 心之所向,无惧无悔! - 博客频道 - CSDN.NET...

    1. 预使mysql开机自启动,首先需要注册mysql为ubuntu下的服务. 直接拷贝MySQL.server文件至/etc/init.d/目录下即可. sudo cp $MYSQL_HOME/su ...

  5. QT信号与槽——观察者模式——回调函数

    QT信号与槽--观察者模式--回调函数 1.QT信号与槽机制 1.1信号本质 信号是由于用户对窗口或控件进行了某些操作,导致窗口或控件产生了某个特定事件,这时候 Qt 对应的窗口类会发出某个信号.比如 ...

  6. javascript利用回调函数解决异步困扰

    虽然已经存在promise,StratifiedJS等工具用来解决回调地狱,但是讲真,我觉得他们也并没有让代码的可读性大大增强,而且在回调函数的嵌套次数有限的情况下也不至于成为一个"地狱&q ...

  7. 计算器(利用回调函数/函数指针数组实现) C语言

    玩点不一样的 一.利用回调函数实现 #include <stdio.h>void menu() {printf("************ 计算器 **********\n&qu ...

  8. mysql触发器生成流水_利用mysql触发器生成流水号

    http://blog.csdn.net/bluestream/article/details/5755176 利用mysql触发器可以生成如日期(20100721)+编号(0001)的流水号,编号每 ...

  9. bootstraptable 加载完成回调函数_牛皮了!头一次见有大佬把「JavaScript中的回调函数」详解得如此清晰明了...

    前言 callback,大家都知道是回调函数的意思.但是你对这个概念应该是模模糊糊.比如Ajax,你只知道去调用返回函数,如果对callback没有理解清楚,估计你在学习Node.js后会崩溃,因为c ...

  10. 利用Bmob云后端云函数实现移动应用与数据库的数据交互

    关于我,欢迎关注 csdn博客:ccapton(http://blog.csdn.net/ccapton) 微信:Ccapton Github: (https://www.github.com/cca ...

最新文章

  1. 神经网络设计与分析之如何知道权重的利用率
  2. IntelliJ IDEA 的 project 和 module 区别与关系
  3. codeproject网页翻译
  4. solr:关于dismax的使用情况(转:https://my.oschina.net/momohuang/blog/145379)
  5. 一个filter子查询测试
  6. 15分钟从零开始搭建支持10w+用户的生产环境(三)
  7. openstack mitaka 完整安装详细文档(亲测,花了3天时间)
  8. Flex:MyReport报表引擎2.7.3.0新功能——甘特图
  9. 一次线上商城系统高并发优化,涨姿势了~
  10. 21天实战人工智能系列:人工智能产品经理最佳实践(3)
  11. Android五子棋游戏源码详解
  12. 码云仓库第一次上传代码流程和git相关操作合集(持续更新)
  13. css画钟表_用CSS3实现钟表效果
  14. VS code(Visual Studio Code)乱码解决方法
  15. iOS 苹果官方Demo合集
  16. VUE—下载安装并使用mint ui(图文详情)
  17. 2021-09-10 LeetCode1894-找到需要补充粉笔的学生编号(每日一题)
  18. RSA生成密钥对的过程
  19. 自动驾驶仿真软件SCANeRstudio(二)场景、仿真、分析
  20. 关于龙卷风你应该知道的五件事

热门文章

  1. 安装CentOS步骤
  2. Verizon CEO证实公司正考虑出价收购雅虎
  3. 运维之我的docker-不要在给你的docker安装ssh server
  4. PHP 三种方式实现链式操作
  5. Visual Leak Detector(vld)无法显示内存泄露文件名称与行号
  6. php结合nginx,mysql
  7. python改变默认编码
  8. idea添加scala环境_Scala(一)——scala+Idea环境配置
  9. PHP根据开始、结束时间:计算开始、结束时间占当月总天数的百分比
  10. ACCESS_REFUSED - operation not permitted on the default exchange