C#中如何向COM口发送数据,并监听传回的数据,以控制单片机?

时间:2022-08-30 23:23:13
RS232通讯方式,数据示例:0xBF,0xD7,0B0H,0E0H,C2H....,0xBF,0xBF
请问如何通过在C#下写代码实现想COM口发送上列数据?
又如何知道COM口已发回数据且知道发回的数据是什么?
请高手帮忙回答啊!谢谢!

15 个解决方案

#1


这些东西只能调用api了,C#本身对硬件的控制能力有限,这类问题基本上需要用api.

#2


C#本身的定位就不是干这个的,
比较推荐的解决方法是用c写dll,然后在C#中调

#3


不是吧,好象听说有一个控件可以实现的啊?

#4


用API了同意mmqingfeng(漠漠青峰) 的解决方案

#5


The Question is : 俺目前的水平写不来任何DLL文件,有没有相关文档可以参考啊???
就算有,因为工程进度紧急,现在开始看肯定来不及了
我现在最迫切的要求是知道如何能实现在C#里用控件方式向COM实现发送指令
监听的问题实在不行我每秒刷新一次也可以
谢谢各位了啊!

#6


帮顶

#7


msdn里面有一个C#的RS232控件,我下载了可是没有用过。你去找找看

#8


简单的话就使用VB6中带有的MSCOMM.OCX控件.

#9


貌似就是楼上的兄弟提到的那个控件
有知道的高手么?谢谢帮忙了啊!麻烦能不能告诉我这个控件的详细用法???

#10


.NET is a high-level framework
and doesn't support direct port access.


My Serial Port FAQ:

  .NET 1.0 has no support for legacy ports (COM/LPT).

  There are plans to add support for serial ports in a future version:
      http://groups.google.com/groups?&selm=O%23vQLn9bCHA.392%40tkmsftngp09
    "this sample is very similar to what we will be adding" :
      http://www.gotdotnet.com/userarea/filedetails.aspx?FileName=SerialPort.zip
       (note, project built with beta VS.NET, read gotdotnet comments)

  With 1.0 you have to use PInvoke or Interop :

  First understand the Win32 API as described here (C++):
     http://msdn.microsoft.com/library/en-us/dnfiles/html/msdn_serial.asp

  New MSDN article for .NET (mostly C#):
     http://msdn.microsoft.com/msdnmag/issues/02/10/NETSerialComm/

  PInvoke samples for C#:
     http://www.gotdotnet.com/userarea/filedetails.aspx?FileName=SerialPort.zip
     http://msdn.microsoft.com/msdnmag/issues/02/10/NETSerialComm/

   or for VB.NET:
      http://msdn.microsoft.com/library/en-us/dnvssamp/html/vbcs_usingthecomportinvbnet.asp


My Parallel Port FAQ:

  If you have to send raw data to a printer:

    HOW TO: Send Raw Data to a Printer by Using Visual C# .NET :
      http://support.microsoft.com/?kbid=322091


  If you want to control the port pins:
  You have to install some kind of hardware drivers!
   (Warning: will impact system security/reliability)

   for .NET : TSIO  (generic IO)
     www.thoroughsoft.com
     http://65.184.102.81/thoroughsoft/products/Products_TSIO/Products_TSIO.aspx

   commercial, specific for printer ports, e.g.:
     http://www.zealsoftstudio.com/ntport/download.html
     http://www.ntport.com/

   C++/Win32
     http://www.entech*.com/tviclpt.htm
     http://www.internals.com/

  For more information about ports, check this sites:
    http://www.lvr.com/parport.htm
    http://www.beyondlogic.org


My USB Port FAQ:

  USB is a hardware bus and as such not directly exposed
  to user-mode (Win32) applications (or even .NET).
  Only Windows device-drivers do control the USB.
    => get a driver from manufacturer.

  So if you connect a printer with USB, use the Win32/.NET printer-API.
  Or if you connect a modem with USB, use the Win32 serial-API.
  Or if you connect an imaging device (camera/scanner), use TWAIN/WIA.

     If you want to design your own external, USB compliant hardware,
     you have to understand the USB bus protocol
     and implement a controller chip.
     Then on Windows side, you have to write your own
     device driver with the Windows DDK.
     Sure there are OEM kits making all this easier.

     Please visit sites like:
       http://www.usb.org/
       http://www.microsoft.com/hwdev/bus/USB/
       http://www.lvr.com/usb.htm
       http://www.beyondlogic.org
     and learn the technology.

#11


VB6中带有的MSCOMM.OCX的控件也可以用,但在C#不太好用,如果楼主用c#开发的化,我这儿有个控件用起来很方便.已经给用在流水线上的工控了,把你的mail给我

#12


MSCOMM.OCX挺好用的。包装一下自己写一个Container就更方便了。

#13


KentYu(恳鱼)朋友谢谢啊!我已经给你发消息了!在这里也留一下我的信箱吧!
namatree@citiz.net
再次感谢!

#14


串口开发
http://www.codeproject.com/dotnet/DotNetComPorts.asp
http://msdn.microsoft.com/msdnmag/issues/02/10/NETSerialComm/default.aspx

在篇文章展示了使用C#与RS232通信。
P/Invoke是.NET的技术,以使用托管的代码(c#)调用非托管的DLL(C++)
包括执行Win32 API.在这篇文章中我们将使用C#封装串中RS232的API函数,
目的是使用C#开发串口更加方便。
设计原理
这里有四个设计原则是您应该在设计类库考虑的。
1.使用P/Invoke封装API时,常数、结构使用静态域。
2.写一个流控制。
3.建立一个代替MSCOMM的控件,
4.写一个继承的类库。
我们将使用第4种方法.这个类库包括两个抽象基类。使用它们的程序将继承这个类。
第一个类CommBase,用作数据格式,串口的打开、关闭、数据的接收、发送...
第二个类CommLine继承于CommBase,控件编码于解码。
使用基类
1.这里有两个应用程序BaseTerm(C#的WinForm),LineTerm(VB控件台)
2.使用源程序
Lin1e:从Dll中引入名称空间,建立一个新类,

#15


硬盘里的一篇文章,以前从http://www.codeguru.com/找的

The Approach
The way out was to import the access functions from kernel32. A standard way to access API functions is using DLL Import. So, I decided to import three functions:

Create File—to open the COM port. 
Write File—to send commands. 
Read File—to read information. 
And of course, you won't get away without using the Get Last Error.

//file open masks
const uint GENERIC_READ  = 0x80000000;
const uint GENERIC_WRITE = 0x40000000;
const uint OPEN_EXISTING = 3;

[DllImport("kernel32", SetLastError=true)]
static extern unsafe int CreateFile(
  string filename,       // file name
  uint desiredAccess,    // read? write?
  uint shareMode,        // sharing
  uint attributes,       // SecurityAttributes pointer
  uint creationDisposition,
  uint flagsAndAttributes,
  uint templateFile);

[DllImport("kernel32", SetLastError=true)]
static extern unsafe bool ReadFile(int hFile,  // handle to file
  void* lpBuffer,                              // data buffer
  int nBytesToRead,                            // number of bytes
                                               // to read
  int* nBytesRead,                             // number of bytes
                                               // read
  int overlapped);                             // overlapped buffer

[DllImport("kernel32", SetLastError=true)]
static extern unsafe bool WriteFile(int hFile, // handle to file
  void* lpBuffer,                              // data buffer
  int nBytesToWrite,                           // number of bytes
                                               // to write
  int* nBytesWritten,                          // number of bytes
                                               // written
  int overlapped);                             // overlapped buffer

[DllImport("kernel32", SetLastError=true)]
static extern int GetLastError();

The Code
The next step is to use these functions in your code and get the getting going.

Note: I have changed my WriteLogFile function to console.writeline for easy understanding.
/// <summary>
/// Connect to the COM Port.
/// </summary>
private void GetDevice(string Port)
{
  // open the existing port...
  m_ihandle = CreateFile(Port,
    GENERIC_READ | GENERIC_WRITE,
    0,              // comm devices must be opened
                    // w/exclusive-access
    0,              // no security attributes
    OPEN_EXISTING,  // comm devices must use OPEN_EXISTING
    0,              // not overlapped I/O
    0);             // hTemplate must be NULL for comm devices
  //if the handle value is -1, that means you got an error....
  if(m_ihandle == -1)
    //write failure log
    Console.WriteLine("open COM port failed" + GetLastError());
  else
    //write success log
    Console.WriteLine(Port + " opened successfully!");
}

/// <summary>
/// Send Command to the COM Port.
/// As I am using a modem, I send command like "AT+CGMM"
/// </summary>
private unsafe void SendCommand(string szCmd)
{
  int i = 0, n = 0;
  //get string length
  int Len = szCmd.Length;
  //use ASCIIEncoding to work with byte and string
  ASCIIEncoding e = new ASCIIEncoding();
  //assign string to byte buffer and add "return"
  byte[]Buffer = e.GetBytes(szCmd + "\r\n");
  //use fixed to avoid more memory allocation
  fixed (byte* p = Buffer)
  {
    i=0;
    //write command to the port
    if(!WriteFile(m_ihandle, p + i, Len+1, &n, 0))
      //if false, write failure log
      Console.WriteLine("Send Command " + szCmd + " failed");
    else
      // write success log
      Console.WriteLine("Send Command Successed");
  }
}
/// <summary>
/// Read information from the COM Port.
/// </summary>
private unsafe void ReadModem()
{
  //set the maximum limit to read
  int count = 128;
  //create buffer to store the info
  byte[] buffer = new byte[count];
  //use ASCII encoding to work with string and byte
  ASCIIEncoding e = new ASCIIEncoding();
  //loop through read until done...
  int index = 0;
  int n = 1;
  while (n!=0)
  {
    n = 0;
    fixed (byte* p = buffer)
    {
      //read file
      if(!ReadFile(m_ihandle, p + index, count, &n, 0))
        //write the value received in log
        Console.WriteLine(e.GetString(buffer));
      else
        //write failure log
        Console.WriteLine("Read Modem Failed");
    }
  }
}

#1


这些东西只能调用api了,C#本身对硬件的控制能力有限,这类问题基本上需要用api.

#2


C#本身的定位就不是干这个的,
比较推荐的解决方法是用c写dll,然后在C#中调

#3


不是吧,好象听说有一个控件可以实现的啊?

#4


用API了同意mmqingfeng(漠漠青峰) 的解决方案

#5


The Question is : 俺目前的水平写不来任何DLL文件,有没有相关文档可以参考啊???
就算有,因为工程进度紧急,现在开始看肯定来不及了
我现在最迫切的要求是知道如何能实现在C#里用控件方式向COM实现发送指令
监听的问题实在不行我每秒刷新一次也可以
谢谢各位了啊!

#6


帮顶

#7


msdn里面有一个C#的RS232控件,我下载了可是没有用过。你去找找看

#8


简单的话就使用VB6中带有的MSCOMM.OCX控件.

#9


貌似就是楼上的兄弟提到的那个控件
有知道的高手么?谢谢帮忙了啊!麻烦能不能告诉我这个控件的详细用法???

#10


.NET is a high-level framework
and doesn't support direct port access.


My Serial Port FAQ:

  .NET 1.0 has no support for legacy ports (COM/LPT).

  There are plans to add support for serial ports in a future version:
      http://groups.google.com/groups?&selm=O%23vQLn9bCHA.392%40tkmsftngp09
    "this sample is very similar to what we will be adding" :
      http://www.gotdotnet.com/userarea/filedetails.aspx?FileName=SerialPort.zip
       (note, project built with beta VS.NET, read gotdotnet comments)

  With 1.0 you have to use PInvoke or Interop :

  First understand the Win32 API as described here (C++):
     http://msdn.microsoft.com/library/en-us/dnfiles/html/msdn_serial.asp

  New MSDN article for .NET (mostly C#):
     http://msdn.microsoft.com/msdnmag/issues/02/10/NETSerialComm/

  PInvoke samples for C#:
     http://www.gotdotnet.com/userarea/filedetails.aspx?FileName=SerialPort.zip
     http://msdn.microsoft.com/msdnmag/issues/02/10/NETSerialComm/

   or for VB.NET:
      http://msdn.microsoft.com/library/en-us/dnvssamp/html/vbcs_usingthecomportinvbnet.asp


My Parallel Port FAQ:

  If you have to send raw data to a printer:

    HOW TO: Send Raw Data to a Printer by Using Visual C# .NET :
      http://support.microsoft.com/?kbid=322091


  If you want to control the port pins:
  You have to install some kind of hardware drivers!
   (Warning: will impact system security/reliability)

   for .NET : TSIO  (generic IO)
     www.thoroughsoft.com
     http://65.184.102.81/thoroughsoft/products/Products_TSIO/Products_TSIO.aspx

   commercial, specific for printer ports, e.g.:
     http://www.zealsoftstudio.com/ntport/download.html
     http://www.ntport.com/

   C++/Win32
     http://www.entech*.com/tviclpt.htm
     http://www.internals.com/

  For more information about ports, check this sites:
    http://www.lvr.com/parport.htm
    http://www.beyondlogic.org


My USB Port FAQ:

  USB is a hardware bus and as such not directly exposed
  to user-mode (Win32) applications (or even .NET).
  Only Windows device-drivers do control the USB.
    => get a driver from manufacturer.

  So if you connect a printer with USB, use the Win32/.NET printer-API.
  Or if you connect a modem with USB, use the Win32 serial-API.
  Or if you connect an imaging device (camera/scanner), use TWAIN/WIA.

     If you want to design your own external, USB compliant hardware,
     you have to understand the USB bus protocol
     and implement a controller chip.
     Then on Windows side, you have to write your own
     device driver with the Windows DDK.
     Sure there are OEM kits making all this easier.

     Please visit sites like:
       http://www.usb.org/
       http://www.microsoft.com/hwdev/bus/USB/
       http://www.lvr.com/usb.htm
       http://www.beyondlogic.org
     and learn the technology.

#11


VB6中带有的MSCOMM.OCX的控件也可以用,但在C#不太好用,如果楼主用c#开发的化,我这儿有个控件用起来很方便.已经给用在流水线上的工控了,把你的mail给我

#12


MSCOMM.OCX挺好用的。包装一下自己写一个Container就更方便了。

#13


KentYu(恳鱼)朋友谢谢啊!我已经给你发消息了!在这里也留一下我的信箱吧!
namatree@citiz.net
再次感谢!

#14


串口开发
http://www.codeproject.com/dotnet/DotNetComPorts.asp
http://msdn.microsoft.com/msdnmag/issues/02/10/NETSerialComm/default.aspx

在篇文章展示了使用C#与RS232通信。
P/Invoke是.NET的技术,以使用托管的代码(c#)调用非托管的DLL(C++)
包括执行Win32 API.在这篇文章中我们将使用C#封装串中RS232的API函数,
目的是使用C#开发串口更加方便。
设计原理
这里有四个设计原则是您应该在设计类库考虑的。
1.使用P/Invoke封装API时,常数、结构使用静态域。
2.写一个流控制。
3.建立一个代替MSCOMM的控件,
4.写一个继承的类库。
我们将使用第4种方法.这个类库包括两个抽象基类。使用它们的程序将继承这个类。
第一个类CommBase,用作数据格式,串口的打开、关闭、数据的接收、发送...
第二个类CommLine继承于CommBase,控件编码于解码。
使用基类
1.这里有两个应用程序BaseTerm(C#的WinForm),LineTerm(VB控件台)
2.使用源程序
Lin1e:从Dll中引入名称空间,建立一个新类,

#15


硬盘里的一篇文章,以前从http://www.codeguru.com/找的

The Approach
The way out was to import the access functions from kernel32. A standard way to access API functions is using DLL Import. So, I decided to import three functions:

Create File—to open the COM port. 
Write File—to send commands. 
Read File—to read information. 
And of course, you won't get away without using the Get Last Error.

//file open masks
const uint GENERIC_READ  = 0x80000000;
const uint GENERIC_WRITE = 0x40000000;
const uint OPEN_EXISTING = 3;

[DllImport("kernel32", SetLastError=true)]
static extern unsafe int CreateFile(
  string filename,       // file name
  uint desiredAccess,    // read? write?
  uint shareMode,        // sharing
  uint attributes,       // SecurityAttributes pointer
  uint creationDisposition,
  uint flagsAndAttributes,
  uint templateFile);

[DllImport("kernel32", SetLastError=true)]
static extern unsafe bool ReadFile(int hFile,  // handle to file
  void* lpBuffer,                              // data buffer
  int nBytesToRead,                            // number of bytes
                                               // to read
  int* nBytesRead,                             // number of bytes
                                               // read
  int overlapped);                             // overlapped buffer

[DllImport("kernel32", SetLastError=true)]
static extern unsafe bool WriteFile(int hFile, // handle to file
  void* lpBuffer,                              // data buffer
  int nBytesToWrite,                           // number of bytes
                                               // to write
  int* nBytesWritten,                          // number of bytes
                                               // written
  int overlapped);                             // overlapped buffer

[DllImport("kernel32", SetLastError=true)]
static extern int GetLastError();

The Code
The next step is to use these functions in your code and get the getting going.

Note: I have changed my WriteLogFile function to console.writeline for easy understanding.
/// <summary>
/// Connect to the COM Port.
/// </summary>
private void GetDevice(string Port)
{
  // open the existing port...
  m_ihandle = CreateFile(Port,
    GENERIC_READ | GENERIC_WRITE,
    0,              // comm devices must be opened
                    // w/exclusive-access
    0,              // no security attributes
    OPEN_EXISTING,  // comm devices must use OPEN_EXISTING
    0,              // not overlapped I/O
    0);             // hTemplate must be NULL for comm devices
  //if the handle value is -1, that means you got an error....
  if(m_ihandle == -1)
    //write failure log
    Console.WriteLine("open COM port failed" + GetLastError());
  else
    //write success log
    Console.WriteLine(Port + " opened successfully!");
}

/// <summary>
/// Send Command to the COM Port.
/// As I am using a modem, I send command like "AT+CGMM"
/// </summary>
private unsafe void SendCommand(string szCmd)
{
  int i = 0, n = 0;
  //get string length
  int Len = szCmd.Length;
  //use ASCIIEncoding to work with byte and string
  ASCIIEncoding e = new ASCIIEncoding();
  //assign string to byte buffer and add "return"
  byte[]Buffer = e.GetBytes(szCmd + "\r\n");
  //use fixed to avoid more memory allocation
  fixed (byte* p = Buffer)
  {
    i=0;
    //write command to the port
    if(!WriteFile(m_ihandle, p + i, Len+1, &n, 0))
      //if false, write failure log
      Console.WriteLine("Send Command " + szCmd + " failed");
    else
      // write success log
      Console.WriteLine("Send Command Successed");
  }
}
/// <summary>
/// Read information from the COM Port.
/// </summary>
private unsafe void ReadModem()
{
  //set the maximum limit to read
  int count = 128;
  //create buffer to store the info
  byte[] buffer = new byte[count];
  //use ASCII encoding to work with string and byte
  ASCIIEncoding e = new ASCIIEncoding();
  //loop through read until done...
  int index = 0;
  int n = 1;
  while (n!=0)
  {
    n = 0;
    fixed (byte* p = buffer)
    {
      //read file
      if(!ReadFile(m_ihandle, p + index, count, &n, 0))
        //write the value received in log
        Console.WriteLine(e.GetString(buffer));
      else
        //write failure log
        Console.WriteLine("Read Modem Failed");
    }
  }
}