На форуме обязательно:
  1. Заполнить свой профиль НА РУССКОМ ЯЗЫКЕ КИРИЛЛИЦЕЙ. См. Правила, п.2.d.
  2. Не писать свой вопрос в первую попавшуюся тему, а вместо этого создать свою. См. Правила, п.3.a.

Дублирование сообщений приравнивается к спаму. Рекламу мы не размещаем ни на каких условиях.

Некорректно обрабатываемый ответ от контроллера ПЛК-150

Ответить

Автор темы
kolyagl
здесь недавно
здесь недавно
Сообщения: 13
Зарегистрирован: 28 апр 2017, 13:57
Имя: Николай
Благодарил (а): 2 раза

Некорректно обрабатываемый ответ от контроллера ПЛК-150

Сообщение kolyagl » 15 июн 2017, 17:13

Здравствуйте, не так много времени прошло с того момента как я создал первую тему на этом форуме) и снова у меня возникли трудности теперь с обработкой ответа, а именно с тем, что каким то мне пока не понятным образом программа написанная мною на C# некорректно обрабатывает ответ от ПЛК-150. Суть проблемы вот в чём ПЛК отправляет мне значение float в виде 4-х байт, задача стоит в том, чтобы эти 4-е байта преобразовать в значение float которое отправляет мне ПЛК. С этой задачей я вроде справился т.к полученные байты я преобразую во float но тут выяснилось, что эти значения не совпадают+ к этому значения в моей программе постоянно изменяются причем не незначительно а как то рандомно. При этом в Modscan всё отлично работает и запрос отправляемый мной полностью совпадает с запросом отправляемым Modscan. А теперь основной вопрос как так получилось, что при одинаковом запросе я получаю разные ответы?) скрины и код к рассказу прилагаются . Да и ещё один интересный факт данная программа нормально работала с ТРМ-138 по суть основа и была взята из той программы

Код: Выделить всё

namespace ТРМ_138
{
    
    public partial class Form1 : Form
    {
        SerialPort serialPort1 = new SerialPort("COM5", 115200, Parity.None, 8, StopBits.One);
        public Form1()
        {
            InitializeComponent();
           
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            serialPort1.Open();
        }

        //Метод формирования запроса ModBus RTU
        public static byte[] ReadHoldingRegister(byte id, byte command, byte startAddress, byte length)
        {
            byte[] data = new byte[8];
            byte High, Low;
            //Адрес устройства
            data[0] = Convert.ToByte(001);
            //Код функции Modbus
            data[1] = Convert.ToByte(004);
            //Начальный адрес регистра
            byte[] _adr = BitConverter.GetBytes(startAddress);
            data[2] = 00;//[1] младший
            data[3] = 00;//[0] старший
            //Колличество регистров которое необходимо считать
            byte[] _length = BitConverter.GetBytes(length);
            data[4] = 00;//[1] 
            data[5] = 02;//[0]
                         //Контрольная сумма CRC
            myCRC(data, 6, out High, out Low);
            data[6] = Low;//[1]
            data[7] = High;//[0]
            return data;
        }

        //Метод расчёта контрольной суммы CRC-16
        public static void myCRC(byte[] message, int length, out byte CRCHigh, out byte CRCLow)
        {
            ushort CRCFull = 0xFFFF;
            for (int i = 0; i < length; i++)
            {
                CRCFull = (ushort)(CRCFull ^ message[i]);
                for (int j = 0; j < 8; j++)
                {
                    if ((CRCFull & 0x0001) == 0)
                        CRCFull = (ushort)(CRCFull >> 1);
                    else
                    {
                        CRCFull = (ushort)((CRCFull >> 1) ^ 0xA001);
                    }
                }
            }
            CRCHigh = (byte)((CRCFull >> 8) & 0xFFFF);
            CRCLow = (byte)(CRCFull & 0xFFFF);
        }

        private void button1_Click(object sender, EventArgs e)
        {
          
          timer1.Enabled=true;         
        }
        private void timer1_Tick(object sender, EventArgs e)
        {
           
             { //Отправка команды для ПЛК-150
                 serialPort1.Write(ReadHoldingRegister(16, 004, 0000, 0010), 0, 8);

                //Побайтовое считывание ответа от ПЛК-150
                byte[] IntArr = new byte[9];
                 for (int i = 0; 8 >= i; ++i)
                 {  
                     IntArr[i] = Convert.ToByte(serialPort1.ReadByte());        
                 }

                string otv = string.Concat(IntArr[0], "   ", IntArr[1], "   ", IntArr[2], "   ", IntArr[3], "   ", IntArr[4], "   ", IntArr[5], "   ", IntArr[6], "   ", IntArr[7], "   ", IntArr[8]);
                textBox5.Text = otv;
           
                //Конвертирование 4-х байт полученных от ПЛК-150 во float
                float value1 =BitConverter.ToSingle(IntArr,2);
                textBox1.Text = value1.ToString();

             }       
        }
    }
}
Помогите советом дельным)))
У вас нет необходимых прав для просмотра вложений в этом сообщении.


LexSL
здесь недавно
здесь недавно
Сообщения: 94
Зарегистрирован: 16 дек 2011, 14:13
Имя: Михайлов Алексей
Поблагодарили: 13 раз

Некорректно обрабатываемый ответ от контроллера ПЛК-150

Сообщение LexSL » 16 июн 2017, 10:34

Код: Выделить всё

float value1 =BitConverter.ToSingle(IntArr,2);
Вы неправильно выбрали смещение для преобразования в Single
Смотрите код, я там Вам в комментариях отписал.

Код: Выделить всё

static void Main(string[] args)
        {
            var bytes = new byte[] {1, 4, 4, 63, 184, 65 , 172, 71, 152}; // ответ от modbus slave
            Console.WriteLine(BitConverter.ToSingle(bytes, 2));// неправильное смещение - дает 23.03077

            //смещение надо 3, так как 
            //1 байт - адрес
            //2 байт - номер функции
            //3 байт - сколько байтов прршло - длина данных (макс 255)
            //4 - данные
            //...
            //n
            //CRC16

            //берем для Single 4 байта со смещением 3 от начала массива
            var bytes1 = bytes.Skip(3).Take(4).ToArray();
            
            //преобразуем в строку с разделителем ";"
            var str = bytes1
                .Select(b => b.ToString())
                .Aggregate((f, s) => f + ";" + s);
            Console.WriteLine(str);
            Console.WriteLine();

            //теперь преобразуем порядок байт из сетевого (big-endian) в little-endian 
            var data = NetworkBytesToHostUInt16(bytes1);
            //получили из набора байтов набор регистров (16 bit) и выведем на экран
            str = data.Select(b => b.ToString()).Aggregate((f, s) => f + ";" + s);
            Console.WriteLine(str);

            //теперь можно сконвертить в Single
            Console.WriteLine(GetSingle(data[1], data[0]));
            Console.WriteLine();

            //демонстрация порядка байт для правильного значения
            float val = 21.53111f;
            var bytes2 = BitConverter.GetBytes(val);
            str = bytes2.Select(b => b.ToString()).Aggregate((f, s) => f + ";" + s);
            Console.WriteLine(str);

            Console.ReadKey();
        }


        //взято из NModbus бибилотеки
        public static ushort[] NetworkBytesToHostUInt16(byte[] networkBytes)
        {
            if (networkBytes == null)
                throw new ArgumentNullException("networkBytes");

            if (networkBytes.Length % 2 != 0)
                throw new Exception("error length");

            ushort[] result = new ushort[networkBytes.Length / 2];

            for (int i = 0; i < result.Length; i++)
                result[i] = (ushort)IPAddress.NetworkToHostOrder(BitConverter.ToInt16(networkBytes, i * 2));

            return result;
        }

        //взято из NModbus бибилотеки
        public static float GetSingle(ushort highOrderValue, ushort lowOrderValue)
        {
            return BitConverter.ToSingle(BitConverter.GetBytes(lowOrderValue).Concat(BitConverter.GetBytes(highOrderValue)).ToArray(), 0);
        }
А вообще,я понимаю, зачем городить свои "костыли" :-P (тут и Modbus TCP и RTU народ на форуме пытается освоить) :ext_book:
Сам через это проходил, в итоге мне всё заменила библиотека NModbus. Погуглите, на гитхабе лежит репозиторий, можно скачать и код и примеры. Если что не понятно, спрашивайте


Автор темы
kolyagl
здесь недавно
здесь недавно
Сообщения: 13
Зарегистрирован: 28 апр 2017, 13:57
Имя: Николай
Благодарил (а): 2 раза

Некорректно обрабатываемый ответ от контроллера ПЛК-150

Сообщение kolyagl » 19 июн 2017, 09:35

Спасибо за ответ. Смещение верное т.к нумерация с нуля начинается(т.е 0, 1, 2 байт пропускаются и мы начинаем выдёргивать 4-е байта с 3-го) 0-адрес 1-номер функции 2-количество байт 3-данные. С библиотекой сейчас постараюсь ознакомится.

Код: Выделить всё

  //теперь преобразуем порядок байт из сетевого (big-endian) в little-endian 
            var data = NetworkBytesToHostUInt16(bytes1);
мне не совсем понятно это действие, зачем преобразовывать порядки? Я в разных порядках пытался читать байты результат не изменился. Может конечно я делал, что-то не так, если можно поподробнее объясните.

Отправлено спустя 1 час 9 минут 43 секунды:
Всё заработало. Тема закрыта спасибо за помощь. Если по библиотеке вопросы будут в ЛС могу писать?


LexSL
здесь недавно
здесь недавно
Сообщения: 94
Зарегистрирован: 16 дек 2011, 14:13
Имя: Михайлов Алексей
Поблагодарили: 13 раз

Некорректно обрабатываемый ответ от контроллера ПЛК-150

Сообщение LexSL » 20 июн 2017, 16:51

kolyagl писал(а): Я в разных порядках пытался читать байты результат не изменился.
Вы читаете байты так, как они к Вам пришли, ничего не поделаешь)))
А вот интерпретировать их Вы вольны уже как угодно.
Если вопросы будут, то спрашивайте здесь (может быть не нам одним будет интересно). будет много вопросов, то попросим администрацию перенести в новую тему

Ответить

Вернуться в «ОВЕН»