VS2015 +Qt5 串口工具

简介:

简单的小工具是VS2015 + Qt5.6.1实现的,界面部分是Qt实现,口是封装的WinAPI把串口收发模块封装成了Serialport.dllQt界面调用。

由于VS2015需要Universal CRT运行环境,因此把Qt编译成了静态的版本。

一、串口收发是封装的Win32,单独封装成了一个Serialport.dll.

包括串口通信类:

复制代码

class CSerialport
{public:
    CSerialport();    ~CSerialport();
    BOOL openComm(const string & name);
    BOOL closeComm();
    BOOL setCommState(const DCB & dcb)const;
    BOOL getCommState(DCB & dcb)const;
    BOOL setCommTimeouts(const COMMTIMEOUTS & commtimeOuts)const;
    BOOL purgeComm(DWORD flags = PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT)const;
    BOOL setupComm(DWORD dwInQueue, DWORD dwOutQueue)const;    int  readFile(vector<char> & buffer, DWORD nNumberOfBytesToRead,DWORD & lpNumberOfBytesRead, LPOVERLAPPED pLoverlapped = NULL);    int  writeFile(vector<char> & buffer, DWORD nNumberOfBytesToRead, DWORD & lpNumberOfBytesRead, LPOVERLAPPED pLoverlapped = NULL);    string getPortName()const;
    HANDLE getHandle()const;    //private:
    HANDLE m_hspCom;    string m_commName;
};

复制代码

此类负责基本的串口通信。

线程类:

复制代码

 1 class CBaseThread 2 { 3 public: 4     CBaseThread(void); 5     virtual ~CBaseThread(void); 6 public: 7     virtual void start();                                        //创建线程 8     virtual void end();                                          //结束线程 9     virtual void resume();                                       //重启线程10     virtual void suspend();                                      //暂停线程11     //12     virtual int  getThreadID() const;                            //获得线程ID13     virtual BOOL isRun() const;                                  //判断线程是否运行14     virtual void runTask() = 0;                                  //子类实现此函数完成业务逻辑15     //16     static unsigned _stdcall threadFunc(void* pParam);           //线程函数,调RunTask逻辑17 18 protected:19     HANDLE m_hEndEvent;                                         //设置退出线程处理20     HANDLE m_hExitEvent;                                        //线程RunTask结束时设置,确保线程正常退出                                     21     HANDLE m_hThreadHandle;22     unsigned int m_uThreadID;23     //24 };

复制代码

 

线程管理基类,封装_beginthreadex()

串口线程调度线程:

 

复制代码

typedef int (*pGET_DATA_CAAL_BACK)(list<char> &);class CSerialportThread :    public CBaseThread
{public:
   CSerialportThread(void);    virtual ~CSerialportThread(void);    void setCommConfig(const char* com, int baudRate, char byteSize, char parity, char stopBits);    static CSerialportThread * getInstance();    int  writeFile(const char * writeBuffer,int size);    void initCallBack(void *);protected:    virtual void runTask();    void initComm();protected:
   CSerialport m_serialport;    //    string m_com;    int m_baudRate;    char m_byteSize;    char m_parity;    char m_stopBits;    bool m_bInit;
   pGET_DATA_CAAL_BACK m_addDataCallBack;
};

复制代码

 

继承CBaseThread实现runTask()线程函数,有CSerialport 类成员变量进行串口的通信的管理,并提供一个回调接口,将接收到的数据回调给接收数据维护的类。

串口数据接收维护类:

复制代码

class CCommDataHolder
{public:
   CCommDataHolder();    ~CCommDataHolder();    //    static std::shared_ptr<CCommDataHolder> getInstance();    static int getDataCallBackS(list<char> & buffer);    
   int getCommData(char * buffer,int len);protected:    int getDataCallBack(list<char> & buffer);    //private:    static std::shared_ptr<CCommDataHolder>  s_pInstance;    static std::mutex s_mt;    //    list<char> m_listData;
   std::mutex m_mt;
};

复制代码

 

数据维护类,上层应用来这里取数据即可。

Serialport.dll导出接口:

复制代码

 1 #pragma once 2  3 #define SERIALPORT_DLL_EXPORT __declspec(dllexport) 4  5 #ifdef __cplusplus 6 extern "C" 7 { 8 #endif //  9     10 SERIALPORT_DLL_EXPORT int commReadData(char* buffer,int size);11 SERIALPORT_DLL_EXPORT int commWriteData(const char* buffer, int size);12 SERIALPORT_DLL_EXPORT void setCommConfig(const char* com,int baudRate,char byteSize,char parity,char stopBits);13 SERIALPORT_DLL_EXPORT void start();14 SERIALPORT_DLL_EXPORT void end();15 16 #ifdef __cplusplus17 }18 #endif // 

复制代码

 

二、Qt界面实现

界面实现主要是设置串口的通信的参数,然后设置串口通信的收发区域,这里使textEdit控件,然后设置了一下数据的展现方式,分ASCIIHEX(16进制发送),

16进制发送的形式应该为: 61 25 AA 7A 5B的这种形式,然后选择Hex选项,发送。

 

串口列表:自动枚举系统的所有已存在串口enumPort(QStringList & strList)

复制代码

 1 void SerialPortTools::enumPort(QStringList & strList) 2 { 3     HKEY hKey; 4     LPCTSTR lpSubKey = _T("HARDWARE\\DEVICEMAP\\SERIALCOMM\\"); 5  6     if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, lpSubKey, 0, KEY_READ, &hKey) != ERROR_SUCCESS) 7     { 8         return; 9     }10     WCHAR szValueName[100] = { 0 };11     WCHAR szPortName[100] = { 0 };12     LONG status;13     DWORD dwIndex = 0;14     DWORD dwSizeValueName = 100;15     DWORD dwSizeofPortName = 100;16     DWORD Type;17     dwSizeValueName = 100;18     dwSizeofPortName = 100;19     do20     {21         status = RegEnumValue(hKey, dwIndex++, szValueName, &dwSizeValueName, NULL, &Type, (PUCHAR)szPortName, &dwSizeofPortName);22         if ((status == ERROR_SUCCESS))23         {24             QString tmp = CCodecUtils::str2qstr(CEcoder::wstringToString(szPortName));25             strList << tmp;26         }27         dwSizeValueName = 100;28         dwSizeofPortName = 100;29     } while ((status != ERROR_NO_MORE_ITEMS));30     RegCloseKey(hKey);31 }

复制代码

 

设置好串口参数,串口号,波特率,数据位,校验位,停止位等参数后setCommConfig(com.c_str(), baudRate, byteSize, parity, stopBit);

,打开串口start();开启调度串口通信线程。

打开串口需要引用Serialport.dll的接口函数

复制代码

 1 void SerialPortTools::openPort() 2 { 3     QString strCom = ui.comboBox->currentText(); 4     QString strBaudRate = ui.comboBox_2->currentText(); 5     QString strByteSize = ui.comboBox_3->currentText(); 6     // 7     string com   = CCodecUtils::qstr2str(strCom); 8     int baudRate = strBaudRate.toInt(); 9     int byteSize = strByteSize.toInt();10     int parity     = ui.comboBox_4->currentIndex();11     int stopBit  = ui.comboBox_5->currentIndex();12     setCommConfig(com.c_str(), baudRate, byteSize, parity, stopBit);13     //14     start();    
15     m_timer.start();16     MessageBoxInfo(tr("提示"), tr("    串口打开成功    "));17     ui.openaction->setEnabled(false);18     ui.closeaction->setEnabled(true);19 }

复制代码

 

数据接收的实现是设置了一个定时器,不断去调commReadData(char* buffer,int size) 去读取dll数据缓存区的数据,读到之后更新到数据接收区的界面。

发送则很简单,获取数据发送区的内容,点击发送,直接调用commWriteData(const char *buffer,int size)发送串口数据。

 

定时器:

1     m_timer.setInterval(2000);2     connect(&m_timer, SIGNAL(timeout()), this, SLOT(reciveData()));

 

数据收:

复制代码

 1 void SerialPortTools::reciveData() 2 { 3     char szRead[1024] = { 0 }; 4     memset(&szRead, 0, 1024); 5     int nRet = commReadData(szRead, 1024); 6     m_strRec = CCodecUtils::qstr2str(ui.textEdit->toPlainText()); 7     if (nRet != 0) 8     { 9         string str = szRead;10         m_strRec += str;11         if (ui.radioButton->isChecked())12         {13             ui.textEdit->setText(CCodecUtils::str2qstr(m_strRec));14         }15         else if (ui.radioButton_2->isChecked())16         {17             char sz[2048];18             memset(&sz, 0, 2048);19             ui.textEdit->setText(CCodecUtils::str2qstr(CCodecUtils::byte2HexCpp(m_strRec)));20         }21     }    
22 }

复制代码

 

数据发:

复制代码

 1 void SerialPortTools::sendData() 2 { 3     QString str = ui.textEdit_2->toPlainText(); 4     string strSend = CCodecUtils::qstr2str(str); 5     if (!strSend.empty()) 6     { 7         // 8         if (ui.radioButton_3->isChecked()) 9         {10             commWriteData(strSend.c_str(), strSend.length() + 1);11         }12         else if (ui.radioButton_4->isChecked())13         {14             string strtmp = CCodecUtils::hexStr2Str(CCodecUtils::eraseSpace(strSend));15             commWriteData(strtmp.c_str(),strtmp.length()+1);16             //17         }18     }19 }

复制代码

 

串口关end();

复制代码

1 void SerialPortTools::closePort()2 {3     end();4     ui.openaction->setEnabled(true);5     ui.closeaction->setEnabled(false);6 }

复制代码

 

软件运行:

用虚拟串口工具打开COM1COM2两个串口对,打开两SerialPortTools.exe ,分别打开COM1COM2,进行简单的数据通信测试。

 

 

 




本文转自lzwxx 51CTO博客,原文链接:http://blog.51cto.com/13064681/1944329
相关文章
|
1月前
|
存储 传感器 安全
【串口通信】使用C++和Qt设计和实现串口协议解析器(二)
【串口通信】使用C++和Qt设计和实现串口协议解析器
52 0
|
1月前
|
存储 开发框架 算法
【串口通信】使用C++和Qt设计和实现串口协议解析器(一)
【串口通信】使用C++和Qt设计和实现串口协议解析器
99 0
|
1月前
|
Linux API C语言
Qt串口编程探究:理论与实践
Qt串口编程探究:理论与实践
64 1
|
6月前
|
API
QT学习—属于自己的串口调试助手
本文详细介绍了如何编写一个属于自己的串口助手。
71 3
|
10月前
QT上位机串口+STM32单片机项目(二)
QT上位机串口+STM32单片机项目
164 0
|
10月前
QT上位机串口+STM32单片机项目(一)
QT上位机串口+STM32单片机项目
451 0
|
Linux
QT实战串口助手
QT实战串口助手
199 0
|
存储
QT串口助手(串口的查找和打开)
QT串口助手(串口的查找和打开)
171 0
|
移动开发
QT串口助手(实现数据的收发功能)
QT串口助手(实现数据的收发功能)
414 0

热门文章

最新文章

推荐镜像

更多