using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO.Ports;
using Modbus.Device;
using Modbus.IO;
using Modbus;
using System.Text;
using Modbus.Message;
using Modbus.Data;
namespace MES
{
    public partial class Form2 : Form
    {
        public Form2()
        {
            InitializeComponent();
        }
        private void label1_Click(object sender, EventArgs e)
        {        }        static SerialPort serialPort1 = new SerialPort("COM7");//声明串口        IModbusSerialMaster master = ModbusSerialMaster.CreateRtu(serialPort1);
        byte slaveId = 2;
                 //Read holdregisters 
        ushort startAddress = 50;
        ushort numRegisters = 10;
         
        //Read input
        ushort startAddress_c1 = 0;
        ushort numRegisters_c1 = 8;
        
        //Read output
        ushort startAddress_c2 = 0;
        ushort numRegisters_c2 = 8;//读取现场状态
        public void ReadState()
        {
            //寄存器数值
            ushort[] registers = master.ReadHoldingRegisters(slaveId, startAddress, numRegisters);
            float f_done = ushort2float(registers[0], registers[1]);
            float f_un = (Convert.ToSingle(Txtb_Set.Text))-f_done;            Txtb_Done.Text = f_done.ToString();
            Txtb_Un.Text = f_un.ToString();
            //进度条显示
            //布尔量输入
               bool []intput_1 = master.ReadInputs (slaveId, startAddress_c1, numRegisters_c1);
               if (intput_1[0])
                     Lab_Xianti.ForeColor = Color.Green;
               else
               Lab_Xianti.ForeColor = Color.Gray;           //布尔量输出
              bool[] state = master.ReadCoils(slaveId, startAddress_c2, numRegisters_c2);
              if (state[1])
                  Lab_RaoXian.ForeColor = Color.Green;
              else
                  Lab_RaoXian.ForeColor = Color.Gray;        }
//窗口加载时打开串口,设置参数
        private void Form2_Load(object sender, EventArgs e)
        {            serialPort1.BaudRate = 9600;
            serialPort1.DataBits = 8;
            serialPort1.Parity = Parity.None;
            serialPort1.StopBits = StopBits.One;
            serialPort1.ReadTimeout = 1000;
            serialPort1.WriteTimeout = 1000;            serialPort1.Open();//只能执行一次,不能在定时器中持续调用
            ////serialPort1.ReceivedBytesThreshold = 1;
            //ReadState();
           
        }
       // public Timer timer1 =new Timer();       
//实时时间显示
        private void timer1_Tick(object sender, EventArgs e)
        {
            DateTime dt = DateTime.Now;
            label4_Time.Text = dt.ToString();
        }
//定时采集数据
        private void timer2_Tick(object sender, EventArgs e)
        {
            ReadState();
            progressBar1.Value = Convert.ToInt32((Convert.ToSingle(Txtb_Done.Text) / (Convert.ToSingle(Txtb_Set.Text)) * 100));
        }
//ushort2float
        public float  ushort2float(ushort a, ushort b)
        {
            string aa = Convert.ToString((a), 16);
            string bb = Convert.ToString((b), 16);
            bb = aa + bb;
            //string to float
            uint num = uint.Parse(bb, System.Globalization.NumberStyles.AllowHexSpecifier);
            byte[] floatVals = BitConverter.GetBytes(num);
            float f = BitConverter.ToSingle(floatVals, 0);
            return f;
        }        private void button1_Click(object sender, EventArgs e)
        {
           progressBar1.Value = Convert.ToInt32((Convert.ToSingle(Txtb_Done.Text) / (Convert.ToSingle(Txtb_Set.Text)) * 100));
        }        private void Form2_FormClosed(object sender, FormClosedEventArgs e)
        {
            master.Dispose();
            master = null;            // Destroy serial port
            serialPort1.Close();
            serialPort1.Dispose();
            serialPort1 = null;
            System.Environment.Exit(0);
        }
    }
            
}

解决方案 »

  1.   

    界面卡死是主线程被阻塞了
    耗时的操作都需要放到工作线程中去,使用线程,UI交互就需要使用委托使用timer也可以,但是timer有短板,无法解决重入
    也就是如果某一轮由于异常没有执行完超时,
    发生重入后,就会发生问题。如果对线程不熟悉,可以换成backgroundworker控件
      

  2.   

    刷新用线程。serialPort1.WriteTimeout = 1000;注释掉试试。
      

  3.   

    是你这段代码阻塞了主线程
    //定时采集数据
            private void timer2_Tick(object sender, EventArgs e)
            {
                ReadState();
                progressBar1.Value = Convert.ToInt32((Convert.ToSingle(Txtb_Done.Text) / (Convert.ToSingle(Txtb_Set.Text)) * 100));
            }就算是另外开线程也不好开吧,因为你靠定时器2每隔一段时间操作一次耗时的操作,估计你的程序需要重新设计了,要不你把定时器2定时的时间长一点,但是定时的时间需要是串口读写时间的倍数
      

  4.   

    搞WinForm,必用多线程,一个线程搞定UI,不要在UI线程中搞一些需要挂起等待的事情;需要挂起的动作放到别的线程中去。再如P哥所说,不要胡乱轮询。
      

  5.   

    比如说 Data_Received 之后有可能会通知我们来更新界面,这是多么基本的设计概念啊?!!就好像你用了 Text 控件知道捕获 TextChanged 事件,用其它控件则知道如何捕获处理控件的事件,这也是基本的设计概念。如果你遇到一个人说每一个 TextBox 控件都要对应一个“线程”来死循环轮询,遇到其它每一个控件也对应一个‘线程“,遇到其它一个对象属性监听也要对应一个”线程“.......无数线程来轮询,那么此时虽然用了线程来缓解界面卡死现象了,这就好像是血管被10000处、每一处血栓都堵死了90%,这个软件快被这类代码弄垮掉了。
      

  6.   

    你的进程中假设使用了1万个控件实例、每个控件都有那么几十种事件可以捕获,那么你监听其状态值改变时自然都知道怎么写代码。为什么自己设计程序的时候就只知道只能搞 几十万个 timer 轮询、或者搞几十万个死循环的”线程“去轮询呢?(记住,每一个线程都要占用至少1K栈空间、要占用操作系统上下文切换调度时间)这是一个设计问题。当你设计一个稍微实用的软件,只有设计思路堵死了,或者没有学过设计模式,才会仅仅用刚学编程时的方式。
      

  7.   

    我使用winform 做串口助手,都是开工作线程接收数据(接收方法都是阻塞)并处理数据,然后通过委托发送消息到UI线程中显示数据。
      

  8.   

    用以太网,建立多个连接用多啊线程,几百台PLC都没有问题的;
    这里有范例:
    http://blog.sina.com.cn/s/blog_16d7d3ecb0102x1z5.html