Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > .NET Frameworks (точка нет фреймворки) > C# (си шарп)
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 02.11.2020, 03:38   #1
Kalculon
Новичок
Джуниор
 
Регистрация: 02.11.2020
Сообщений: 4
По умолчанию SerialPorts

Здравствуйте!

Есть термометр, к нему идет описание, что он работает по простому бинарному протоколу, нужно отослать 01hex и он ответит двумя байтами температуры. По коду ниже я получаю ответ "7 8 63 63 35 40". В десятичном формате, потому что температура формируется из ответа таким образом (byte1*256 + byte2 - 1000) / 10.

Проверяя термометр меняются последние два байта, подскажите пожалуйста, как правильно провести парсинг, чтобы получить правильное значение.



Код:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO.Ports;
using System.IO;



namespace CP_Serial_Port_Terminal
{
    public partial class Form1 : Form
    {
        string sendWith;
        string dataIN;
        int dataINLength;
        int[] dataInDec;

        StreamWriter objStreamWriter;
        string pathFile;
        bool state_AppendText = true;

   
       

        public Form1()
        {
            InitializeComponent();
        }
        private string RxDataFormat(int[] dataInput)
        {
            string strOut = "";


            foreach (int element in dataInput)
            {
                strOut += Convert.ToString(element) + "\t";
            }


            return strOut;
        }

        private void TxDataFormat()
        {
            //Declare Local Variable
            string dataOutBuffer;
            int countComma = 0;
            string[] dataPrepareToSend;
            byte[] dataToSend;

            try
            {
                //Move the data package in the textbox into a variable
                dataOutBuffer = tBoxDataOut.Text;

                //Count how much comma (,) punctuation in the data package
                foreach (char c in dataOutBuffer) { if (c == ',') { countComma++; } }

                //Create one-dimensional array (string data type) with the length based on the countComma
                dataPrepareToSend = new string[countComma];

                //Parsing the data in dataOutBuffer and save it into an array dataPrepareToSend based on comma punctuation
                countComma = 0; //Reset Value to 0
                foreach (char c in dataOutBuffer)
                {
                    if (c != ',')
                    {
                        //Append the data to array of dataPrepareToSend
                        dataPrepareToSend[countComma] += c;
                    }
                    else
                    {
                        //If a comma finds in the data package, then increase the countComma variable. CountComma is using to determine the index of dataPrepareToSend array
                        countComma++;
                        //Stop foreach process if numbers of countComma equal to the size of dataPrepareToSend
                        if (countComma == dataPrepareToSend.GetLength(0)) { break; }
                    }
                }

                //Create one-dimensional array (byte data type) with the length based on the size of dataPrepareToSend
                dataToSend = new byte[dataPrepareToSend.Length];


                //Convert data in string array (dataPrepareToSend) into byte array(dataToSend)
                for (int a = 0; a < dataPrepareToSend.Length; a++)
                {
                    dataToSend[a] = Convert.ToByte(dataPrepareToSend[a], 10);
                    //Convert string to an 8-bit unsigned integer with the specified base number
                    //Value 10 mean Decimal
                }


                //Send a specified number of bytes to the serial port
                serialPort1.Write(dataToSend, 0, dataToSend.Length);

                //Calculate the length of data sent and then show it

            }
            catch (Exception error)
            {
                MessageBox.Show(error.Message);
            }

        }

        private void TxSendData()
        {
            if (serialPort1.IsOpen)
            {

                //serialPort1.Write(dataOUT + "\r\n");
                TxDataFormat();
                serialPort1.Write("\r\n");
            }

        }
        private void Form1_Load(object sender, EventArgs e)
        {
            serialPort1.PortName = "COM4";
            serialPort1.BaudRate = 115200;
            serialPort1.DataBits = 8;
            serialPort1.StopBits = StopBits.One;
            serialPort1.Parity = Parity.Even;

            serialPort1.Open();

          
        }

        private void btnSendData_Click(object sender, EventArgs e)
        {
            TxSendData();
        }

        private void toolStripComboBox2_DropDownClosed(object sender, EventArgs e)
        {
         
                sendWith = @"Both (\r\n)";
           
        }

        private void doSomething()
        {
            TxSendData();
        }

        private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            //dataIN = serialPort1.ReadExisting();

            List<int> dataBuffer = new List<int>();

            while(serialPort1.BytesToRead > 0)
            {
                try
                {
                    dataBuffer.Add(serialPort1.ReadByte());
                }
                catch(Exception error)
                {
                    MessageBox.Show(error.Message);
                }
            }

            dataINLength = dataBuffer.Count();
            dataInDec = new int[dataINLength];
            dataInDec = dataBuffer.ToArray();

            this.Invoke(new EventHandler(ShowData));
        }

        private void ShowData(object sender, EventArgs e)
        {
            //int dataINLength = dataIN.Length;

            dataIN = RxDataFormat(dataInDec);

            tBoxDataIN.Text = tBoxDataIN.Text.Insert(0, dataIN);
               

      
        }

        private void tBoxDataIN_TextChanged(object sender, EventArgs e)
        {

        }
    }
}
Оригинальный код не мой. Честно скачал и сделал из велосипеда самокат, для собственного удобства.

Заранее спасибо!
Kalculon вне форума Ответить с цитированием
Старый 02.11.2020, 10:56   #2
Black Fregat
Программист
Участник клуба
 
Аватар для Black Fregat
 
Регистрация: 23.06.2009
Сообщений: 1,772
По умолчанию

Цитата:
Сообщение от Kalculon Посмотреть сообщение
Проверяя термометр меняются последние два байта, подскажите пожалуйста, как правильно провести парсинг, чтобы получить правильное значение.
!
Надо смотреть, что именно написано в руководстве
Black Fregat вне форума Ответить с цитированием
Старый 02.11.2020, 12:24   #3
Kalculon
Новичок
Джуниор
 
Регистрация: 02.11.2020
Сообщений: 4
По умолчанию

Цитата:
Сообщение от Black Fregat Посмотреть сообщение
Надо смотреть, что именно написано в руководстве
Serial interface parameters

Baud rate: 9600…115200, set by user (factory default: 115200) Data bits: 8 Parity: none Stop bits: 1 Flow control: off

Protocol

The protocol of the optris CT/ CTlaser/ CTvideo is a binary protocol. Checksum is needed for set commands but not for read commands. The protocol has no additional overhead with CR, LR or ACK bytes. This makes the communication fast. To get the current object temperature the user must send a simple 01hex byte and the CT/ CTlaser/ CTvideo will respond with the two byte temperature. To get the temperature as a floating value subtract 1000 and divide by 10.

Checksum’s

If the device is setup to use checksums any SET command must have a checksum suffix. The checksum can be switched off with command AD. After every “Power on” the device will expect the checksum again. The checksum byte is build by the arithmetical XOR of all command bytes except of the address prefix.

To switch off the checksums with the SET command AD you must send the checksum. To switch on the checksums with the SET command AD you must not send the checksum.


Комманды:
CSlaser/ CSvideo Commands
Decimal HEX Binary/ ASCII Command Data Answer Result Unit

1 0x01 binary READ Temp - Target no byte1 byte2 = (byte1 x 256 + byte2 - 1000) / 10 °C
2 0x02 binary READ Temp - Head no byte1 byte2 = (byte1 x 256 + byte2 - 1000) / 10 °C
3 0x03 binary READ current Temp - Target no byte1 byte2 = (byte1 x 256 + byte2 - 1000) / 10 °C
4 0x04 binary READ Emissivity no byte1 byte2 = (byte1 x 256 + byte2) / 1000
5 0x05 binary READ Transmission no byte1 byte2 = (byte1 x 256 + byte2) / 1000
9 0x09 binary READ Processor Temperature no byte1 = (byte1 x 256 + byte2 - 1000) / 10
14 0x0E binary READ Serial number no byte1 byte2 byte3 = byte1 x 65536 + byte2 x 256 + byte3
15 0x0F binary READ FW Rev. no byte1 byte2 = byte1 x 256 + byte2
16 0x10 binary READ Laser status no byte1 0 = off/ 1 = on
17 0x11 binary READ Emissivity switch setting no HEX value (e.g. 0x58) = Switch setting (e.g. SW1=5/ SW2=8 -> Eps. = 0,58)
129 0x81 binary SET DAC mA byte1 byte1 byte 1= mA x 10 (z.B. 4mA = 4 x 10=40) °C
130 0x82 binary RESET of DAC mA output
132 0x84 binary SET Emissivity byte1 byte2 byte1 byte2 = (byte1 x 256 + byte2) / 1000
133 0x85 binary SET Transmission byte1 byte2 byte1 byte2 = (byte1 x 256 + byte2) / 1000
144 0x90 binary SET Laser byte1 byte1 0 = off/ 1 = on

Temperature calculation at CSlaser hs: (byte1 x 256 + byte2 - 10000) / 100

EXAMPLES (all bytes in HEX)

Readout of object temperature

Send: 01 Command for readout of object temperature
Receive: 04 D3 Object temperature in tenth degree + 1000 04 D3 = dec. 1235
1235 - 1000 = 235
235 / 10 = 23,5 °C

Readout of object temperature (at hs version)

Send: 01 Command for readout of object temperature
Receive: 30 3E Object temperature in hundredth degree + 10000 30 3E = dec. 12350
12350 - 10000 = 2350
2350 / 100 = 23.50 °C

Set of emissivity

Send: 84 03 B6 03B6 = dec. 950
Receive: 03 B6 950 / 1000 = 0,950
Kalculon вне форума Ответить с цитированием
Старый 02.11.2020, 14:07   #4
Black Fregat
Программист
Участник клуба
 
Аватар для Black Fregat
 
Регистрация: 23.06.2009
Сообщений: 1,772
По умолчанию

А зачем Вы пишете в порт \r\n ?
По доке нужно писать только \x01

Я ещё покопаю - откуда взялось 6 байт ответа

То есть на текущий момент непонятно:
1) что именно ушло в порт
2) какие байты ответа надо рассматривать.

Попробуйте убрать лишнюю запись, посмотрим, что ответит устройство

Последний раз редактировалось Black Fregat; 02.11.2020 в 14:13.
Black Fregat вне форума Ответить с цитированием
Старый 03.11.2020, 08:19   #5
WorldMaster
Старожил
 
Аватар для WorldMaster
 
Регистрация: 25.08.2011
Сообщений: 2,841
По умолчанию

Почему не прикладываете модель термометра то??

Вроде код то элементарный:
На картинке тестовый пример.

А ваш код получения данных будет таким:

Код:
port.ReceivedBytesThreshold = 2;
            port.DiscardInBuffer();
            port.DiscardOutBuffer();
            port.Write(new byte[] { 0x01 }, 0, 1);
            while (port.BytesToRead < 2)
                Thread.Sleep(100);

            byte[] data = new byte[2];
            port.Read(data, 0, 2);

            // в зависимости от типа отправки LSB или HSB то возможно придется развернуть массив
            // data = data.Reverse().ToArray();

            dec = BitConverter.ToInt16(data, 0);
            temp = ((float)dec - 1000.0f) / 10.0f;
Если хотите то переделайте на событие приема хотя так как значение по запросу и ответ короткий то даже такая обработка не затормозит систему.
Изображения
Тип файла: png port1.png (6.1 Кб, 12 просмотров)
Skype - wmaster_s E-Mail - WorldMasters@gmail.com
Работаем по 3 критериям - быстро, качественно, недорого. Заказчик выбирает любые два.

Последний раз редактировалось WorldMaster; 03.11.2020 в 08:27.
WorldMaster вне форума Ответить с цитированием
Старый 03.11.2020, 14:19   #6
Kalculon
Новичок
Джуниор
 
Регистрация: 02.11.2020
Сообщений: 4
По умолчанию

Цитата:
Сообщение от WorldMaster Посмотреть сообщение
Почему не прикладываете модель термометра то??

Вроде код то элементарный:
На картинке тестовый пример.

А ваш код получения данных будет таким:

Код:
port.ReceivedBytesThreshold = 2;
            port.DiscardInBuffer();
            port.DiscardOutBuffer();
            port.Write(new byte[] { 0x01 }, 0, 1);
            while (port.BytesToRead < 2)
                Thread.Sleep(100);

            byte[] data = new byte[2];
            port.Read(data, 0, 2);

            // в зависимости от типа отправки LSB или HSB то возможно придется развернуть массив
            // data = data.Reverse().ToArray();

            dec = BitConverter.ToInt16(data, 0);
            temp = ((float)dec - 1000.0f) / 10.0f;
Если хотите то переделайте на событие приема хотя так как значение по запросу и ответ короткий то даже такая обработка не затормозит систему.
Модель такая https://www.optris.ru/ctlaser-1m2m

По сути да, нужна простая форма с текстовым окном, в котором актуальная температура.
Я не очень понимаю в какую часть кода надо вставить этот отрывок
Kalculon вне форума Ответить с цитированием
Старый 03.11.2020, 18:01   #7
WorldMaster
Старожил
 
Аватар для WorldMaster
 
Регистрация: 25.08.2011
Сообщений: 2,841
По умолчанию

Цитата:
Сообщение от Kalculon Посмотреть сообщение
Я не очень понимаю в какую часть кода надо вставить этот отрывок
У вас проект какой то слишком уж запутанный. Столько всего лишнего что я так с ходу не соображу куда вам это вставить.
Но как простой вариант - сделать кнопку. По нажатию на нее в обработчике и вставьте этот код. Разве что нужно будет компорт открыть. а потом закрыть.

Если надо чтобы постоянно работало то вначале работы программы откройте порт и в какой нибуть таймере вставьте этот код. он и будет выводить данные на вашу форму.
Skype - wmaster_s E-Mail - WorldMasters@gmail.com
Работаем по 3 критериям - быстро, качественно, недорого. Заказчик выбирает любые два.
WorldMaster вне форума Ответить с цитированием
Старый 03.11.2020, 18:58   #8
Black Fregat
Программист
Участник клуба
 
Аватар для Black Fregat
 
Регистрация: 23.06.2009
Сообщений: 1,772
По умолчанию

Вы можете, наконец, сделать то, что я попросил?
Уберите запись "\r\n", поставьте вместо этого запись "\x01"
И выложите ответ от устройства
Black Fregat вне форума Ответить с цитированием
Старый 04.11.2020, 19:33   #9
Kalculon
Новичок
Джуниор
 
Регистрация: 02.11.2020
Сообщений: 4
По умолчанию

Цитата:
Сообщение от Black Fregat Посмотреть сообщение
Вы можете, наконец, сделать то, что я попросил?
Уберите запись "\r\n", поставьте вместо этого запись "\x01"
И выложите ответ от устройства
Убрал, вставил "63 35 40 63 35 40", обрабатывая байты получается то что нужно, но последовательность байтов иногда меняется, и температура скачет от 800 до 1532(((
Вообщем я забил, буду мониторить на дисплейчике(
Извиняюсь что не отвечал.

"А зачем Вы пишете в порт \r\n ?
По доке нужно писать только \x01"

А что это вообще?

Последний раз редактировалось Kalculon; 04.11.2020 в 19:34. Причина: невнимательность
Kalculon вне форума Ответить с цитированием
Старый 04.11.2020, 22:00   #10
WorldMaster
Старожил
 
Аватар для WorldMaster
 
Регистрация: 25.08.2011
Сообщений: 2,841
По умолчанию

Цитата:
Сообщение от Kalculon Посмотреть сообщение
но последовательность байтов иногда меняется, и температура скачет от 800 до 1532
Инверсия байтов поможет скорее всего
Skype - wmaster_s E-Mail - WorldMasters@gmail.com
Работаем по 3 критериям - быстро, качественно, недорого. Заказчик выбирает любые два.
WorldMaster вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц