这是我在Stackoverflow的第一个问题,所以如果我忘记提到一些事情,请原谅!
我正在使用WPF C#应用程序和Arduino DUE创建工业洗衣机的界面。他们通过串行端口通信。
串行端口当前设置:
Arduino打印到串行端口没有任何延迟,所有模拟输入引脚和一对数字输入引脚的状态。
在接口的当前状态下,我尝试简单地打开和关闭某些引脚,但是c#应用程序冻结,然后崩溃,并显示以下错误消息=“System.IO.IOException:“信号量超时时间已过期。”。
以下是我的一些经验和以下结果:
>
将波特率降低到9600,这样一些消息就可以通过,管脚会关闭或打开,如果我更改得太快,就会出现相同的错误消息。
波特率回到115200,在Arduino代码上,我停止向串行端口发送输入管脚状态,错误消失,我可以快速更改管脚状态,没有任何问题,但我无法从Arduino读取任何内容。
以下代码表示发送模拟和数字输入状态启用的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属性默认为8,Parity属性默认为无枚举值,StopBits属性默认为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()
过了几天我已经弄明白发生了什么!
当它崩溃时,C#会抛出信号量超时异常,即使在尝试捕获的情况下也不会从中恢复,我给它时间清除所有发送数据的流量!
最初从C#发送的消息如下:
序列端口。写入("#30"pin Number power"\n");
当使用滑块时,它会在短时间内多次以不同的功率值发送此消息。使Arduino崩溃并需要重置。
经过几天的测试,我尝试了以下消息作为实验:
序列端口。写入(power"\n");
我临时将arduino代码更改为仅更改插脚2,这样就只需要更改一个值。
在此更改后,无论我如何快速拖动滑块从一边到另一边,Arduino将遵守和问题得到解决。
首先想到的问题是,为什么我们需要信号量? 一个简单的答案,以保护多个进程共享的关键/共同区域。 假设多个进程正在使用相同的代码区域,如果所有人都想并行访问,那么结果是重叠的。 例如,多个用户仅使用一台打印机(通用/关键部分),例如个用户,同时给予个作业,如果所有作业并行启动,则一个用户输出与另一个用户输出重叠。 因此,我们需要使用信号量来保护这个信号,即当一个进程正在运行时锁定关键部分,并在完成时
信号量 信号量是一种同步互斥机制的实现,普遍存在于现在的各种操作系统内核里。相对于spinlock 的应用对象,信号量的应用对象是在临界区中运行的时间较长的进程。等待信号量的进程需要睡眠来减少占用 CPU 的开销。参考教科书“Operating Systems Internals and Design Principles”第五章“同步互斥”中对信号量实现的原理性描述: struct semaph
一个线程发送信号量,另外一个线程接收信号量 一个线程发送信号量,另外一个线程接收信号量 源码/* * Copyright (c) 2006-2018, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2018-08-24 yangjie
信号量接口 结构体 struct rt_semaphore 信号量控制块 更多... 类型定义 typedef struct rt_semaphore * rt_sem_t 信号量类型指针定义 函数 rt_err_t rt_sem_init (rt_sem_t sem, const char *name, rt_uint32_t value, rt_uint8_t flag
信号量 这是本章的第三部分 chapter,本章描述了内核中的同步原语,在之前的部分我们见到了特殊的 自旋锁 - 排队自旋锁。 在更前的 部分 是和 自旋锁 相关的描述。我们将描述更多同步原语。 在 自旋锁 之后的下一个我们将要讲到的 内核同步原语是 信号量。我们会从理论角度开始学习什么是 信号量, 然后我们会像前几章一样讲到Linux内核是如何实现信号量的。 好吧,现在我们开始。 介绍Linux
我想创建一个共享内存和信号量的C程序。应该有两个子进程。两个孩子都有一个不同的int数。然后有一个目标号码,应该写在共享内存中。现在两个孩子都应该从进球数中减去他们的数字,直到进球数低于或等于0。我不希望出现比赛条件。这就是为什么我尝试使用信号量。但对我没用。下面是我的代码: