我在从DLPIO20设备上的DS18B20 +传感器读取实时温度数据时遇到问题。我在Windows平台上使用FTD2XX.DLL .NET包装器(版本1.0.14)(根据链接:http://www.ftdichip.com/Support/SoftwareExamples/CodeExamples/CSharp/FTD2XX_NET_v1.0.14.zip)。
测试应用程序以证明问题如下。
这就是我的实时意思。
2.1在相当恒定的环境温度下(比如说20°C)几乎没有温度读数,以便在调试模式下看到一致的结果(第55行温度读取周期结束时的断点)。
2.2。然后,在断点处,只需在传感器上呼气或使用其他方法将其加热到环境温度以上几度。
2.3。再运行两到三个温度读数循环。
传感器加热后的第一次读数是20°C的“旧”温度。仅在第二次或第三次读取循环时,我在28°C左右得到了真实的结果。
有趣的是,如果我在读取之前发出转换命令,测试应用程序IO20Demo(随购买DLP-IO20板),我会立即获得28°C的实时结果。有了这个程序和托管的.NET包装器类,我也会在Read之前发送Convert命令,但无济于事。最大的区别是IO20Demo不使用托管包装类,而是直接使用FTD2XX.lib。
你能帮我理解我在这里做错了什么吗?如何使用托管的.NET包装类获取实时温度数据?非常感谢您的帮助!
/// <summary>
/// Program for DLPIO20 device to read temperature data from DS18B20+
/// digital temperature sensor attached to one of its channels.
/// </summary>
class Program
{
static void Main(string[] args)
{
FTDI FtdiWrapper = null;
// DLPIO20 channel where the DS18B20+ sensor is attached
byte sensorChannel = 0x06;
try
{
// create new instance of the FTDI device class
FtdiWrapper = ConnectToFirstFtdiDevice();
if (FtdiWrapper == null || !FtdiWrapper.IsOpen)
{
throw new Exception("Error connection to FTDI device.");
}
// didn't helped at all for 85dC issue
//PurgeRxBuffer(FtdiWrapper);
// helped avoid 85dC issue at first read
ConvertSensorData(FtdiWrapper, sensorChannel);
// send read sensor command
float? degreesC = null;
for (int i = 0; i < 100; i++)
{
// calling Convert just before ReadTemperatureSensor causes
// IO20Demo (using FTD2XX.lib) to return real temperature
// but it doesn't help when using .NET wrapper
ConvertSensorData(FtdiWrapper, sensorChannel);
// other failed attempts to get real time sensor data
// previous value returned:
//PurgeRxBuffer(FtdiWrapper);
// read but only initiate conversion on success
degreesC = ReadTemperatureSensor(FtdiWrapper, sensorChannel);
if (degreesC == null)
{
throw new Exception("Error converting raw data to Celsius");
}
var message = string.Format("Success! {0}° Celsius.", degreesC);
Console.WriteLine(message);
}
Console.WriteLine("Press any key to exit ...");
Console.ReadKey();
}
catch (Exception ex)
{
Console.WriteLine(ex);
Console.WriteLine("Press any key to exit ...");
Console.ReadKey();
}
finally
{
if (FtdiWrapper != null && FtdiWrapper.IsOpen)
{
FtdiWrapper.Close();
}
}
}
这是用于连接第一个FTDI设备的代码
static private FTDI ConnectToFirstFtdiDevice()
{
FTDI FtdiWrapper = new FTDI();
UInt32 ftdiDeviceCount = 0;
FTDI.FT_STATUS ftStatus = FTDI.FT_STATUS.FT_OTHER_ERROR;
// Determine the number of FTDI devices connected to the machine
ftStatus = FtdiWrapper.GetNumberOfDevices(ref ftdiDeviceCount);
// Check status
if (ftStatus != FTDI.FT_STATUS.FT_OK)
throw new Exception(string.Format("Error after GetNumberOfDevices(), ftStatus: {0}", ftStatus));
if (ftdiDeviceCount == 0)
throw new Exception("No FTDI device found");
// Allocate storage for device info list
var ftdiDeviceList = new FTDI.FT_DEVICE_INFO_NODE[ftdiDeviceCount];
// Populate our device list
ftStatus = FtdiWrapper.GetDeviceList(ftdiDeviceList);
if (ftStatus == FTDI.FT_STATUS.FT_OK)
{
// Open first device in our list by serial number
ftStatus = FtdiWrapper.OpenBySerialNumber(ftdiDeviceList[0].SerialNumber);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
throw new Exception(string.Format("Error opening first device, ftStatus: {0}", ftStatus));
ftStatus = FtdiWrapper.SetBaudRate(9600);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
throw new Exception(string.Format("Error to set Baud rate, ftStatus: {0}", ftStatus));
// Set data characteristics - Data bits, Stop bits, Parity
ftStatus = FtdiWrapper.SetDataCharacteristics(FTDI.FT_DATA_BITS.FT_BITS_8, FTDI.FT_STOP_BITS.FT_STOP_BITS_1, FTDI.FT_PARITY.FT_PARITY_NONE);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
throw new Exception(string.Format("Error to set data characteristics , ftStatus: {0}", ftStatus));
// Set flow control - set RTS/CTS flow control
ftStatus = FtdiWrapper.SetFlowControl(FTDI.FT_FLOW_CONTROL.FT_FLOW_RTS_CTS, 0x11, 0x13);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
throw new Exception(string.Format("Error to set flow control , ftStatus: {0}", ftStatus));
// Set read timeout to 5 seconds, write timeout to infinite
ftStatus = FtdiWrapper.SetTimeouts(5000, 0);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
throw new Exception(string.Format("Error to set timeouts, ftStatus: {0}", ftStatus));
}
return FtdiWrapper;
}
转换原始传感器数据的方法
static private void ConvertSensorData(FTDI FtdiWrapper, byte sensorChannel)
{
FTDI.FT_STATUS ftStatus = FTDI.FT_STATUS.FT_OTHER_ERROR;
UInt32 numBytesWritten = 0;
byte[] convertCommand = new byte[] { 0x03, 0x40, sensorChannel };
ftStatus = FtdiWrapper.Write(convertCommand, convertCommand.Length, ref numBytesWritten);
bool isAllBytesWritten = numBytesWritten == convertCommand.Length;
if (ftStatus != FTDI.FT_STATUS.FT_OK && isAllBytesWritten)
throw new Exception(string.Format("Failed to write Convert command to device; Status: {0}, isAllBytesWritten: {1}", ftStatus.ToString(), isAllBytesWritten));
}
读取传感器温度的方法
static private float? ReadTemperatureSensor(FTDI FtdiWrapper, byte sensorChannel)
{
float? degreesC = null;
FTDI.FT_STATUS ftStatus = FTDI.FT_STATUS.FT_OTHER_ERROR;
UInt32 numBytesWritten = 0;
byte[] readSensorCommand = new byte[] { 0x03, 0x41, sensorChannel };
ftStatus = FtdiWrapper.Write(readSensorCommand, readSensorCommand.Length, ref numBytesWritten);
bool isAllBytesWritten = numBytesWritten == readSensorCommand.Length;
if (ftStatus != FTDI.FT_STATUS.FT_OK && isAllBytesWritten)
throw new Exception(string.Format("Failed to write readSensorCommand to device; Status: {0}, isAllBytesWritten: {1}", ftStatus.ToString(), isAllBytesWritten));
// Read back response
UInt32 numBytesAvailable = 0;
UInt32 numBytesExpected = 2; // read sensor command expected to return 2 bytes
while (numBytesAvailable == 0)
{
Thread.Sleep(40); // value of 40 taken from DLP IO20 demo solution
ftStatus = FtdiWrapper.GetRxBytesAvailable(ref numBytesAvailable);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
throw new Exception("Failed to get number of bytes available to read; error: " + ftStatus);
} //while (numBytesAvailable < numBytesExpected);
if (numBytesAvailable != numBytesExpected)
throw new Exception("Error: Invalid data in buffer. (1350)");
UInt32 numBytesRead = 0;
byte[] rawData = new byte[numBytesExpected];
ftStatus = FtdiWrapper.Read(rawData, numBytesAvailable, ref numBytesRead);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
throw new Exception("Failed to read data from device after command has been sent; error: " + ftStatus);
//convert raw response data to degrees Celsius
degreesC = ConvertTemperature(rawData);
return degreesC;
}
清除发送缓冲区的方法
static private void PurgeRxBuffer(FTDI FtdiWrapper)
{
UInt32 numBytesAvailable = 0;
UInt32 numBytesRead = 0;
FTDI.FT_STATUS ftStatus = FTDI.FT_STATUS.FT_OTHER_ERROR;
byte[] rx = new byte[1001]; //allocate large enough space to read from device
Thread.Sleep(5);
ftStatus = FtdiWrapper.GetRxBytesAvailable(ref numBytesAvailable);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
throw new Exception("Failed to get number of bytes available to read; error: " + ftStatus);
if (numBytesAvailable > 1000)
numBytesAvailable = 1000;
while (numBytesAvailable > 0)
{
//read the data from the buffer
numBytesRead = 0;
ftStatus = FtdiWrapper.Read(rx, numBytesAvailable, ref numBytesRead);
ftStatus = FtdiWrapper.GetRxBytesAvailable(ref numBytesAvailable);
if (ftStatus != FTDI.FT_STATUS.FT_OK)
throw new Exception("Failed to get number of bytes available to read; error: " + ftStatus);
if (numBytesAvailable > 1000)
numBytesAvailable = 1000;
Thread.Sleep(5);
}
}
将温度从原始数据转换为摄氏温度的方法
static private float? ConvertTemperature(byte[] rawData)
{
float? tempCelsius = null;
bool isnegative = false;
//check input
if (rawData.Length < 2)
throw new Exception(string.Format("Input parameter rawData for temperature conversion must be 2 bytes, actual length is: {0}", rawData.Length));
int temp = rawData[0] | (rawData[1] << 8);
if ((temp & 0x8000) == 0x8000)//if MSBit is set then negative temperature
{
temp &= 0x07ff;
isnegative = true;
temp = 0x800 - temp;
}
temp &= 0x07ff;
tempCelsius = (float)((float)temp / 16.0);
if (isnegative) tempCelsius *= -1;
return tempCelsius;
}
}
答案 0 :(得分:0)
我认为您需要将ConnectToFirstFtdiDevice中的FTDI设备上的延迟计时器设置为最小值,我使用16ms,我帮助解决了这类问题。 purgeRX只是一个软件缓冲区而不是HW,因此不会阻止您在FTDI USB缓冲区中进行过时测量。
答案 1 :(得分:0)
应该在这里使用监视器/命令/响应设计模式。这里有重复的命令/响应序列,因此实现模式可以减少代码中存在的冗余。我开始使用界面&amp;具有事件处理程序的命令/响应结构;即,如果FTDI.deviceCount> 0,然后触发事件处理程序。 ,跟进依赖孩子的处理程序。在接收端,最低级别的.net串口处理程序是基于TDM的。它会在途中丢失一些信息。要完成,添加一个简单的数据包传递协议,例如两端带校验和的XOR。即计算设备上的消息校验和,发送命令,在另一端接收命令,计算校验和,与捕获的校验和进行比较。如果相同则OK,否则,将捕获的命令回送给设备。副总裁在这里..
我的两分钱==我的两美元,同样的事情
答案 2 :(得分:0)
您无法从调用FtdiWrapper.GetRxBytesAvailable获取可用字节。您需要在循环中调用FtdiWrapper.Read,直到获得预期的字节,然后跳出循环。