前些日子帮朋友写个小软件,要求用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;
}

/******************************************************************************
*函数功能:打开串口,设置串口参数
*参数说明:
    nCom:操作的串口值,如COM1:,COM2:等等
    lnBaudrate: 波特率
    nStopbits: 停止位
    nDatabits: 数据位
    nParity:奇偶校验
*返回值: 返回串口的句柄
*时间:2008/10/22
*作者:XiangDing
*****************************************************************************/
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[i]);
   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[i];
  if(hstr==' ')
  {
   i++;
   continue;
  }
  i++;
  if(i>=len)
   break;
  lstr=str[i];
  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导出函数实现:
/*
返回值:
 -9: 打开串口失败。
 -1: 往串口写数据失败。
 -2: 清除串口错误失败。
 -3: 串口返回数据为0。
  正值: 返回正常。
*/

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#中直接调用。

二. C#调用的代码就更简单啦,像平常调API函数一样,用DllImport声明一下即可。这时就不多讲了。

本人一直从事mobile/wince/linux平台下开发,使用C++虽有多年,但觉得自已对很多底层细节技术理解仍不够深刻,希望有机会得到高手指点

C#调用C++函数来与串口通信相关推荐

  1. 基于API函数的串口通信(方法讲解)

    用到的串口通信编程方法有:使用通信控件.在高级语言中嵌入汇编以及使用API函数.在这几种方法中,使用API函数编写的串口通信程序最为高效.灵活.串口通信编程将用到三种API函数 --串口通信相关API ...

  2. Ariduino入门笔记——9. Arduino 默认函数(串口通信)

    文章目录 什么是串口 Serial 串口函数 串口准备--if(Serial) 获取可读取的字节数--available() 获取可写入的最大字节数--availableForWrite() 串口连接 ...

  3. windows串口通信函数API

    windows串口通讯主要函数 先列个目录表 1.CreateFile - 打开串口: 2.SetupComm-初始化一个指定的通信设备的通信参数 3.ReadFile - 读数据: 4.WriteF ...

  4. VC串口通信编程-2

    VC串口通信编程 (2009-07-08 13:48:40) 转载▼ Win32串口编程(转:韩耀旭) 在工业控制中,工控机(一般都基于Windows平台)经常需要与智能仪表通过串口进行通信.串口通信 ...

  5. 串口通信模块3:串口通信编程基础(读写、关闭)

    上一节总结了如何打开串口并讨论了如何配置串口,本节是在上一节的基础上,进一步讨论串口编程的基础--如何进行文件读写?如何关闭串口? 1. 读写串口 串口的读写操作和文件的读写操作是一样的,也是通过Re ...

  6. 串口通信模块2:串口通信编程基础(打开、配置)

    有两种方式可以操作串口:同步操作方式和异步操作方式(即重叠操作方式).同步操作时,API函数会阻塞直到操作完成以后才能返回(在多线程方式中,虽然不会阻塞主线程,但是仍然会阻塞监听线程):而异步操作方式 ...

  7. 基于VC++开发串口通信的方法

    串行通信中的关键是串行通信设备的初始化.数据的发送和接收及其实现方式. 在Dos环境下,用户可以直接对通信设备编程,可以通过查询中断的方式使用通信设备.但是Windows不提倡应用程序直接控制硬件,而 ...

  8. C/C++串口通信原理及读写与操作

    http://wangbaiyuan.cn/c-serial-communication-write-reading.html [展开]文章目录 在工业控制中,工控机(一般都基于Windows平台)经 ...

  9. 详解 Qt 串口通信程序全程图文 (2)

    Qt 串口通信程序全程图文是本文介绍的内容,上一部分中已经介绍了实现最简单的串口接收程序的编写,下面将对程序内容进行分析. 1.首先应说明操作串口的流程 步骤一:设置串口参数,如:波特率,数据位,奇偶 ...

最新文章

  1. Django Python:完整的BUNDLE + Django真实项目2021
  2. SQLSERVER2014中的新功能
  3. GridView滚动条
  4. BeetleX服务网关流量控制
  5. qt商业版和开源版的区别_微擎商业版系统V2.0.9全开源版纯净框架
  6. 飞秋官方下载 访问我博客也有近一半的用户
  7. ES6函数相关包含箭头函数
  8. sqlserver模仿mysql函数FIND_IN_SET,group_concat的功能
  9. Visual C++ 2008入门经典 第十章标准模板库(二)
  10. 抢占计算机与通信设备未来产业制高点 ——《信息产业发展指南》解读
  11. 读书:雨果的《巴黎圣母院》
  12. 第三章 3.4 DI之Bean的作用域 --《跟我学Spring》笔记 张开涛
  13. 《软件质量保证与测试》读书笔记(一)
  14. 显卡煲机测试软件,铁三角耳机煲机方法三分钟让您学会煲耳机
  15. 哪个说了算?漫谈网吧网络的稳定和安全(转)
  16. protoc安装配置
  17. setpositivebutton
  18. Hbase Locality
  19. android miui连接开发者选项,(最详细)MIUI11系统的Usb调试模式在哪里开启的步骤
  20. hyperopt/hyperas

热门文章

  1. 2021甘肃高考成绩查询时间几点,2021年甘肃高考成绩什么时候出来,今天几点钟出成绩可以查询...
  2. vivado 综合报错 “ incorrect freePtr. Call out of sequence? “
  3. js php 分段上传文件,php+js实现文件分块上传
  4. python在哪些控制结构中使用else保留字_python的程序控制结构-循环结构与random库使用和圆周率案例--pyt...
  5. pb界面框架开发_CATIA CAA二次开发草图界面框架类:CATSketcherCommands
  6. 简易无接触温度测量与身份识别装置【2020年大学生电子设计竞赛F题】
  7. 突发!百度CEO李彦宏被当中泼了一瓶水,肇事者网名:直男上树
  8. ultra96-v2通过网线连接PC传输文件
  9. linux系统下4k对齐,linux查看硬盘4K对齐方法
  10. java邮件中添加excel_使用java api 创建excel内容并发送邮件