【发布时间】:2008-12-02 00:05:49
【问题描述】:
我正在尝试找出一种将 C# 代码连接到数字秤的方法。特殊的秤是带有 USB 连接的 Ohaus SP202 数字秤。我想以编程方式读取秤上测量的重量。我还没有规模,我只是在做手头的研究。
以前有人做过吗?我一直在互联网上做研究,还没有发现任何值得一提的东西。
【问题讨论】:
我正在尝试找出一种将 C# 代码连接到数字秤的方法。特殊的秤是带有 USB 连接的 Ohaus SP202 数字秤。我想以编程方式读取秤上测量的重量。我还没有规模,我只是在做手头的研究。
以前有人做过吗?我一直在互联网上做研究,还没有发现任何值得一提的东西。
【问题讨论】:
USB 硬件通信通常采用以下三种方式之一。
专有软件通过专有驱动程序与硬件通信。
设备有一个串行仿真芯片(例如FTDI)当您插入电子秤时,您只需安装虚拟通信端口驱动程序,设备就会在您的系统上显示为一个通信端口。然后就像使用 System.IO.Ports.SerialPort 与设备对话一样简单。
设备实施 HID 配置文件,可通过操作系统的 HID 系统使用。我在 Windows 上使用this .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,这是非常标准的串行编程。 A starter article here
【讨论】:
我不知道这个规模的任何细节,但我做过一些 USB 的东西。
它最有可能使用 USB 中断来传输数据。所有的usb鼠标也都使用中断,所以如果你能弄清楚如何读取鼠标信号(使用HID api),那么它应该与scale完全一样,只是返回的数据格式会完全不同。
在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
}
}
【讨论】: