通过串口采集来自多个仪表的数据,协议是Modbus,仪表并接在RS485总线上,通过转接口连接到电脑USB接口
我现在用了一个计时器timer1,是System.Windows.Forms.Timer类型的,间隔一秒钟触发timer1_Tick函数
主要的代码是这样的:
private void timer1_Tick_1(object sender, EventArgs e)
        {
            try
            {
                System.Threading.Thread timerThread = new System.Threading.Thread(new System.Threading.ThreadStart(TimerMethod));
                    timerThread.Start();
                //周期性将临时数据存入历史数据库
            }
            catch (Exception exp)
            {
                timer1.Stop();
            }
        }
public void TimerMethod()
        {
            try
            {
                //清除临时数据
                using (SerialPort port = new SerialPort())
                {
                    //设置串口 
                    port.Open();
                    //从串口读数据
                    port.Close();
                            
                    if (con.State == ConnectionState.Open)
                    {
                        //将实时数据写入数据库
                        //***********显示实时数值                           
                        // ************刷新控件状态
                        //************判断是否报警
                       }                    
                }
            }
            catch (Exception exp)
            {
                timer1.Stop();
                System.Threading.Thread.CurrentThread.Abort();
            }
        }
在运行了一小段时间之后就会出现“对COM1的访问被拒绝”这样的错误,但是有时候又会一直运行下去很长时间才出错,我是第一次尝试写多线程的代码,希望有朋友帮我看一下我这样的方式是否可行,另外帮我分析下出现这个错误的可能原因是什么。
PS:因为TimerMethod代码太长所以只贴了说明文字,如果需要我选取详细的代码再贴上来

解决方案 »

  1.   

    Timer控件本来就是多线程的,没有必要在 tick中再加个线程!去掉试试!
      

  2.   

    原本的代码就是没有在tick中新建线程,而是直接调用TimerMethod,但是这样UI界面的响应速度就很慢,所以我想用多线程的方式来执行。
      

  3.   


    我这个是写一个命令,他会返回一些数据!
    如果只是读数据的话只是读一个串口的数据是没有必要用多线程
    可以使用timer或起动一个后台线程就可以了!
    我这个也是用timer实现的每5Min读一次!测试效果还很稳定
    SerialPort这个类中有一个datareceive(不知道是不是这样子拼的)这个事件
    也可以在这个事件里完成的!
    public string WriteCommand(byte[] bCommand)
            {
                StringBuilder sb = new StringBuilder();
                bool bRead = true;
                try
                {
                    ss_port.DiscardInBuffer();
                    ss_port.Write(bCommand,0,bCommand.Length);
                    Thread.Sleep(1500);
                    while (bRead)
                    {
                        _ReadBuffer = new byte[ss_port.BytesToRead];
                        ss_port.Read(_ReadBuffer, 0, _ReadBuffer.Length);
                        sb.Append(Encoding.ASCII.GetString(_ReadBuffer));
                        Thread.Sleep(500);
                        if (ss_port.BytesToRead <= 0)
                        {
                            bRead = false;
                        }
                    }
                    if (sb.ToString().Length == 0)
                    {
                        nReadCount++;
                    }                if (nReadCount == 3)
                    {
                        nReadCount = 0;
                        throw new Exception("设置不正确或没有联接设备!");
                    }               
                }
                catch (Exception ex)
                {
                    throw new Exception("从设备获取数据失败!\r\n错误信息:" + ex.Message);
                }
                return sb.ToString();
            }
      

  4.   

    我也不想这样的,但是这个软件是用来做监控的,要求就是要频繁的读取数据以保证每一时刻的状态都能被看到
    另外,我设置好串口之后读数据不是用的SerialPort的DataReceived事件,因为仪表采用的是Modbus协议,所以我找了一个Modbus控件来帮助读取数据,里面有ReadHoldingRegisters()这样的函数可供使用
      

  5.   

    lz不要用timer,你大概可以这样,效果一样
    在一个新线程里面:
    while(true)

    读数据。
      
    Thread.Sleep(1000); }
      

  6.   

    你將Timer設為2S試試,我以前碰到類似經歷。
      

  7.   

    SerialPort是一种临界资源,就好像有一个座位一次只能坐一个人一样,坐多了就会出问题。你上面的代码在多线程里面打开SerialPort,偶然可能会正好出现两个线程同时去打开COM1,或者一个已经打开了COM1,而另一个也企图去打开。解决这个问题,可以将SerialPort做一次封装,内部使用单例模式。
      

  8.   

    多谢楼上各位的回复,问题已经解决了,我给SerialPort以及其他几个临界资源加锁然后加入了一些同步的代码就好了