我试图找出一种从 C# 代码连接到数字刻度的方法。特殊的秤是带有 USB 连接的 Ohaus SP202 数字秤。我想以编程方式读取秤上测量的重量。我还没有规模,我只是在做手头的研究。
有没有人这样做过?我一直在互联网上进行研究,并没有发现任何值得一提的东西。
USB 硬件通信通常采用以下三种方式之一。
专有软件通过专有驱动程序与硬件对话。
设备具有串行仿真芯片(例如FTDI) 当您插入电子秤时,您只需要安装虚拟通信端口驱动程序,设备就会在您的系统上显示为一个通信端口。然后就像使用 System.IO.Ports.SerialPort 与设备对话一样简单。
该设备实施 HID 配置文件,可通过您操作系统的 HID 系统使用。我在 Windows 上使用了这个 .NET HID库来成功地与实现 HID 的条形码扫描仪进行对话。HID 库将根据您正在与之交谈的硬件以块的形式从硬件向您发送数据。
使用方法 2 和 3,您只需要找到您正在与之交谈的比例的数据格式。我使用的秤每秒左右发送一次更新,其中包含硬件 UI 上显示的重量和其他信息,例如负载是否稳定。
查看他们的讨论论坛,看起来他们的秤使用方法 2 (http://ohaus.com/support/forum_messages.asp?topicid=584)并且您需要通过发送“P\r\n”来轮询秤,然后它将以显示屏上显示的字符进行响应(http://ohaus.com/support/forum_messages.asp?topicid=802)。
我没有使用过那个特定的秤,但我之前已经连接到其他数字秤。基本上它通常只是通过 USB 到 Com 转换器进行串行通信。
如果秤有一个 API 就更好了,但如果没有,那么您将只使用 System.IO.Ports.SerialPort 这是非常标准的串行编程。这里有一篇入门文章
我不知道这个规模的任何细节,但我做过一些 USB 的东西。
它最有可能使用usb中断来传输数据。所有的usb鼠标也都使用中断,所以如果你能弄清楚如何读取鼠标信号(使用HID api),那么它应该与规模完全相同,只是返回的数据格式会完全不同。
在ftw上运行
Scales 是我必须从中读取数据的第一批设备之一。那时,它只是一个串口,我猜你仍然可以使用SerialPort.Net从串口读取。
这是 Windows 上的串行端口传输代码
using Device.Net;
using Device.Net.Windows;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions;
using Microsoft.Win32.SafeHandles;
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
namespace SerialPort.Net.Windows
{
public class WindowsSerialPortDevice : DeviceBase, IDevice
{
#region Fields
private readonly int _BaudRate;
private readonly byte _ByteSize;
private bool disposed;
private readonly Parity _Parity;
private SafeFileHandle _ReadSafeFileHandle;
private readonly StopBits _StopBits;
private ushort ReadBufferSize { get; }
#endregion
#region Public Properties
public bool IsInitialized => _ReadSafeFileHandle != null && !_ReadSafeFileHandle.IsInvalid;
/// <summary>
/// TODO: No need to implement this. The property probably shouldn't exist at the base level
/// </summary>
public IApiService ApiService { get; }
public ConnectedDeviceDefinition ConnectedDeviceDefinition { get; private set; }
#endregion
#region Constructor
public WindowsSerialPortDevice(
string deviceId,
int baudRate = 9600,
StopBits stopBits = StopBits.One,
Parity parity = Parity.None,
byte byteSize = 8,
ushort readBufferSize = 1024,
ILoggerFactory loggerFactory = null,
IApiService apiService = null) : base(
deviceId,
loggerFactory,
(loggerFactory ?? NullLoggerFactory.Instance).CreateLogger<WindowsSerialPortDevice>())
{
ApiService = apiService ?? new ApiService(null);
ConnectedDeviceDefinition = new ConnectedDeviceDefinition(DeviceId, DeviceType.SerialPort);
if ((byteSize == 5 && stopBits == StopBits.Two) || (stopBits == StopBits.OnePointFive && byteSize > 5))
throw new ArgumentException(Messages.ErrorInvalidByteSizeAndStopBitsCombo);
if (byteSize is < 5 or > 8)
throw new ArgumentOutOfRangeException(nameof(byteSize), Messages.ErrorByteSizeMustBeFiveToEight);
if (baudRate is < 110 or > 256000)
throw new ArgumentOutOfRangeException(nameof(baudRate), Messages.ErrorBaudRateInvalid);
if (stopBits == StopBits.None)
throw new ArgumentException(Messages.ErrorMessageStopBitsMustBeSpecified, nameof(stopBits));
ReadBufferSize = readBufferSize;
_BaudRate = baudRate;
_ByteSize = byteSize;
_StopBits = stopBits;
_Parity = parity;
}
#endregion
#region Public Methods
public Task InitializeAsync(CancellationToken cancellationToken = default) => Task.Run(Initialize, cancellationToken);
private uint Write(byte[] data) => data == null ? 0 : ApiService.AWriteFile(_ReadSafeFileHandle, data, data.Length, out var bytesWritten, 0) ? (uint)bytesWritten : 0;
public override Task<uint> WriteAsync(byte[] data, CancellationToken cancellationToken = default)
{
ValidateConnection();
return Task.Run(() =>
{
var bytesWritten = Write(data);
Logger.LogDataTransfer(new Trace(false, data));
return bytesWritten;
}, cancellationToken);
}
public override Task<TransferResult> ReadAsync(CancellationToken cancellationToken = default)
{
ValidateConnection();
return Task.Run(() =>
{
var buffer = new byte[ReadBufferSize];
var bytesRead = Read(buffer);
var transferResult = new TransferResult(buffer, bytesRead);
Logger.LogDataTransfer(new Trace(false, transferResult));
return transferResult;
}, cancellationToken);
}
public override Task Flush(CancellationToken cancellationToken = default)
{
ValidateConnection();
return Task.Run(() => ApiService.APurgeComm(_ReadSafeFileHandle, APICalls.PURGE_RXCLEAR | APICalls.PURGE_TXCLEAR),
cancellationToken);
}
public override void Dispose()
{
if (disposed)
{
Logger.LogWarning(Messages.WarningMessageAlreadyDisposed, DeviceId);
return;
}
disposed = true;
Logger.LogInformation(Messages.InformationMessageDisposingDevice, DeviceId);
if (_ReadSafeFileHandle != null)
{
_ReadSafeFileHandle.Dispose();
_ReadSafeFileHandle = new SafeFileHandle((IntPtr)0, true);
}
base.Dispose();
}
public void Close() => Dispose();
#endregion
#region Private Methods
private void Initialize()
{
_ReadSafeFileHandle = ApiService.CreateReadConnection(DeviceId, FileAccessRights.GenericRead | FileAccessRights.GenericWrite);
if (_ReadSafeFileHandle.IsInvalid) return;
var dcb = new Dcb();
var isSuccess = ApiService.AGetCommState(_ReadSafeFileHandle, ref dcb);
_ = WindowsHelpers.HandleError(isSuccess, Messages.ErrorCouldNotGetCommState, Logger);
dcb.ByteSize = _ByteSize;
dcb.fDtrControl = 1;
dcb.BaudRate = (uint)_BaudRate;
dcb.fBinary = 1;
dcb.fTXContinueOnXoff = 0;
dcb.fAbortOnError = 0;
dcb.fParity = 1;
#pragma warning disable IDE0010 // Add missing cases
dcb.Parity = _Parity switch
{
Parity.Even => 2,
Parity.Mark => 3,
Parity.Odd => 1,
Parity.Space => 4,
Parity.None => 0,
_ => 0
};
dcb.StopBits = _StopBits switch
{
StopBits.One => 0,
StopBits.OnePointFive => 1,
StopBits.Two => 2,
StopBits.None => throw new ArgumentException(Messages.ErrorMessageStopBitsMustBeSpecified),
_ => throw new ArgumentException(Messages.ErrorMessageStopBitsMustBeSpecified),
};
#pragma warning restore IDE0010 // Add missing cases
isSuccess = ApiService.ASetCommState(_ReadSafeFileHandle, ref dcb);
_ = WindowsHelpers.HandleError(isSuccess, Messages.ErrorCouldNotSetCommState, Logger);
var timeouts = new CommTimeouts
{
WriteTotalTimeoutConstant = 0,
ReadIntervalTimeout = 1,
WriteTotalTimeoutMultiplier = 0,
ReadTotalTimeoutMultiplier = 0,
ReadTotalTimeoutConstant = 0
};
isSuccess = ApiService.ASetCommTimeouts(_ReadSafeFileHandle, ref timeouts);
_ = WindowsHelpers.HandleError(isSuccess, Messages.ErrorCouldNotSetCommTimeout, Logger);
Logger.LogInformation("Serial Port device initialized successfully. Port: {port}", DeviceId);
}
private uint Read(byte[] data)
=>
ApiService.AReadFile(_ReadSafeFileHandle, data, data.Length, out var bytesRead, 0)
? bytesRead
: throw new IOException(Messages.ErrorMessageRead);
private void ValidateConnection()
{
if (!IsInitialized)
{
throw new InvalidOperationException(Messages.ErrorMessageNotInitialized);
}
}
#endregion
}
}