原创 C#调用C++函数来与串口通信收藏

2009-9-5 20:41 3934 6 6 分类: 软件与OS


前些日子帮朋友写个小软件,要求用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#中直接调用。

PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
EE直播间
更多
我要评论
0
6
关闭 站长推荐上一条 /3 下一条