前些日子帮朋友写个小软件,要求用C#来实现主程序,主要的功能是与一些通信设备打交道,当然就是通过串口了,以十进制发送和读取串口
的数据,考虑到C#调用API并没有C++来得方便,因此,我用C++封装了一个读写串口的DLL,只提供一个函数供外部调用,这样的好处在于,C#
只要调用这个函数发送完数据后,函数立即就能获得串口返回的数据。另一个好处在于,一些不熟悉C++的朋友,也能够直接通过这个DLL来对
串口做一些操作。
杂话就不多讲了,直接贴这个读写串口的dll代码:
一. C++部分:
1)头文件:
// SerialPortSync.h: interface
for the CSerialPortSync class.
//
//////////////////////////////////////////////////////////////////////
#if
!defined(AFX_SERIALPORTSYNC_H__7FC698BB_BF4D_449E_8DE9_62B8876187CF__INCLUDED_)
#define
AFX_SERIALPORTSYNC_H__7FC698BB_BF4D_449E_8DE9_62B8876187CF__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
class CSerialPortSync
{
public:
CSerialPortSync();
public:
bool Open(int nPort, int nBaud,int nDatabit, int
nStopbit, int nParity, int nTimeOut = 500);
DWORD SendData(const char *buffer, const unsigned
int writebytes, char *RecBuffer, int nSendType = 1);
void Close();
private:
HANDLE m_hCom; //串口句柄
bool m_bOpened;
char ConvertHexChar(char ch);
int String2Hex(const char *str, const unsigned
int nLen, byte *senddata);
};
#endif //
!defined(AFX_SERIALPORTSYNC_H__7FC698BB_BF4D_449E_8DE9_62B8876187CF__INCLUDED_)
2). CPP文件:
// SerialPortSync.cpp: implementation of the CSerialPortSync
class.
//
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
//#include "SerialPortDemo.h"
#include "SerialPortSync.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
#define MAXSENDLENGTH 20
#define MAXRECEIVELENGTH 20
CSerialPortSync::CSerialPortSync()
{
m_bOpened = false;
}
bool CSerialPortSync::Open(int nPort, int nBaud,int nDatabit,int
nStopbit,int nParity, int nTimeOut)
{
if( m_bOpened ) return( true );
char strPort[10]={0};
sprintf(strPort,"COM%d",nPort);
m_hCom=CreateFile(strPort,
GENERIC_READ|GENERIC_WRITE, 0, NULL ,OPEN_EXISTING, 0,NULL);
if ((m_hCom==INVALID_HANDLE_VALUE) ||
(m_hCom==NULL ))
{
m_bOpened = false;
return false;
}
COMMTIMEOUTS ct;
ct.ReadIntervalTimeout
=
MAXDWORD;
//设置超时设置
ct.ReadTotalTimeoutMultiplier = 0;
ct.ReadTotalTimeoutConstant
= nTimeOut;
ct.WriteTotalTimeoutMultiplier = 0;
ct.WriteTotalTimeoutConstant =
nTimeOut;
SetCommTimeouts( m_hCom, &ct
);
DCB dcb;
GetCommState( m_hCom, &dcb
);
dcb.BaudRate
= nBaud;
dcb.StopBits
= nStopbit;
dcb.Parity
= nParity;
dcb.ByteSize
=
(BYTE)nDatabit;
// number of bits/byte, 4-8
BOOL bl = SetCommState( m_hCom,
&dcb );
m_bOpened = TRUE;
return true;
}
// nSendType 1: 以十六进制发送. 0: 直接发送字符串
//返回值是已接收的个数
//返回 -1: 写串口失败. -2:清除串口错误; -3: 串口返回数据为0;
DWORD CSerialPortSync::SendData(const char *sendBuffer, const
unsigned int writebytes, char *RecBuffer, int nSendType)
{
if( !m_bOpened ) return 0;
DWORD
dwWritten = 0;
DWORD
dwError;
DWORD dwBytesRead = 0;
if (nSendType == 1)
{
byte bHexData[MAXSENDLENGTH] =
{0};
memset(bHexData, 0,
MAXSENDLENGTH);
int len =
String2Hex(sendBuffer, writebytes, bHexData);
BOOL bWriteRet = FALSE;
bWriteRet = WriteFile(m_hCom, bHexData, len,
&dwWritten, NULL);
BOOL bReadStatus;
BYTE bReadBuf[MAXRECEIVELENGTH]
= {0};
bReadStatus = ReadFile(
m_hCom, bReadBuf, MAXRECEIVELENGTH, &dwBytesRead,
NULL);
if (dwBytesRead
<1 ) return dwBytesRead;
CString strBuf;
CString strTemp;
for(int i=0;
i<dwBytesRead; i++ )
{
strTemp.Format("%02X",
bReadBuf);
strBuf +=
strTemp;
}
strBuf.TrimRight();
strncpy(RecBuffer,
(LPCTSTR)strBuf, dwBytesRead * 2 + 1);
return dwBytesRead;
}
return dwBytesRead;
}
void CSerialPortSync::Close()
{
if(m_hCom !=
INVALID_HANDLE_VALUE)
{
CloseHandle(m_hCom);
m_hCom =
INVALID_HANDLE_VALUE;
}
if( m_bOpened ) m_bOpened = false;
}
//由于这个转换函数的格式限制,在发送框中的十六制字符应该每两个字符之间插入一个空隔
//如:A1 23 45 0B 00 29
int CSerialPortSync::String2Hex(const char *str, const unsigned int
nLen, byte *senddata)
{
int hexdata,lowhexdata;
int hexdatalen=0;
int len=nLen;
for(int i=0;i<len;)
{
char lstr,hstr=str;
if(hstr==' ')
{
i++;
continue;
}
i++;
if(i>=len)
break;
lstr=str;
hexdata=ConvertHexChar(hstr);
lowhexdata=ConvertHexChar(lstr);
if((hexdata==16)||(lowhexdata==16))
break;
else
hexdata=hexdata*16+lowhexdata;
i++;
senddata[hexdatalen]=(char)hexdata;
hexdatalen++;
}
// senddata.SetSize(hexdatalen);
return hexdatalen;
}
//这是一个将字符转换为相应的十六进制值的函数
//功能:若是在0-F之间的字符,则转换为相应的十六进制字符,否则返回-1
char CSerialPortSync::ConvertHexChar(char ch)
{
if((ch>='0')&&(ch<='9'))
return ch-0x30;
else
if((ch>='A')&&(ch<='F'))
return ch-'A'+10;
else
if((ch>='a')&&(ch<='f'))
return ch-'a'+10;
else
return (-1);
}
3) DLL导出函数实现:
SERIALPORT_DLL int __stdcall SendData(int nPort, int nBaud,int
nDatabit,int nStopbit,
int nParity, const char
*sendBuffer, int writebytes,
char *RecBuffer, int nSendType,
int nTimeOut)
{
CSerialPortSync sPort;
if
(!sPort.Open(nPort,nBaud,nDatabit,nStopbit,nParity))
{
return -9;
}
int nReadCount = sPort.SendData(sendBuffer,
writebytes, RecBuffer);
sPort.Close();
return nReadCount;
}
4).
我为什么要用类来实现C++的串口读写呢,主要也是方便C++开发人员可以直接使用该类,而C#的开发人员,直可以通过上面第三步,导出
到dll中,在C#中直接调用。
文章评论(0条评论)
登录后参与讨论