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;                            //獲得線程ID
13     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 __cplusplus 17 } 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     do
20  { 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,進行簡單的數據通信測試。

 

 

 

 

 

源碼地址:https://github.com/karllen/SerialPortTools

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM