前一段時間接觸硬件,用到了串口數據傳輸。就百度了一下。也是拿網上的代碼進行修改的。現在給大家參考。
是參考一位大佬:老司機的詩和遠方。
這是他的博客地址
先上代碼:
readport.h文件
#ifndef _WZSERIALPORT_H
#define _WZSERIALPORT_H
#include<iostream>
#include <string>
#include <vector>
using namespace std;
class WZSerialPort
{
public:
WZSerialPort();
~WZSerialPort();
// 打開串口,成功返回true,失敗返回false
// portname(串口名): 在Windows下是"COM1""COM2"等,在Linux下是"/dev/ttyS1"等
// baudrate(波特率): 9600、19200、38400、43000、56000、57600、115200
// parity(校驗位): 0爲無校驗,1爲奇校驗,2爲偶校驗,3爲標記校驗
// databit(數據位): 4-8,通常爲8位
// stopbit(停止位): 1爲1位停止位,2爲2位停止位,3爲1.5位停止位
// synchronizable(同步、異步): 0爲異步,1爲同步
//在這裏已經對配置進行了初始化,你們可以自己改配置使用
bool open(const char* portname, int baudrate = 115200, char parity = 0, char databit = 8, char stopbit = 1, char synchronizeflag = 1);
//關閉串口,參數待定
void close();
//發送數據或寫數據,成功返回發送數據長度,失敗返回0
int send(string dat);
//接受數據或讀數據,成功返回讀取實際數據的長度,失敗返回0
string receive();
//vector<unsigned char> revcmsg;
private:
int pHandle[16];
char synchronizeflag;
};
#endif
readport.cpp文件:
#include "readport.h"
#include <stdio.h>
#include <string.h>
#include <WinSock2.h>
#include <windows.h>
WZSerialPort::WZSerialPort()
{
}
WZSerialPort::~WZSerialPort()
{
}
bool WZSerialPort::open(const char* portname,
int baudrate,
char parity,
char databit,
char stopbit,
char synchronizeflag)
{
this->synchronizeflag = synchronizeflag;
HANDLE hCom = NULL;
if (this->synchronizeflag)
{
//同步方式
hCom = CreateFileA(portname, //串口名
GENERIC_READ | GENERIC_WRITE, //支持讀寫
0, //獨佔方式,串口不支持共享
NULL,//安全屬性指針,默認值爲NULL
OPEN_EXISTING, //打開現有的串口文件
0, //0:同步方式,FILE_FLAG_OVERLAPPED:異步方式
NULL);//用於複製文件句柄,默認值爲NULL,對串口而言該參數必須置爲NULL
}
else
{
//異步方式
hCom = CreateFileA(portname, //串口名
GENERIC_READ | GENERIC_WRITE, //支持讀寫
0, //獨佔方式,串口不支持共享
NULL,//安全屬性指針,默認值爲NULL
OPEN_EXISTING, //打開現有的串口文件
FILE_FLAG_OVERLAPPED, //0:同步方式,FILE_FLAG_OVERLAPPED:異步方式
NULL);//用於複製文件句柄,默認值爲NULL,對串口而言該參數必須置爲NULL
}
if (hCom == (HANDLE)-1)
{
return false;
}
//配置緩衝區大小
if (!SetupComm(hCom, 1024, 1024))
{
return false;
}
// 配置參數
DCB p;
memset(&p, 0, sizeof(p));
p.DCBlength = sizeof(p);
p.BaudRate = baudrate; // 波特率
p.ByteSize = databit; // 數據位
switch (parity) //校驗位
{
case 0:
p.Parity = NOPARITY; //無校驗
break;
case 1:
p.Parity = ODDPARITY; //奇校驗
break;
case 2:
p.Parity = EVENPARITY; //偶校驗
break;
case 3:
p.Parity = MARKPARITY; //標記校驗
break;
}
switch (stopbit) //停止位
{
case 1:
p.StopBits = ONESTOPBIT; //1位停止位
break;
case 2:
p.StopBits = TWOSTOPBITS; //2位停止位
break;
case 3:
p.StopBits = ONE5STOPBITS; //1.5位停止位
break;
}
if (!SetCommState(hCom, &p))
{
// 設置參數失敗
return false;
}
//超時處理,單位:毫秒
//總超時=時間係數×讀或寫的字符數+時間常量
COMMTIMEOUTS TimeOuts;
TimeOuts.ReadIntervalTimeout = 1000; //讀間隔超時
TimeOuts.ReadTotalTimeoutMultiplier = 500; //讀時間係數
TimeOuts.ReadTotalTimeoutConstant = 5000; //讀時間常量
TimeOuts.WriteTotalTimeoutMultiplier = 500; // 寫時間係數
TimeOuts.WriteTotalTimeoutConstant = 2000; //寫時間常量
SetCommTimeouts(hCom, &TimeOuts);
PurgeComm(hCom, PURGE_TXCLEAR | PURGE_RXCLEAR);//清空串口緩衝區
memcpy(pHandle, &hCom, sizeof(hCom));// 保存句柄
return true;
}
void WZSerialPort::close()
{
HANDLE hCom = *(HANDLE*)pHandle;
CloseHandle(hCom);
}
int WZSerialPort::send(string dat)
{
HANDLE hCom = *(HANDLE*)pHandle;
if (this->synchronizeflag)
{
// 同步方式
DWORD dwBytesWrite = dat.length(); //成功寫入的數據字節數
BOOL bWriteStat = WriteFile(hCom, //串口句柄
(char*)dat.c_str(), //數據首地址
dwBytesWrite, //要發送的數據字節數
&dwBytesWrite, //DWORD*,用來接收返回成功發送的數據字節數
NULL); //NULL爲同步發送,OVERLAPPED*爲異步發送
if (!bWriteStat)
{
return 0;
}
return dwBytesWrite;
}
else
{
//異步方式
DWORD dwBytesWrite = dat.length(); //成功寫入的數據字節數
DWORD dwErrorFlags; //錯誤標誌
COMSTAT comStat; //通訊狀態
OVERLAPPED m_osWrite; //異步輸入輸出結構體
//創建一個用於OVERLAPPED的事件處理,不會真正用到,但系統要求這麼做
memset(&m_osWrite, 0, sizeof(m_osWrite));
m_osWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, L"WriteEvent");
ClearCommError(hCom, &dwErrorFlags, &comStat); //清除通訊錯誤,獲得設備當前狀態
BOOL bWriteStat = WriteFile(hCom, //串口句柄
(char*)dat.c_str(), //數據首地址
dwBytesWrite, //要發送的數據字節數
&dwBytesWrite, //DWORD*,用來接收返回成功發送的數據字節數
&m_osWrite); //NULL爲同步發送,OVERLAPPED*爲異步發送
if (!bWriteStat)
{
if (GetLastError() == ERROR_IO_PENDING) //如果串口正在寫入
{
WaitForSingleObject(m_osWrite.hEvent, 1000); //等待寫入事件1秒鐘
}
else
{
ClearCommError(hCom, &dwErrorFlags, &comStat); //清除通訊錯誤
CloseHandle(m_osWrite.hEvent); //關閉並釋放hEvent內存
return 0;
}
}
return dwBytesWrite;
}
}
string WZSerialPort::receive()
{
HANDLE hCom = *(HANDLE*)pHandle;
string rec_str = "";
char buf[1024];
if (this->synchronizeflag)
{
//同步方式
DWORD wCount=1024; //成功讀取的數據字節數
BOOL bReadStat = ReadFile(hCom, //串口句柄
buf, //數據首地址
wCount, //要讀取的數據最大字節數
&wCount, //DWORD*,用來接收返回成功讀取的數據字節數
NULL); //NULL爲同步發送,OVERLAPPED*爲異步發送
for (int i = 0; i < strlen(buf); i++)
{
if (buf[i] != -52)
{
//cout << buf[i];
rec_str += buf[i];
//revcmsg.push_back(buf[i]);
}
else
{
break;
}
}
return rec_str;
}
else
{
//異步方式
DWORD wCount = 1024; //成功讀取的數據字節數
DWORD dwErrorFlags; //錯誤標誌
COMSTAT comStat; //通訊狀態
OVERLAPPED m_osRead; //異步輸入輸出結構體
//創建一個用於OVERLAPPED的事件處理,不會真正用到,但系統要求這麼做
memset(&m_osRead, 0, sizeof(m_osRead));
m_osRead.hEvent = CreateEvent(NULL, TRUE, FALSE, L"ReadEvent");
ClearCommError(hCom, &dwErrorFlags, &comStat); //清除通訊錯誤,獲得設備當前狀態
if (!comStat.cbInQue)return 0; //如果輸入緩衝區字節數爲0,則返回false
//std::cout << comStat.cbInQue << std::endl;
BOOL bReadStat = ReadFile(hCom, //串口句柄
buf, //數據首地址
wCount, //要讀取的數據最大字節數
&wCount, //DWORD*,用來接收返回成功讀取的數據字節數
&m_osRead); //NULL爲同步發送,OVERLAPPED*爲異步發送
if (!bReadStat)
{
if (GetLastError() == ERROR_IO_PENDING) //如果串口正在讀取中
{
//GetOverlappedResult函數的最後一個參數設爲TRUE
//函數會一直等待,直到讀操作完成或由於錯誤而返回
GetOverlappedResult(hCom, &m_osRead, &wCount, TRUE);
}
else
{
ClearCommError(hCom, &dwErrorFlags, &comStat); //清除通訊錯誤
CloseHandle(m_osRead.hEvent); //關閉並釋放hEvent的內存
return 0;
}
}
for (int i = 0; i < strlen(buf); i++)
{
if (buf[i] != -52)
{
rec_str += buf[i];
//revcmsg.push_back(buf[i]);
}
else
{
break;
}
}
return rec_str;
}
}
mian.cpp文件
#include "readport.h"
int main()
{
WZSerialPort w;
//這裏是選擇端口號,其他波特率信息可在頭文件修改,或者在下面重新賦值。
if (w.open("COM3"))
{
cout << "打開成功" << endl;
cout << "在這裏我發送:恭喜發財" << endl;
w.send("恭喜發財");
//w.close();
}
else
{
cout << "打開失敗" << endl;
}
while (true)
{
//w.receive();
cout << "receive: " << w.receive() << endl;
w.revcmsg.clear();
}
return 0;
}
這樣就完成了串口之間的通信。(其實我基本沒改代碼,哈哈哈)
感謝那位大佬。
代碼都比較容易看懂,如果還想詳細瞭解一下函數解釋的話。看下面的鏈接:
c++串口通信詳解
下面再提供一些小工具給大家使用。
以下是虛擬端口工具和串口通信工具,網上都有,可自行下載。鏈接在下面
虛擬端口vspd:
串口工具:
XCOM V2.0
百度雲盤鏈接:(永久有效)
https://pan.baidu.com/s/13ew5x0dJuGf8zi8BZgZKcw
提取碼
3lw0