C++编写串口通信协议

不问归期 提交于 2020-01-02 23:56:57

无论是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);
};

 

 

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!