2015-05-15 14 views
10

Tôi đang phát triển một OPC Khách hàng C# tùy chỉnh, tôi bắt đầu viết trong một ứng dụng giao diện điều khiển cho nhanh gọn, tất cả mọi thứ hoạt động hoàn hảo như tôi muốn nó.C Ứng dụng # OPC Mã giống hệt, nhưng công việc khác nhau

Sau đó, tôi quyết định tạo một ứng dụng biểu mẫu cửa sổ để có trải nghiệm hình ảnh.

Các cửa sổ đơn chỉ đơn giản là ngừng hoạt động, ngừng đọc dữ liệu từ máy chủ OPC sau khoảng một phút. Nơi ứng dụng giao diện điều khiển tiếp tục đọc và đọc.

Tôi cũng không thể tìm thấy bất kỳ điều gì rõ ràng trong chế độ gỡ lỗi.

Tôi hoàn toàn nắm chặt vào ống hút ở đây và hy vọng ai đó có thể làm sáng tỏ.

Mỗi ứng dụng đang sử dụng file .dll được cung cấp bởi OPCFoundation.

Đây là giao diện điều khiển ứng dụng

static void Main(string[] args) 
     { 

      Opc.URL url = new Opc.URL("opcda://localhost/RSLinx OPC Server"); 
      Opc.Da.Server server = null; 
      OpcCom.Factory fact = new OpcCom.Factory(); 
      server = new Opc.Da.Server(fact, null); 
      server.Connect(url, new Opc.ConnectData(new System.Net.NetworkCredential())); 
      // Create a group 
      Opc.Da.Subscription group; 
      Opc.Da.SubscriptionState groupState = new Opc.Da.SubscriptionState(); 
      groupState.Name = "Group"; 
      groupState.Active = true; 
      group = (Opc.Da.Subscription)server.CreateSubscription(groupState); 
      // add items to the group. 
      Opc.Da.Item[] items = new Opc.Da.Item[6]; 
      items[0] = new Opc.Da.Item(); 
      items[0].ItemName = "[UX1]F20:9"; 
      items[1] = new Opc.Da.Item(); 
      items[1].ItemName = "[UX1]F22:30"; 
      items[2] = new Opc.Da.Item(); 
      items[2].ItemName = "[UX1]F22:6"; 
      items[3] = new Opc.Da.Item(); 
      items[3].ItemName = "[UX1]F18:8"; 
      items[4] = new Opc.Da.Item(); 
      items[4].ItemName = "[UX1]F22:32"; 
      items[5] = new Opc.Da.Item(); 
      items[5].ItemName = "[UX1]F22:5"; 
      items = group.AddItems(items); 

       group.DataChanged += new Opc.Da.DataChangedEventHandler(OnTransactionCompleted); 

     } 





     static void OnTransactionCompleted(object group, object hReq, Opc.Da.ItemValueResult[] items) 
     { 

      Console.WriteLine("------------------->"); 
      Console.WriteLine("DataChanged ..."); 
      for (int i = 0; i < items.GetLength(0); i++) 
      { 

        Console.WriteLine("Item DataChange - ItemId: {0}", items[i].ItemName); 
        Console.WriteLine(" Value: {0,-20}", items[i].Value); 
        Console.WriteLine(" TimeStamp: {0:00}:{1:00}:{2:00}.{3:000}", 
        items[i].Timestamp.Hour, 
        items[i].Timestamp.Minute, 
        items[i].Timestamp.Second, 
        items[i].Timestamp.Millisecond); 

      } 
      Console.WriteLine("-------------------<"); 
     } 

Đây là ứng dụng WinForm

public Form1() 

    { 
     InitializeComponent(); 
     _Form1 = this; 
    } 

    public static Form1 _Form1; 

    public void update(string message) 

    { 
     this.richTextBox1.Text = message; 
    } 

    private void Form1_Load(object sender, EventArgs e) 

    { 

     readplc(); 

    } 


static void readplc() 
     { 
       Opc.URL url = new Opc.URL("opcda://localhost/RSLinx OPC Server"); 
      Opc.Da.Server server = null; 
      OpcCom.Factory fact = new OpcCom.Factory(); 
      server = new Opc.Da.Server(fact, null); 
      server.Connect(url, new Opc.ConnectData(new System.Net.NetworkCredential())); 
      // Create a group 
      Opc.Da.Subscription group; 
      Opc.Da.SubscriptionState groupState = new Opc.Da.SubscriptionState(); 
      groupState.Name = "Group"; 
      groupState.Active = true; 
      group = (Opc.Da.Subscription)server.CreateSubscription(groupState); 
      // add items to the group. 
      Opc.Da.Item[] items = new Opc.Da.Item[6]; 
      items[0] = new Opc.Da.Item(); 
      items[0].ItemName = "[UX1]F20:9"; 
      items[1] = new Opc.Da.Item(); 
      items[1].ItemName = "[UX1]F22:30"; 
      items[2] = new Opc.Da.Item(); 
      items[2].ItemName = "[UX1]F22:6"; 
      items[3] = new Opc.Da.Item(); 
      items[3].ItemName = "[UX1]F18:8"; 
      items[4] = new Opc.Da.Item(); 
      items[4].ItemName = "[UX1]F22:32"; 
      items[5] = new Opc.Da.Item(); 
      items[5].ItemName = "[UX1]F22:5"; 
      items = group.AddItems(items); 



       group.DataChanged += new Opc.Da.DataChangedEventHandler(OnTransactionCompleted); 


     } 




     static void OnTransactionCompleted(object group, object hReq, Opc.Da.ItemValueResult[] items) 
     { 

      for (int i = 0; i < items.GetLength(0); i++) 
      { 

       UIUpdater TEXT = new UIUpdater(); 
        TEXT.UpdateText(items.GetLength(0).ToString() + " t " + i.ToString() + "Item DataChange - ItemId:" + items[i].ItemName + 
         "Value: " + items[i].Value + " TimeStamp: " + items[i].Timestamp.Hour + ":" + 
         items[i].Timestamp.Minute + ":" + items[i].Timestamp.Second + ":" + items[i].Timestamp.Millisecond); 

      } 

     } 

UIUpdate Lớp

class UIUpdater 

    { 

     public void UpdateText(string DATA) 

     { 
      Form1._Form1.update(DATA); 
     } 

     public class UpdateUI 

     { 



      public int updatedRows { get; set; } 

      public string Custom1 { get; set; } 

      public string Custom2 { get; set; } 

      public string Custom3 { get; set; } 

      public string exception { get; set; } 

      public plcTextStatus PLCStatus { get; set; } 


     } 

Bất kỳ câu hỏi nào, hãy hỏi!

+0

'UIUpdater' là gì? –

+0

Chỉ cần một lớp để cập nhật UserInterface Thread – SK2017

+0

Bạn có thể đăng mã cho nó không? Điều này trông giống như một vấn đề xuyên luồng. Tôi đã phát triển rất nhiều ứng dụng bằng cách sử dụng OPC, RSLinx khá mạnh mẽ, có vẻ như bạn đang kết nối với Micrologix hoặc SLC hoặc thứ gì đó của thời đại PLC5 ... –

Trả lời

5

Như bị nghi ngờ, đây là vấn đề đa luồng. Vấn đề là bạn không thể cập nhật giao diện người dùng từ bất kỳ chủ đề nào khác ngoài chuỗi giao diện người dùng. Sự kiện cho giao dịch hoàn thành thực sự được gọi trên một chuỗi riêng biệt, vì vậy nó cập nhật giao diện người dùng.

Nó hoạt động trong một thời gian ngắn vì nó tương đối chịu lỗi, tuy nhiên bạn có thể đạt đến điểm mà bạn đang bế tắc hoặc ném một ngoại lệ không bị bắt (hoặc được báo cáo).

Khắc phục đơn giản là đủ.

Trong phương pháp này:

public void update(string message) 
{ 
    this.richTextBox1.Text = message; 
} 

Thay đổi nó để:

public void update(string message) 
{ 
    richTextBox1.Invoke(
     (MethodInvoker) delegate 
     { 
      richTextBox1.Text = message; 
     }); 
} 

Điều này không là kể richTextBox1 để "gọi" hoặc chạy các đại biểu sau (chức năng) về chủ đề sở hữu của nó (aka, thread UI).

Bạn thực sự nên cố gắng tránh sử dụng static phương pháp và tài liệu tham khảo trong mã này. Tôi không thấy bất kỳ lý do nào mà mã bạn không nên là các phương thức thể hiện thay vì các phương thức tĩnh.

Cũng giống như một lưu ý phụ, tôi viết các chương trình OPC xử lý hàng nghìn thẻ và hàng trăm cập nhật giao diện người dùng mỗi giây. Những gì bạn đang làm cho các chương trình demo nhỏ nhưng sẽ không tăng lên rất nhiều. Khi kiến ​​trúc phát triển, bạn cần phải bắt đầu trộn các cập nhật giao diện người dùng của bạn để bạn không bận rộn gọi chủ đề giao diện người dùng liên tục bên trong bản cập nhật.

Sửa

Một vấn đề khác bạn có đang sử dụng tài liệu tham khảo địa phương (đến máy chủ OPC, và đăng ký ví dụ) và chứng minh một rò rỉ bộ nhớ và đối tượng zombie. Điều đang xảy ra là phương thức readplc vượt quá phạm vi và bạn đã tạo tham chiếu đến các đối tượng bên trong đang được giữ trong bộ nhớ. Vì bạn không có cách nào để hủy đăng ký sự kiện, sự kiện sẽ tiếp tục kích hoạt. Các biến này phải được khai báo bên ngoài phạm vi của phương thức readplc để bạn có thể hủy đăng ký đúng sự kiện và tắt máy chủ OPC. Nếu không, bạn sẽ rời khỏi đăng ký zombie (xem trang Chẩn đoán OPC RSLinx, bạn sẽ thấy tất cả đăng ký của mình đang ngồi ở đó).

+0

Chỉ cần thay đổi mã để Gọi, vẫn không tạo sự khác biệt, nó vẫn bị lỗi sau quá lâu – SK2017

0

Đặt máy chủ của bạn ở bên ngoài phương thức readplc() làm đối tượng cấp biểu mẫu. Miễn là biểu mẫu của bạn được khởi tạo (không đóng) - đối tượng máy chủ của bạn sẽ hoạt động và sự kiện đăng ký của bạn cũng vậy.

Máy chủ có nhiều khả năng được thu thập bởi Bộ thu gom rác.

Opc.Da.Server server = null; 

static void readplc() 
     { 
       Opc.URL url = new Opc.URL("opcda://localhost/RSLinx OPC Server"); 
      Opc.Da.Server server = null; 
      OpcCom.Factory fact = new OpcCom.Factory(); 
      **this.server = new Opc.Da.Server(fact, null);** 
    .... 
    } 
Các vấn đề liên quan