无论是R485还是R232,都不影响我们编程。
1、编写串口通信的接口
class CSerialPort
{
public:
CSerialPort(bool bIsRs232 );
~CSerialPort(void);
public:
bool InitPort(UINT portNo=1,UINT baud=CBR_9600,UINT databits=8,UINT stopbits=1);
bool InitPort(UINT portNo,const LPDCB& plDCB);//初始化串口
bool WriteData(unsigned char* pData,unsigned int length);//读数据
bool ReadData( unsigned char *pData,int nBytes ); //写数据
DWORD GetByteInCom();//获取串口缓冲区的字节数
void ClosePort();//关闭串口
bool ClearAllBuffer();//清除缓冲区数据
private:
bool OpenPort(UINT portNo);
private:
volatile HANDLE m_hComm;
bool m_bIsRS232;
};
2、基本类图
通信基类接口:
#pragma once
#include "SerialPort.h"
#include "DebugLog.h"
#include <vector>
#include "DataStruct.h"
#include "DebugLog.h"
#ifdef COMMUNICATION_EXPORTS
#define COMMUNICATIONAPI __declspec(dllexport)
#else
#define COMMUNICATIONAPI __declspec(dllimport)
#endif
#pragma warning(disable:4251)
class COMMUNICATIONAPI CommunicationBase
{
public:
CommunicationBase( const char* pModelName,bool bIsRs232 );
~CommunicationBase();
private:
std::vector<unsigned long> m_nRFlags;
std::vector<TimerData> m_TimerData;
protected:
bool GetR(unsigned int nIndex, unsigned int nBit);
void SetR(unsigned int nIndex, unsigned int nBit);
void RstR(unsigned int nIndex, unsigned int nBit);
void RstAllBit(unsigned int nIndex);
void RstAllR();
bool CheckIsAllReset();
void InitTimer(unsigned int nIndex, double time); //时间单位为毫秒
bool IsTimerEnd(unsigned int nIndex);
void RstTimer(unsigned int nIndex);
protected:
void ResetRSize(unsigned short nSize);
void ResetTimerSize(unsigned short nSize);
void GetCriticalSection(CRITICAL_SECTION** psync);
private:
CSerialPort* m_pSerialPort;//串口模块
DebugLog* m_pDebugLog;//日志模块
bool m_bIsSerialPortInited;
bool m_bIsEnableCommLog;
bool m_bIsEnableModelLog;
UINT m_nPortNum;
UINT m_nBaud;
UINT m_nDatabits;
UINT m_nStopbits;
protected:
CRITICAL_SECTION m_csRSync;
protected:
void WriteLog(LPCTSTR pData);
void WriteLogA(const char* sz_str);
void WriteCommLog(LPCTSTR pData);
void WriteCommLogA(const char* sz_str);
public:
void EnableCommLog(bool flag);
void EnableModelLog(bool flag);
void WriteModelLog(LPCTSTR pData);
void WriteModelLogA(const char* sz_str);
void GetLogThreadInfo(long& nRecursionCount, DWORD& nThreadID, DWORD& nCurrentThreadID); //测试使用
protected:
bool InitSerialPortParam(UINT portNo = 1, UINT baud = CBR_9600, UINT databits = 8, UINT stopbits = 1);
void CloseSerialPort();
bool ResetSerialPortParam(UINT portNo = 1, UINT baud = CBR_9600, UINT databits = 8, UINT stopbits = 1);
bool ReInitSerialPortParam();
bool SerialPortSendDatas(unsigned char* pData, unsigned int length);
UINT SerialPortGetBytesInCome();
bool SerialPortRecvDatas(unsigned char *pData, int nBytes);
bool SerialPortClearAllBuffer();
};
数据结构DataStruch.h
#pragma once
typedef struct tdTimerData
{
long long nStartTime;
long long nEndTime;
double Time;
tdTimerData()
{
nStartTime = 0;
nEndTime = 0;
Time = 0;
}
void Rst()
{
nStartTime = 0;
nEndTime = 0;
Time = 0;
}
}TimerData;
//仪表应答数据
typedef struct stMeterDataStruct
{
unsigned char nID;
bool bResultDataUpdate;
unsigned short nResultDataCount;
unsigned char ResultData[1024];
stMeterDataStruct()
{
Rst();
}
void Rst()
{
nID = 0;
bResultDataUpdate = false;
nResultDataCount = 0;
memset(ResultData, 0, 1024);
}
}MeterDataStruct;
typedef struct tagPwrRWStruct
{
float fVolSet;
float fCrtSet;
int nPwrSlaveID;
int nErrCode;
bool bStartRW;
bool bRWEnd;
void Rst()
{
fVolSet=0.0f;
fCrtSet=0.0f;
nPwrSlaveID=0;
nErrCode=0;
bStartRW=false;
bRWEnd =false;
}
}PwrSetStruct;
/* ModusBusComm */
#define MBC_MAX_BUF_ID 0xFF
//ErrorCode
#define MBC_ECD_OK 0x00 // 正常状态
#define MBC_ECD_RUNING 0x01 // 正在运行
#define MBC_ECD_BUSY 0x02 // 线程忙
#define MBC_ECD_SP_WDER 0x03 // 串口写数据异常
#define MBC_ECD_SP_RDER 0x04 // 串口读数据异常
#define MBC_ECD_PT_FBER 0x05 // 协议标志位指示指令执行失败
#define MBC_ECD_PT_DAER 0x06 // 非协议数据格式
#define MBC_ECD_PT_CRCER 0x07 // CRC校验出错
#define MBC_ECD_CMD_TIMEOUT 0x08 // 指令周期超时
#define MBC_ECD_ACK_TIMEOUT 0x09 // 等待回应超时
/* TestMeterComm */
#define TMC_MAX_BUF_ID 0xFF
#define TMC_SPCL_TIMEOUT_OFFSET 200
//ErrorCode
#define TMC_ECD_OK 0x00 // 正常状态
#define TMC_ECD_RUNING 0x01 // 正在运行
#define TMC_ECD_BUSY 0x02 // 线程忙
#define TMC_ECD_SP_WDER 0x03 // 串口写数据异常
#define TMC_ECD_SP_RDER 0x04 // 串口读数据异常
#define TMC_ECD_PT_FBER 0x05 // 协议标志位指示指令执行失败
#define TMC_ECD_PT_DAER 0x06 // 非协议数据格式
#define TMC_ECD_PT_BCCER 0x07 // BCC校验出错
#define TMC_ECD_CMD_TIMEOUT 0x08 // 指令周期超时
#define TMC_ECD_ACK_TIMEOUT 0x09 // 等待回应超时
/* ScanComm */
#define SC_MAX_BUF_ID 2
3、具体的协议,例如仪表通讯
#pragma once
#include "CommunicationBase.h"
#include <list>
class COMMUNICATIONAPI TestMeterComm : public CommunicationBase
{
public:
TestMeterComm( const char* pModelName );
~TestMeterComm();
private:
bool m_bIsInited;
unsigned char m_DataToSendBuf[TMC_MAX_BUF_ID][1024]; //发送数据缓存区
unsigned char m_DataToRecvBuf[TMC_MAX_BUF_ID][1024]; //接收数据缓存区
unsigned short m_nDataToSendCount[TMC_MAX_BUF_ID]; //发送数据字节数
unsigned short m_nDataToRecvCount[TMC_MAX_BUF_ID]; //接收数据字节数
unsigned short m_nWaitToRecvDataCount[TMC_MAX_BUF_ID];//等待接收数据字节数
unsigned char m_nProtocolErrorCode[TMC_MAX_BUF_ID]; //协议错误代码
unsigned char m_nCurrentDataBufID; //当前缓存区ID
double m_ACKTimeOut; //等待指令回应超时时间
double m_ACKTimeOut2;//被动模式下回应超时时间
double m_CmdMaxPeriod;//最大指令周期
bool m_bIsRecvDataBufUpdate[TMC_MAX_BUF_ID]; //接收数据是否完成
bool m_bIsLoopIdel; //扫描线程是否空闲
bool m_bIsCmdExeSuccess[TMC_MAX_BUF_ID]; //指令是否执行成功
bool m_bIsCmdExeFinish[TMC_MAX_BUF_ID]; //指令是否执行完成
unsigned char m_nErrorCode[TMC_MAX_BUF_ID]; //错误代码
bool m_bIsSpecialHandle[TMC_MAX_BUF_ID]; //是否特殊处理
bool m_bIsSpecialHandle_TimeOut[TMC_MAX_BUF_ID]; //延时是否特殊处理
bool m_bIsClearBufTask[TMC_MAX_BUF_ID]; //被动触发模式下,是否为清串口缓存区任务
bool m_bIsSpecialHandle_Check;
private:
std::vector<unsigned char> RecvDataList;
HANDLE m_hThead;
HANDLE m_hEvent;
void InitThread();
static unsigned int __stdcall ThreadProcMode2(void* pParam);//指令读写,要求有回应
unsigned int m_nProcThreadID;
private:
void AppendBCC(unsigned char *CmmBuf, unsigned char DataLen,unsigned char nStartIndex = 1);//追加异或校验
bool BCC_Check(const unsigned char* pData, unsigned int nDataLen);
protected:
bool SendData(unsigned char nItemCount, unsigned char nStartAddr, unsigned int* pData, unsigned char nThreadID );
bool SendReadDataCmdMode2(unsigned short nWaitToReadDataCount,unsigned char nThreadID ); // 外部触发式
bool SendReadDataCmdMode1(unsigned char nItemCount, unsigned char nStartAddr,unsigned char nThreadID ); // 应答式
unsigned int GetRecvData(unsigned char*pData, unsigned int nDataCount,unsigned char nThreadID );
bool SetToWaitRecvDataCount(unsigned short nCount, unsigned char nThreadID );
bool SetSpecialHandle(bool bIsSpecial,unsigned char nThreadID ); // 特殊处理模式下判断接收长度从设置的参数中判断不在从协议中去取
bool SetSpecialHandle_TimeOut(bool bIsSpecial, unsigned char nThreadID); //超时特殊处理
bool SetSpecialHandle_Check(bool bIsSpecial);
bool ForceExitThread();
public:
bool InitModel(UINT portNo = 1, UINT baud = CBR_9600, UINT databits = 8, UINT stopbits = 1);
bool IsRecvDataFinish(unsigned char nThreadID );
bool SetAckTimeOut(unsigned short nTimeOut);
bool IsIdle(); //任务是否空闲
bool IsCmdExeSuccess(unsigned char nThreadID );
bool IsCmdExeFinish(unsigned char nThreadID );
bool IsClearBufTask(unsigned char nThreadID);
bool SendClearBufTaskCmdMode2(unsigned char nThreadID);
bool IsIdle(unsigned short nTimeOut);
bool IsCmdExeFinish(unsigned char nThreadID, unsigned short nTimeOut);
bool StopThread();
unsigned char GetErrorCode(unsigned char nFlag = 0, unsigned char nThreadID = 0); //获取错误代码
void GetThreadInfo(long& nRecursionCount, DWORD& nThreadID, DWORD& nCurrentThreadID, DWORD& nSubThreadID); //测试使用
bool StartThread();
protected:
bool CheckCmdIsSuccess(unsigned char nThreadID, unsigned int nTimeOut);
};
来源:CSDN
作者:淡月明
链接:https://blog.csdn.net/sinat_31608641/article/details/103811030