4

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. さらに 2 ~ 3 サイクルの温度読み取りを実行します。

センサーが加熱された後の最初の読み取りは、20°C の「古い」温度です。2 回目または 3 回目の読み取りサイクルでのみ、28°C 付近で現実的な結果が得られます。

興味深いことに、テスト アプリケーション プログラム IO20Demo (DLP-IO20 ボードの購入に付属) を使用して、読み取り前に Convert コマンドを発行すると、すぐに 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;
    }
}
4

3 に答える 3

0

ここでは、モニター/コマンド/レスポンスの設計パターンを使用する必要があります。ここではコマンド/応答シーケンスが繰り返されるため、パターンを実装することで、コードに存在する冗長性を減らします。私は、イベントハンドラーを備えたインターフェイスとコマンド/応答構造から始めます。つまり、FTDI.deviceCount > 0 の場合、イベント ハンドラーを起動します。、子依存ハンドラーでフォローアップします。受信側では、最下位レベルの .net シリアル ポート ハンドラは TDM ベースです。途中でいくつかの情報が失われます。完全にするには、両端にチェックサムがある XOR などの単純なパケット パッシング プロトコルを追加します。つまり、デバイスでメッセージのチェックサムを計算し、コマンドを送信し、相手側でコマンドを受信し、チェックサムを計算し、取得したチェックサムと比較します。同じ場合はOK、そうでない場合は、キャプチャしたコマンドをデバイスにエコーバックします。ここではその逆..

私の 2 セント == 私の 2 ドル、同じこと

于 2016-08-02T18:41:29.053 に答える
0

ConnectToFirstFtdiDevice の FTDI デバイスのレイテンシ タイマーを最小値に設定する必要があると思います。私は 16ms を使用しており、このタイプの問題を解決するのに役立ちました。purgeRX はハードウェアではなく単なるソフトウェア バッファであるため、FTDI USB バッファに古い測定値が含まれることを防ぐことはできません。

于 2014-09-06T00:54:07.487 に答える
0

FtdiWrapper.GetRxBytesAvailable を呼び出して使用可能なバイトを取得することはできません。予想されるバイト数を取得するまでループ内で FtdiWrapper.Read を呼び出してから、ループから飛び出す必要があります。

于 2017-01-13T21:05:35.260 に答える