C# 往返于 Arduino DUE 串行信号量超时

C# to and from Arduino DUE Serial Semaphore Time out

这是我在 Whosebug 中的第一个问题,如果我忘记提及某些内容,请原谅!

我正在使用 WPF C# 应用程序和 Arduino DUE 创建工业洗​​衣机的界面。 他们通过串行端口进行通信。

串口当前设置:

Arduino 正在毫无延迟地打印到串行端口,所有模拟输入引脚和几个数字输入引脚的状态。

在界面的当前状态下,我尝试简单地打开和关闭某些引脚,但是 c# 应用程序冻结然后崩溃并显示以下错误消息 = "System.IO.IOException: '信号量超时期限已过。".

以下是我的一些经验和以下结果:

以下代码表示启用模拟和数字输入状态发送的arduino代码。 要禁用我评论最后两行

void read_input_analog()
{
  for(int i = 54; i<= NUMBER_ANALOG_INPUT_PORTS; i++)
  {
    String pinNumber = "A";
    pinNumber += i;
    String message = "#A";
    message += i-54;
    message +=":";
    // IMPORTANT NOTE: 54 represents analog pin A0 and 64 Analog pin A11
    message += analogRead(i);
    message +='!';
    Serial.println(message);
  }
}

void read_input_digital()
{
  for(int i = 22; i<= NUMBER_DIGITAL_INPUTS; i++)
  {
    String pinNumber = "D";
    pinNumber += i;
    String message = "#D";
    message += i;
    message +=":";
    // IMPORTANT NOTE: 54 represents analog pin A0 and 64 Analog pin A11
    message += digitalRead(i);
    message +='!';
    Serial.println(message);
  }
}

void loop(){

  
  while(Serial.available()>=8)
  {
    char c = Serial.read();
    Serial.println(c);
    if(c == '#')
    {
      recieve_order();
    }
  }
  
  read_input_analog();
  read_input_digital();
}

编辑 1 串行端口设置中未提及的每个 属性 都保留为默认值。

DataBits property defaults to 8, the Parity property defaults to the None enumeration value, the StopBits property defaults to 1

编辑 2

我注意到 UART 只能作为半双工工作,我误以为是全双工。从那以后,我使用 millis() 函数为从 arduino 端发送信息添加了延迟。这对问题有很大帮助,但问题仍然存在,但不那么频繁了。

编辑 3

我已经做到了,所以 Arduino 上的读取代码通过在每次一个字节进入缓冲区时附加一个字符串来更快地清除缓冲区,而不是让它在执行某些操作之前等待填充 8 个字节。

它有助于发送单独的消息不再使程序崩溃,但是现在使用滑块来控制模拟信号,程序在滚动滑块发送大量消息时崩溃!

我还使用 Windows 表单项目(我在网上找到的)进行了测试,它的滑块非常有用!没有崩溃!

System.IO.IOException
  HResult=0x80070079
  Message=The semaphore timeout period has expired.

  Source=System
  StackTrace:
   at System.IO.Ports.InternalResources.WinIOError(Int32 errorCode, String str)
   at System.IO.Ports.SerialStream.EndWrite(IAsyncResult asyncResult)
   at System.IO.Ports.SerialStream.Write(Byte[] array, Int32 offset, Int32 count, Int32 timeout)
   at System.IO.Ports.SerialPort.Write(String text)
   at Washing_Machine_Interface.Communication.Arduino.ArduinoProtocol.AnalogValue(Int32 pinNumber, Int32 power) in D:\André O Viking\Projetos\Washing_Machine_Interface\washing-machine-interface\WM_Interface\Washing_Machine_Interface\Washing_Machine_Interface\Communication\Arduino\ArduinoProtocol.cs:line 67
   at Washing_Machine_Interface.MainWindow.Pin2Slider_ValueChanged(Object sender, RoutedPropertyChangedEventArgs`1 e) in D:\André O Viking\Projetos\Washing_Machine_Interface\washing-machine-interface\WM_Interface\Washing_Machine_Interface\Washing_Machine_Interface\MainWindow.xaml.cs:line 115
   at System.Windows.RoutedPropertyChangedEventArgs`1.InvokeEventHandler(Delegate genericHandler, Object genericTarget)
   at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)
   at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)
   at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
   at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)
   at System.Windows.UIElement.RaiseEvent(RoutedEventArgs e)
   at System.Windows.Controls.Primitives.RangeBase.OnValueChanged(Double oldValue, Double newValue)
   at System.Windows.Controls.Slider.OnValueChanged(Double oldValue, Double newValue)
   at System.Windows.Controls.Primitives.RangeBase.OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
   at System.Windows.DependencyObject.OnPropertyChanged(DependencyPropertyChangedEventArgs e)
   at System.Windows.FrameworkElement.OnPropertyChanged(DependencyPropertyChangedEventArgs e)
   at System.Windows.DependencyObject.NotifyPropertyChange(DependencyPropertyChangedEventArgs args)
   at System.Windows.DependencyObject.UpdateEffectiveValue(EntryIndex entryIndex, DependencyProperty dp, PropertyMetadata metadata, EffectiveValueEntry oldEntry, EffectiveValueEntry& newEntry, Boolean coerceWithDeferredReference, Boolean coerceWithCurrentValue, OperationType operationType)
   at System.Windows.DependencyObject.SetValueCommon(DependencyProperty dp, Object value, PropertyMetadata metadata, Boolean coerceWithDeferredReference, Boolean coerceWithCurrentValue, OperationType operationType, Boolean isInternal)
   at System.Windows.DependencyObject.SetCurrentValueInternal(DependencyProperty dp, Object value)
   at System.Windows.Controls.Slider.UpdateValue(Double value)
   at System.Windows.Controls.Slider.OnThumbDragDelta(DragDeltaEventArgs e)
   at System.Windows.Controls.Slider.OnThumbDragDelta(Object sender, DragDeltaEventArgs e)
   at System.Windows.Controls.Primitives.DragDeltaEventArgs.InvokeEventHandler(Delegate genericHandler, Object genericTarget)
   at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)
   at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)
   at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
   at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)
   at System.Windows.UIElement.RaiseEvent(RoutedEventArgs e)
   at System.Windows.Controls.Primitives.Thumb.OnMouseMove(MouseEventArgs e)
   at System.Windows.UIElement.OnMouseMoveThunk(Object sender, MouseEventArgs e)
   at System.Windows.Input.MouseEventArgs.InvokeEventHandler(Delegate genericHandler, Object genericTarget)
   at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)
   at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)
   at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
   at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)
   at System.Windows.UIElement.RaiseTrustedEvent(RoutedEventArgs args)
   at System.Windows.UIElement.RaiseEvent(RoutedEventArgs args, Boolean trusted)
   at System.Windows.Input.InputManager.ProcessStagingArea()
   at System.Windows.Input.InputManager.ProcessInput(InputEventArgs input)
   at System.Windows.Input.InputProviderSite.ReportInput(InputReport inputReport)
   at System.Windows.Interop.HwndMouseInputProvider.ReportInput(IntPtr hwnd, InputMode mode, Int32 timestamp, RawMouseActions actions, Int32 x, Int32 y, Int32 wheel)
   at System.Windows.Interop.HwndMouseInputProvider.FilterMessage(IntPtr hwnd, WindowMessage msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at System.Windows.Interop.HwndSource.InputFilterMessage(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
   at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
   at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Int32 numArgs)
   at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Int32 numArgs, Delegate catchHandler)
   at System.Windows.Threading.Dispatcher.LegacyInvokeImpl(DispatcherPriority priority, TimeSpan timeout, Delegate method, Object args, Int32 numArgs)
   at MS.Win32.HwndSubclass.SubclassWndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam)
   at MS.Win32.UnsafeNativeMethods.DispatchMessage(MSG& msg)
   at System.Windows.Threading.Dispatcher.PushFrameImpl(DispatcherFrame frame)
   at System.Windows.Threading.Dispatcher.PushFrame(DispatcherFrame frame)
   at System.Windows.Application.RunDispatcher(Object ignore)
   at System.Windows.Application.RunInternal(Window window)
   at System.Windows.Application.Run(Window window)
   at System.Windows.Application.Run()
   at Washing_Machine_Interface.App.Main()

几天后我弄明白是怎么回事了!

Arduino Due 因来自 C# 的数据溢出而崩溃!

当它崩溃时,C# 会抛出信号量超时异常,并且即使在 try and catch 就位时也永远不会从中恢复,我给了它时间来清除所有已发送数据的流量!

最初从 C# 发送的消息如下:

serialPort.Write("#30" + pinNumber + power + "\n");

  • '#' -> 顺序
  • 3 -> 模拟输出
  • '0'+pinNumber -> pin 编号(当 pin 编号只有 1 位时添加 0,例如 02 por pin 2)
  • 功率 -> 值从 0-255
  • '\n' -> 结束命令

使用滑块时,它会在短时间内多次发送具有不同功率值的消息。 使 Arduino 崩溃 并需要重置。

经过几天的测试,我尝试了以下消息作为实验:

serialPort.Write(power + "\n");

我暂时将 arduino 代码更改为仅更改引脚 2,这样只需要更改为的值。

进行此更改后,无论我将滑块从一侧拖到另一侧的速度有多快,Arduino 都会遵守,问题就解决了