Multithreading and Serial Ports

时间秒杀一切 提交于 2019-12-06 02:38:21

问题


Ok..this will be lengthy but I need to explain some background first.

This part of my software is for sorting items running down a conveyor belt. I am using Modbus for the conveyor belt. Modbus will open gates at a specific time to let an item go through the gate. Items will go through certain gates based on weight.

I am monitoring a sensor to determine when an item is on a scale. When the sensor is blocked, the item is weighed and sent to the appropriate gate. Timers are set to open/close the gate.

My code will work for this..the problem is, it will not work for multiple items. By that I mean, while a gate is open the sensor is not being monitored until the gate is closed. So while Item A is on the way to the gate, Item B will not get weighed on the scale when it blocks the sensor. I could have up to 8 items on the line at once. Here is the code I am running now:

private void SensorThread_DoWork(object sender, DoWorkEventArgs e)
{
    if (SensorThread.CancellationPending == true)
        e.Cancel = true;
    else
    {
        ReadSensor();
    }    
}

private void SensorThread_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    //if sensor is blocked
    if (sensorstatus == 0)
    {
        //the timers just start the thread
        scaleTimer.Start();
    }
    else
    {
        sensorTimer.Start();
    }
}

private void ScaleThread_DoWork(object sender, DoWorkEventArgs e)
{
  if (ScaleThread.CancellationPending == true)
    {
        e.Cancel = true;
    }
    else
    {
        ReadScale();
        //SaveWeight();
        prevgate = gate;
        gate = DetermineGate();
        SetOpenDelay();
        SetDuration();
    }
  }

private void ScaleThread_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    //if gate = 0, this means the weight of meat on scale 
    //is not in any weight range. Meat runs off the end.
    if (gate == 0)
    {
        txtStatus.Invoke(new UpdateStatusCallback(UpdateStatus), new object[] { meatweight.ToString() + 
                                                                                "lbs is out of range"});
        sensorTimer.Start();
    }
    else
    {
      //open gate
      //then close gate
    }
  }

This code works fine, I just need to be able to account for multiple items on the line. Any suggestions????

I've also tried the following:

private void SensorThread_DoWork(object sender, DoWorkEventArgs e)
{
    if (SensorThread.CancellationPending == true)
        e.Cancel = true;
    else
    {
        ReadSensor();
    }    
}    

private void SensorThread_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
  sensorTimer.Start();
}

  private void ScaleThread_DoWork(object sender, DoWorkEventArgs e)
{
  if (ScaleThread.CancellationPending == true)
    {
        e.Cancel = true;
    }
    else
    {   
        //sensor blocked
        if (sensorstatus == 0)
        {
          ReadScale();
          //SaveWeight();
          prevgate = gate;
          gate = DetermineGate();
          SetOpenDelay();
          SetDuration();

          //if gate = 0, this means the weight of meat on scale 
          //is not in any weight range. Meat runs off the end.
          if (gate == 0)
          {
            txtStatus.Invoke(new UpdateStatusCallback(UpdateStatus), new object[] { meatweight.ToString() + 
                                                                                "lbs is out of range"});
          }
          else
          {
            //open gate
            //close gate
          }
    }
}

private void ScaleThread_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
   scaleTimer.Start();
}

When I did this, I started both threads when the start button was pressed. I get all kinds of exceptions and the program eventually throws the SEHException and crashes. The other errors I get say "Serial port already opened" or "I/O Error".


回答1:


I think you need something like this. Don't know if the locks are needed but I added them for safety since you are getting errors

private void SensorThread_DoWork(object sender, DoWorkEventArgs e) 
{
    int sensor = 1;
    while(!SensorThread.CancellationPending == true) 
    {
        int newSensor;
        lock(this)
        {
            newSensor = ReadSensor(); 
        }

        //sensor state changed
        if(newSensor != sensor)
        {
            //sensor was 1 and changed to 0
            if(newSensor==0)
            {
               scaleTimer.Start(); 
            }
            sensor = newSensor;
        }
        Thread.Sleep(1);
    }
    e.Cancel = true; 
}     

private void ScaleThread_DoWork(object sender, DoWorkEventArgs e) 
{ 
    //sensor blocked 
    //if (sensorstatus == 0) 
    { 
        lock(this)
        {
            ReadScale(); 
        }
        //SaveWeight(); 
        prevgate = gate; 
        gate = DetermineGate(); 
        lock(this)
        {
            SetOpenDelay(); 
            SetDuration(); 
        }

      //if gate = 0, this means the weight of meat on scale  
      //is not in any weight range. Meat runs off the end. 
      if (gate == 0) 
      { 
        txtStatus.Invoke(new UpdateStatusCallback(UpdateStatus), new object[] { meatweight.ToString() +  
                                                                            "lbs is out of range"}); 
      } 
      else 
      { 
        lock(this)
        {
        //open gate 
        }
        lock(this)
        {
        //close gate 
        }
      } 
  } 



回答2:


I would suggest that your best bet is probably to create a dedicated thread to sit on each serial port. Such an approach will neither require, nor forbid, any similarity in how the ports are handled, will avoid any interference in operation between the ports, and will be scalable within reasonable bounds (using a thread for each of 32 ports would be fine; using a thread for each of 1,000 would be bad). Although one should avoid creating threads which will simply run for a short time and quit, or creating really huge numbers of threads, using a dedicated thread for each serial port will ensure that when data comes in there will be a thread ready to handle it.




回答3:


I notice that you don't have any loops in your thread's DoWork methods. That would be a great place to start. The worker thread should be a loop that doesn't return until CancellationPending is set to true. They won't loop on their own just because you have it in a thread -- the thread will run until it is done, then exit.

Edited to add: What you seem to be missing is that you need to split up the code that monitors the scale and the code that opens and closes the gate. One way to do that would be to have an infinite loop that monitors the scale, and when it detects something, it starts a new thread that handles opening and closing the gate.



来源:https://stackoverflow.com/questions/9914948/multithreading-and-serial-ports

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!