2012-01-18 58 views
9

Tôi đang phát triển chương trình cần tương tác với các cổng COM.SerialPort không nhận được bất kỳ dữ liệu

Bằng cách học từ Q & A: .NET SerialPort DataReceived event not firing, tôi tạo mã như thế.

namespace ConsoleApplication1 
{ 
class Program 
{ 
    static SerialPort ComPort;   

    public static void OnSerialDataReceived(object sender, SerialDataReceivedEventArgs args) 
    { 
     string data = ComPort.ReadExisting(); 
     Console.Write(data.Replace("\r", "\n")); 
    } 

    static void Main(string[] args) 
    { 
     string port = "COM4"; 
     int baud = 9600; 
     if (args.Length >= 1) 
     { 
      port = args[0]; 
     } 
     if (args.Length >= 2) 
     { 
      baud = int.Parse(args[1]); 
     } 

     InitializeComPort(port, baud); 

     string text; 
     do 
     { 
      String[] mystring = System.IO.Ports.SerialPort.GetPortNames(); 

      text = Console.ReadLine(); 
      int STX = 0x2; 
      int ETX = 0x3; 
      ComPort.Write(Char.ConvertFromUtf32(STX) + text + Char.ConvertFromUtf32(ETX)); 
     } while (text.ToLower() != "q"); 
    } 

    private static void InitializeComPort(string port, int baud) 
    { 
     ComPort = new SerialPort(port, baud); 
     ComPort.PortName = port; 
     ComPort.BaudRate = baud; 
     ComPort.Parity = Parity.None; 
     ComPort.StopBits = StopBits.One; 
     ComPort.DataBits = 8; 
     ComPort.ReceivedBytesThreshold = 9; 
     ComPort.RtsEnable = true; 
     ComPort.DtrEnable = true; 
     ComPort.Handshake = System.IO.Ports.Handshake.XOnXOff; 
     ComPort.DataReceived += OnSerialDataReceived;    
     OpenPort(ComPort);    
    } 

    public static void OpenPort(SerialPort ComPort) 
    { 
     try 
     { 
      if (!ComPort.IsOpen) 
      { 
       ComPort.Open();      
      } 
     } 
     catch (Exception e) 
     { 
      throw e; 
     } 
    } 
} 
} 

Sự cố của tôi là sự kiện DataReceived không bao giờ bị kích hoạt.

thông số kỹ thuật chương trình của tôi là:

  1. Chỉ cần .net console lập trình
  2. tôi sử dụng VSPE từ http://www.eterlogic.com
  3. Máy tính của tôi có COM1 và COM2 cổng rồi.
  4. Tôi đã tạo COM2 và COM4 bằng cách sử dụng VSPE.
  5. tôi nhận được kết quả đầu ra từ mystring mảng (COM1, COM2, COM3, COM4)

Nhưng tôi vẫn không biết tại sao DataReceived sự kiện không được sa thải.


Cập nhật

Thật không may, tôi vẫn không thể thực hiện để bắn DataReceived sự kiện trong bất kỳ cách nào.

Vì vậy, tôi đã tạo dự án mới bằng cách hy vọng rằng tôi sẽ đối mặt với một cách để giải quyết.

Lúc đó dự án mới [chỉ an ủi ứng dụng], tôi đã tạo ra một lớp ...

public class MyTest 
{ 
    public SerialPort SPCOM4; 

    public MyTest() 
    { 

     SPCOM4 = new SerialPort(); 
     if(this.SerialPortOpen(SPCOM4, "4")) 
     { 
      this.SendToPort(SPCOM4, "com test..."); 
     } 

    } 

    private bool SerialPortOpen(System.IO.Ports.SerialPort objCom, string portName) 
    { 
     bool blnOpenStatus = false; 
     try 
     { 
      objCom.PortName = "COM" + portName; 
      objCom.BaudRate = 9600; 
      objCom.DataBits = 8; 

      int SerParity = 2; 
      int SerStop = 0; 

      switch (SerParity) 
      { 
       case 0: 
        objCom.Parity = System.IO.Ports.Parity.Even; 
        break; 
       case 1: 
        objCom.Parity = System.IO.Ports.Parity.Odd; 
        break; 
       case 2: 
        objCom.Parity = System.IO.Ports.Parity.None; 
        break; 
       case 3: 
        objCom.Parity = System.IO.Ports.Parity.Mark; 
        break; 
      } 

      switch (SerStop) 
      { 
       case 0: 
        objCom.StopBits = System.IO.Ports.StopBits.One; 
        break; 
       case 1: 
        objCom.StopBits = System.IO.Ports.StopBits.Two; 
        break; 
      } 

      objCom.RtsEnable = false; 
      objCom.DtrEnable = false; 
      objCom.Handshake = System.IO.Ports.Handshake.XOnXOff; 
      objCom.Open(); 
      blnOpenStatus = true; 

     } 
     catch (Exception ex) 
     { 
      throw ex; 
     } 
     return blnOpenStatus; 
    } 

    private bool SendToPort(System.IO.Ports.SerialPort objCom, string strText) 
    { 
     try 
     { 
      int STX = 0x2; 
      int ETX = 0x3; 

      if (objCom.IsOpen && strText != "") 
      { 
       objCom.Write(Char.ConvertFromUtf32(STX) + strText + Char.ConvertFromUtf32(ETX)); 
      } 
     } 
     catch (Exception ex) 
     { 
      throw ex; 
     } 
     return true; 
    } 
} 

Tôi không chắc chắn mà tôi phải đối mặt với may mắn hay xui xẻo vì lớp mới này có thể làm cho đám cháy sự kiện DataReceived mà từ ứng dụng bảng điều khiển cũ hơn vẫn đang chạy. Điều kỳ diệu đối với tôi là tôi không biết chuyện này xảy ra như thế nào.

Hãy để tôi cho bạn biết thêm chi tiết để bạn có thể đưa ra đề xuất cho cách tốt hơn.

  1. Cuối cùng tôi đã tạo 2 dự án bảng điều khiển.
  2. Dự án đầu tiên là lớp mà tôi đã đăng là câu hỏi ngày hôm qua.
  3. Dự án thứ hai là lớp được gọi là MyTest có thể gây ra sự kiện cháy DataReceived từ Dự án đầu tiên, đồng thời khi hai dự án đang chạy.

Có ai cho tôi đề xuất về cách tôi có thể kết hợp hai dự án này thành một dự án không?

+1

IIRC 'DataReceived' được kích hoạt sau khi nhận được dấu tách dòng. Bạn có thể xác nhận rằng thiết bị thực sự đang gửi nhiều dòng? – leppie

+0

@leppie: IIRC, nó sẽ kích hoạt sau khi nhận được nhiều hơn (hoặc ít nhất) byte 'ReceivedBytesThreshold'. Vì vậy, các câu hỏi là: 1. bạn nhận được bao nhiêu byte? 2. Bạn có thành công trong việc đọc dữ liệu này bằng cách sử dụng một ứng dụng thiết bị đầu cuối khác không? – Groo

+0

@Groo: Cảm ơn, điều đó có vẻ trực quan hơn :) – leppie

Trả lời

17
ComPort.Handshake = Handshake.None; 

Sự cố không phải là sự kiện DataReceived không kích hoạt, sự cố là cổng nối tiếp không nhận được bất kỳ dữ liệu nào. Có rất, rất ít thiết bị nối tiếp không sử dụng bắt tay. Nếu bạn đặt nó thành None thì trình điều khiển sẽ không bật tín hiệu DTR (Data Terminal Ready) và RTS (Request To Send). Thiết bị cổng nối tiếp nào diễn giải là "máy bị tắt (DTR)" hoặc "máy chưa sẵn sàng nhận dữ liệu (RTS)". Vì vậy, nó sẽ không gửi bất cứ điều gì và sự kiện DataReceived của bạn sẽ không cháy.

Nếu bạn thực sự muốn Không, sau đó đặt thuộc tính DTREnable và RTSEnable thành true. Nhưng có thể bạn muốn HandShake.RequestToSend vì thiết bị dường như chú ý đến các tín hiệu bắt tay.

Nếu bạn vẫn gặp sự cố thì hãy sử dụng một chương trình cổng nối tiếp khác như Putty hoặc HyperTerminal để đảm bảo thông số kết nối và giao tiếp tốt và thiết bị đáp ứng. Tiện ích PortMon của SysInternals cung cấp một cái nhìn mức độ thấp về tương tác của trình điều khiển để bạn có thể so sánh tốt so với xấu.

+1

+1. Nói chung có nhiều lý do tại sao sự kiện DataReceived sẽ không kích hoạt, và hầu như tất cả chúng đều là vì không nhận được dữ liệu thông minh nào. (Thực sự không có dữ liệu nào được gửi đi, cáp không được cắm vào đúng ổ cắm, cáp không tạo kết nối tốt hoặc bị hỏng, hoặc cài đặt của bạn ở đầu kia hoặc kết nối không chính xác (tốc độ truyền, bắt tay, số bit, bit dừng hoặc bit chẵn lẻ, v.v.). –

+0

Xin lỗi, liên kết thứ hai đó phải có ở đây: [serialport-datareceived-event-do-not-fire] (http://stackoverflow.com/questions/8907490/serialport-datareceived-event-does-not-fire) –

+0

Thiết lập DTREnable và RTSEnable cả hai đều đúng trong trường hợp của tôi – fragmint

0

Tôi chưa bao giờ làm việc với VSPE vì vậy tôi không chắc liệu điều đó có gây ra sự cố hay không. Tôi đã làm việc với một cổng COM trước và tôi nhìn lên mã của tôi. Sự khác biệt chính duy nhất là cách bạn khai báo sự kiện.Bạn có:

ComPort.DataReceived += OnSerialDataReceived; 

tôi có nó như thế này:

ComPort.DataReceived += new SerialDataReceivedEventHandler(OnSerialDataReceived); 

OnSerialDataReceived là eventhandler của bạn. Tôi không chắc chắn nếu điều này sẽ làm cho bất kỳ sự khác biệt, nhưng bạn có thể thử nó. Tôi hi vọng cái này giúp được!

+0

hmm ... đối với tôi, nó tạo nên sự khác biệt. Có thể là một vấn đề Chủ đề. MSDN nói: Sự kiện DataReceived được nâng lên trên một luồng thứ cấp khi dữ liệu được nhận từ đối tượng SerialPort. (tại đây: http://msdn.microsoft.com/en-us/library/system.io.ports.serialport.datareceived.aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-2) +1 của tôi cho câu trả lời! BTW ... ban đầu tôi đã có mã mới nhưng đã xóa nó sau đề xuất ReScharper. Vì vậy, mọi người, không luôn luôn tin tưởng ReSharper :) –

+6

Theo [câu trả lời này] (http://stackoverflow.com/a/863711/921321) điều này làm cho không có sự khác biệt, các mẫu hàng đầu là làm cho việc sử dụng chuyển đổi nhóm phương pháp ngầm, kết quả trong mã được biên dịch chính xác giống như mã dưới cùng. – Lukazoid

0

Tôi gặp sự cố tương tự. Trong một ứng dụng đồ họa (C# win form) tôi đã có một lớp mà gói gọn một thành phần SerialPort. Sự kiện được ghi nhận dữ liệu được kích hoạt chỉ một lần, sau đó các dữ liệu gửi sau đây không kích hoạt bất kỳ sự kiện nào. Tôi đã giải quyết vấn đề bằng cách gọi phương thức SerialPort.Close() ở dạng chính của hàm Closed event. Không có ý tưởng tại sao thay đổi bất cứ điều gì, nhưng bây giờ nó hoạt động.

'Hy vọng điều này có thể giúp ...

+2

Nhưng bạn sẽ làm gì khi cần mở cổng? –

Các vấn đề liên quan