Форум программистов, компьютерный форум, киберфорум
C# .NET
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.87/15: Рейтинг темы: голосов - 15, средняя оценка - 4.87
 Аватар для chjzjk
3 / 3 / 2
Регистрация: 31.10.2013
Сообщений: 22

SerialPort(COM) Разрыв пакета при приеме

10.11.2015, 13:57. Показов 2964. Ответов 3
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Вся соль в приеме данных... Настроил виртуальный порты - гоняю данные все работает идеально, пробую связать 2 машины - приходит не всЕ сообщение, а скачала кусок, потом второй кусок(пакет 15 байт). В принципе не проблема склеить пакет, но как-то не комильфо. Или так и должно быть?
Могу приклеить код если нужно.

Добавлено через 19 минут
Вообщем решил вроде проблему. Оказалось что нужно просто поставить задержку. Ну и конечно обнулять буфер после приема.
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
//где-то в конструкторе 
 _serialPort.DataReceived += _serialPort_DataReceived;
 
 void _serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            Thread.Sleep(15);
            ReadFromComPort();
            _serialPort.DiscardInBuffer();
        }
 public bool ReadFromComPort()
        {
            int CountReadBuf = _serialPort.BytesToRead;
            if (CountReadBuf != 0)
            {
                //MessageBox.Show("Count=" + CountReadBuf.ToString());
                byte[] ReadBuffer = new byte[CountReadBuf];
                try
                {
                    _serialPort.Read(ReadBuffer,0,CountReadBuf);
                    MessageIn.Add(new MessagePer("COM",ReadBuffer,"INPUT"));// моя обработка
                    //MessageBox.Show(String.Join(" ",MessageIn[MessageIn.Count-1].Data));
                    return true;
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Error Read to serial port :: "
                      + ex.Message, "Error!");
                    return false;
                }
                
            }
            return false;
        }
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
10.11.2015, 13:57
Ответы с готовыми решениями:

Возможно ли при импорте в модуль пакета подняться выше пакета?
Есть скрипты .py, лежащие на одном уровне(в одном каталоге) и есть пакет модулей, лежащий на том же самом уровне. Возможно ли...

Виснет USART при приеме
Добрый вечер всем. Подскажите как решить проблему с USORT. Проверяю через proteus и его терминал следующий код: Вот это подключаемый...

Задание при приеме на работу
Здравствуйте, уважаемые форумчане! При устройстве на работу получила перечень заданий, с большинством из которых уже справилась. Осталось...

3
 Аватар для Sanya_sa
912 / 816 / 333
Регистрация: 03.02.2015
Сообщений: 5,276
Записей в блоге: 9
10.11.2015, 14:22
Цитата Сообщение от chjzjk Посмотреть сообщение
приходит не всЕ сообщение
это нормально что не все приходят, я сам их клею. Ща посмотрю гдето проект был давнишний.

Добавлено через 12 минут
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
       public event EventHandler end_data;
       public event EventHandler get_ans_dl_point;
 
        // Для обработки данных и подключения к СОМ порту
        public void scan_ports()
        {
            while(true)
            {
                System.Threading.Thread.Sleep(65);
 
                if(!on)
                {
                    on = Scan_com_ports();
                    all_reset();
                }
                else
                {
                    id_lave = true;     // установим id_lave в true если Read_data_com не выставит в false 
                                        //то читаем дальше если нет то пытаемся сново пронюхать порты
                    
                    Read_data_com();
 
                    if (!id_lave)
                    { 
                        on = id_lave;
                        main_serial.Close();
                    }
                }
            }
        }
 
        // Обнуляем все переменные
        public void all_reset()
        {
            real_cren = 0;
            real_tangaj = 0;
            axel_x = 0;
            axel_y = 0;
            axel_z = 0;
            giro_x = 0;
            giro_y = 0;
            giro_z = 0;
            real_curs = 0;
            real_vertical_speed = 0;
            real_h = 0;
 
            rssi = -1;
            latitude = -1;
            longitude = -1;
 
            curs_gps = 0;
            h_gps = 0;
            speed_gps = 0;
            satilite_gps = -1;
 
            I_last = 0; ;
            I = 0; ;
            U = -1; ;
            U_ant = -1;
            stat_system = false;
            stat_motors = false;
            stat_load = false;
            stat_around = false;
            stat_start = false;
            stat_end = false;
            stat_stop = false;
            stat_gps = false;
            stat_home = false;
        }
 
        // Читаем наиболее актуальные данные из буфера СОМ порта
        public void Read_data_com()
        {
            try
            {
                byte[] tmp_buffer = new byte[4096];
                int size = main_serial.Read(tmp_buffer, 0, 4096);
 
 
                // Вначале оттделим команды и сохраним их в списке команд CommandList,
                // в данном списке команда с одним кодом будет в единственном экземляре
                // таким образом команда с конкретным кодом будет являться последней пришедшей с устройства, т.е. актуальной
                for (int i = 0; i < size; ++i)
                {
                    // Пытаемся поймать ответы на наши действия
                    if (i < tmp_buffer.Length - 16)
                    {
                        if (tmp_buffer[i] == 0xff && tmp_buffer[i + 1] == 0xff && tmp_buffer[i + 2] == 0x63 && tmp_buffer[i + 4] != 0)
                        {
                            back_mesage[0] = tmp_buffer[i + 4];
                            back_mesage[1] = tmp_buffer[i + 5];
                            back_mesage[2] = tmp_buffer[i + 6];
                            back_mesage[3] = tmp_buffer[i + 7];
                            back_mesage[4] = tmp_buffer[i + 8];
                            back_mesage[5] = tmp_buffer[i + 9];
                            back_mesage[6] = tmp_buffer[i + 10];
                            back_mesage[7] = tmp_buffer[i + 11];
                            back_mesage[8] = tmp_buffer[i + 12];
                            back_mesage[9] = tmp_buffer[i + 13];                            
                        }
 
                        if (tmp_buffer[i] == 0xff && tmp_buffer[i + 1] == 0xff && tmp_buffer[i + 2] == 0x64 && tmp_buffer[i + 4] != 0)
                        {
                            back_mesage[10] = tmp_buffer[i + 4];
                            back_mesage[11] = tmp_buffer[i + 5];
                            back_mesage[12] = tmp_buffer[i + 6];
                            back_mesage[13] = tmp_buffer[i + 7];
                            back_mesage[14] = tmp_buffer[i + 8];
                            back_mesage[15] = tmp_buffer[i + 9];
 
                            // Событие отклик на наши действия
                            if (get_ans_dl_point != null) get_ans_dl_point(this, EventArgs.Empty);
                        }                      
                    }
 
                    // Получен маркер нового пакета данных в то время как предыдущий пакет не был дополучен 
                    // (обеспечивается условием DataBufferSize > 1)
                    if (tmp_buffer[i] == 0xff && DataBufferSize > 1 && DataBuffer[DataBufferSize - 1] == 0xff)
                    {
 
                        // Обнулим буффер данных от устройства
                        DataBuffer[0] = 0xff;
                        DataBufferSize = 1;
                    }
 
                    DataBuffer[DataBufferSize] = tmp_buffer[i];
                    ++DataBufferSize;
 
 
                    // Пакеты данных всегда по MAX_DATA_SIZE байт
                    if (DataBufferSize >= MAX_DATA_SIZE)
                    {
                        AddCommand(DataBuffer, DataBufferSize);
 
                        // После разбора данных обнулим буффер
                        DataBufferSize = 0;
                    }
                }
 
                // После получения всех команд обработаем  все данные пришедшие в _актуальных_ командах
                System.Collections.Generic.IEnumerator<System.Collections.Generic.KeyValuePair<byte, byte[]>> enumerator = CommandList.GetEnumerator();
 
                while (enumerator.MoveNext())
                {
                    System.Collections.Generic.KeyValuePair<byte, byte[]> item = enumerator.Current;
                    ParseData(item.Value, item.Value.Length);
                }
                CommandList.Clear();
 
                // Событие окончания
                if (end_data != null) end_data(this, EventArgs.Empty);
            }
 
            catch (System.InvalidOperationException)
            {
                id_lave = false;
            }
 
            catch (System.Exception)
            {
            }
        }
 
        // Поиск нужного порта
        public bool Scan_com_ports()
        {
            // Очищаем массив для хранаения имён СОМ портов и записываем в него имена имеющихся СОМ в системе,
            // необходимо если число ком портов измененилось
            Array.Clear(com_array, 0, com_array.Length);
            com_array = System.IO.Ports.SerialPort.GetPortNames();
 
            if (com_array.Length <= 0)
                return false;
 
            for (int i = 0; i < com_array.Length; ++i)
            {
                try
                {
                    main_serial.Close();
                    if (!main_serial.IsOpen)
                    {
                        main_serial.PortName = com_array[i];
                        main_serial.BaudRate = 57600;
                        main_serial.ReadTimeout = 2000;
                        main_serial.WriteBufferSize = 2048;
                        main_serial.RtsEnable = true;
                        main_serial.DataBits = 8;
                        main_serial.Open();
 
                        System.Threading.Thread.Sleep(310); // время для заполнения буфера СОМ порта
                        main_serial.Read(tmp_buffer, 0, 400);
                        System.Threading.Thread.Sleep(310); // время для заполнения буфера СОМ порта
 
                        // условие того что порт нужный
                        for (int j = 0; j < size - 16; ++j)
                        {
                            if (tmp_buffer[j] == 0xff && tmp_buffer[j + 1] == 0xff && tmp_buffer[j + 2] == 0x75)
                                return true;
                        }
                    }
                }
                catch (System.Exception )
                {
                   
                }
            }
            
            return false;
        }
 
 // Комнды обрабатываются
        private bool AddCommand(byte[] data_buffer, int data_size)
        {
            if (data_size < MAX_DATA_SIZE || data_buffer[0] != 0xFF || data_buffer[1] != 0xFF)
                return false;
            CommandList[data_buffer[2]] = new byte[data_size];
            Array.Copy(data_buffer, CommandList[data_buffer[2]], data_size);
            return true;
        }

Давно писал только начинал программировать. так что не очень всё красиво, но зато по сей день работает отлично.
Это часть кода так что если не обьявленные методы встретети не удивляйтесь. Вам Read_data_com() и AddCommand будет интересен. В ParseData просто через case выбираем нужные пакеты.
0
 Аватар для chjzjk
3 / 3 / 2
Регистрация: 31.10.2013
Сообщений: 22
11.11.2015, 10:48  [ТС]
Хз, вроде не очень правильно ожидать 4096 байт. Тем более, что вы их никогда не получите целиком и массив будет забиваться до конца нулями, от сюда и клейка пакета. Я организовывал передачу на 2 устройствах сразу, то есть под конкретную задачу(пакет 15 байт) и их реально можно получать применив задержку. Думал что достаточно будет установить параметр serialPort.ReadTimeout, но у меня почему-то он, ни на что не влиял. Обычно при большом ожидании данных используют побайтовое чтение (зная за ранее размер данных, или управляющий конечный символ)
0
2 / 2 / 2
Регистрация: 05.09.2018
Сообщений: 183
13.08.2021, 10:52
Цитата Сообщение от chjzjk Посмотреть сообщение
Вообщем решил вроде проблему. Оказалось что нужно просто поставить задержку. Ну и конечно обнулять буфер после приема.
А куда вы добавили задержку?
Я пользуюсь свойством read timeout, но оно ни на что не влияет, и пакет всё равно разрывается
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
13.08.2021, 10:52
Помогаю со студенческими работами здесь

Задача при приеме на работу
Офигенская задача, я ее давно услышал. Сейчас Вам повествую о ней Пришел один человек для приема на работу. Ему задают 4...

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

Траблы с MSCOMM при приеме SMS
Приветствую форумчан. Кто нибудь занимался приемом SMS с трубы подключенной через DATA-кабель к компу? Пробовал использовать...

Тестовое задание при приеме на работу
Друг искал работу. В одной из контор предложили тестовое задание: ----- Разработать на VC векторный графический редактор, с...

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


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
4
Ответ Создать тему
Новые блоги и статьи
SDL3 для Web (WebAssembly): Реализация движения на Box2D v3 - трение и коллизии с повёрнутыми стенами
8Observer8 20.02.2026
Содержание блога Box2D позволяет легко создать главного героя, который не проходит сквозь стены и перемещается с заданным трением о препятствия, которые можно располагать под углом, как верхнее. . .
Конвертировать закладки radiotray-ng в m3u-плейлист
damix 19.02.2026
Это можно сделать скриптом для PowerShell. Использование . \СonvertRadiotrayToM3U. ps1 <path_to_bookmarks. json> Рядом с файлом bookmarks. json появится файл bookmarks. m3u с результатом. # Check if. . .
Семь CDC на одном интерфейсе: 5 U[S]ARTов, 1 CAN и 1 SSI
Eddy_Em 18.02.2026
Постепенно допиливаю свою "многоинтерфейсную плату". Выглядит вот так: https:/ / www. cyberforum. ru/ blog_attachment. php?attachmentid=11617&stc=1&d=1771445347 Основана на STM32F303RBT6. На борту пять. . .
Камера Toupcam IUA500KMA
Eddy_Em 12.02.2026
Т. к. у всяких "хикроботов" слишком уж мелкий пиксель, для подсмотра в ESPriF они вообще плохо годятся: уже 14 величину можно рассмотреть еле-еле лишь на экспозициях под 3 секунды (а то и больше),. . .
И ясному Солнцу
zbw 12.02.2026
И ясному Солнцу, и светлой Луне. В мире покоя нет и люди не могут жить в тишине. А жить им немного лет.
«Знание-Сила»
zbw 12.02.2026
«Знание-Сила» «Время-Деньги» «Деньги -Пуля»
SDL3 для Web (WebAssembly): Подключение Box2D v3, физика и отрисовка коллайдеров
8Observer8 12.02.2026
Содержание блога Box2D - это библиотека для 2D физики для анимаций и игр. С её помощью можно определять были ли коллизии между конкретными объектами и вызывать обработчики событий столкновения. . . .
SDL3 для Web (WebAssembly): Загрузка PNG с прозрачным фоном с помощью SDL_LoadPNG (без SDL3_image)
8Observer8 11.02.2026
Содержание блога Библиотека SDL3 содержит встроенные инструменты для базовой работы с изображениями - без использования библиотеки SDL3_image. Пошагово создадим проект для загрузки изображения. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru