Форум программистов, компьютерный форум, киберфорум
C++ Builder
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.75/4: Рейтинг темы: голосов - 4, средняя оценка - 4.75
0 / 0 / 2
Регистрация: 28.10.2015
Сообщений: 36
1

Потеря байтов при выводе в Memo (потоки)

06.04.2016, 16:45. Показов 707. Ответов 4
Метки нет (Все метки)

Присылаются пачти байтов . У меня программа выводит 9 байт информации с RS 485 в Memo. Мне из них нужен седьмой, потому что это температура. вот пачка:FF 00 00 FF 14 FF 2C FF 2E. На самом деле начинаться пачка может с любого байта, только 2С - это температура. Проблема. Раньше я думала,что при выводе в Memo пачки смещаются каким-то образом и ,когда я хочу поймать bufrd[6] - это всегда разные значения. Сейчас я увидела, что 1 строка мемо: 1 пачка приходит, 2 строка приходит: вторая приходит обрезанная сначала, теряя наколько байтов перед этим где-то и дополняя себя уже третьей пачкой. 3 строка : теряются несколько байтов+ что осталось от 3 пачки + начало 4 пачки.

Посмотрите поток , пожалуйста, может,я там где косячу. Выложу вариант нахождения температуры по уже имеющимся до нее байтам. Скажите, можно ли так делать?
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
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
#include <vcl.h>
#pragma hdrstop
#include <io.h>         //для работы с файлами
#include <fcntl.h>      //для работы с файлами
#include <sys\stat.h>   //для работы с файлами
 
#include "Unit3.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm3 *Form3;
//=============================================================================
//..................... объявления глобальных переменных ......................
//=============================================================================
 
#define BUFSIZE 255     //ёмкость буфера
 
unsigned char bufrd[BUFSIZE], bufwr[BUFSIZE]; //приёмный и передающий буферы
 
//---------------------------------------------------------------------------
 
HANDLE COMport;     //дескриптор порта
 
//структура OVERLAPPED необходима для асинхронных операций, при этом для операции чтения и записи нужно объявить разные структуры
//эти структуры необходимо объявить глобально, иначе программа не будет работать правильно
OVERLAPPED overlapped;      //будем использовать для операций чтения (см. поток ReadThread)
OVERLAPPED overlappedwr;        //будем использовать для операций записи (см. поток WriteThread)
 
//---------------------------------------------------------------------------
 
int handle;                 //дескриптор для работы с файлом с помощью библиотеки <io.h>
 
//---------------------------------------------------------------------------
 
bool fl=0;  //флаг, указывающий на успешность операций записи (1 - успешно, 0 - не успешно)
 
unsigned long counter;  //счётчик принятых байтов, обнуляется при каждом открытии порта
 
 
 
//.............................. объявления функций ...........................
//=============================================================================
 
void COMOpen(void);             //открыть порт
void COMClose(void);            //закрыть порт
 
//=============================================================================
//.............................. объявления потоков ...........................
//=============================================================================
 
//---------------------------------------------------------------------------
 
//поток для чтения последовательности байтов из COM-порта в буфер
class ReadThread : public TThread
{
 private:
        void __fastcall Printing(); //вывод принятых байтов на экран и в файл
 protected:
        void __fastcall Execute();  //основная функция потока
 public:
        __fastcall ReadThread(bool CreateSuspended);    //конструктор потока
};
 
//---------------------------------------------------------------------------
 
//поток для записи последовательности байтов из буфера в COM-порт
class WriteThread : public TThread
{
private:
    void __fastcall Printing(); //вывод состояния на экран
protected:
        void __fastcall Execute();      //основная функция потока
public:
        __fastcall WriteThread(bool CreateSuspended);   //конструктор потока
};
 
//---------------------------------------------------------------------------
 
 
//=============================================================================
//.............................. реализация потоков ...........................
//=============================================================================
 
//-----------------------------------------------------------------------------
//............................... поток ReadThead .............................
//-----------------------------------------------------------------------------
 
ReadThread *reader;     //объект потока ReadThread
 
//---------------------------------------------------------------------------
 
//конструктор потока ReadThread, по умолчанию пустой
__fastcall ReadThread::ReadThread(bool CreateSuspended) : TThread(CreateSuspended)
{}
 
//---------------------------------------------------------------------------
 
//главная функция потока, реализует приём байтов из COM-порта
void __fastcall ReadThread::Execute()
{
 COMSTAT comstat;       //структура текущего состояния порта, в данной программе используется для определения количества принятых в порт байтов
 DWORD btr, temp, mask, signal; //переменная temp используется в качестве заглушки
 
 overlapped.hEvent = CreateEvent(NULL, true, true, NULL);   //создать сигнальный объект-событие для асинхронных операций
 SetCommMask(COMport, EV_RXCHAR);                               //установить маску на срабатывание по событию приёма байта в порт
 while(!Terminated)                     //пока поток не будет прерван, выполняем цикл
  {
   WaitCommEvent(COMport, &mask, &overlapped);                  //ожидать события приёма байта (это и есть перекрываемая операция)
   signal = WaitForSingleObject(overlapped.hEvent, INFINITE);   //приостановить поток до прихода байта
   if(signal == WAIT_OBJECT_0)                      //если событие прихода байта произошло
    {
     if(GetOverlappedResult(COMport, &overlapped, &temp, true)) //проверяем, успешно ли завершилась перекрываемая операция WaitCommEvent
      if((mask & EV_RXCHAR)!=0)                 //если произошло именно событие прихода байта
       {
        ClearCommError(COMport, &temp, &comstat);       //нужно заполнить структуру COMSTAT
        btr = comstat.cbInQue;                              //и получить из неё количество принятых байтов
        if(btr)                                     //если действительно есть байты для чтения
        {
         ReadFile(COMport, bufrd, btr, &temp, &overlapped);     //прочитать байты из порта в буфер программы
         counter+=btr;                                          //увеличиваем счётчик байтов
         Synchronize(Printing);                             //вызываем функцию для вывода данных на экран и в файл
        }
       }
    }
  }
 CloseHandle(overlapped.hEvent);        //перед выходом из потока закрыть объект-событие
}
 
//---------------------------------------------------------------------------
 
//выводим принятые байты на экран и в файл (если включено)
void __fastcall ReadThread::Printing()
{ AnsiString LL ;
 
 Form3->Memo1->Lines->Add(String().sprintf(L"First 16 bytes: " "%.2X %.2X %.2X %.2X %.2X %.2X %.2X %.2X ",
bufrd[0],bufrd[1],bufrd[2],bufrd[3],bufrd[4],bufrd[5],bufrd[6],bufrd[7], bufrd[8]));
    //выводим принятую строку в Memo
    LL = IntToHex((BYTE)bufrd[6],2)+" ";
    Form3->Memo2->Lines->Add(LL );
    memset(bufrd, 0, BUFSIZE);          //очистить буфер (чтобы данные не накладывались друг на друга)
return;
}
//-----------------------------------------------------------------------------
 
//=============================================================================
//............................. элементы формы ................................
//=============================================================================
 
//---------------------------------------------------------------------------
 
//---------------------------------------------------------------------------
__fastcall TForm3::TForm3(TComponent* Owner)
    : TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm3::SpeedButton1Click(TObject *Sender)
{
Form3 -> SpeedButton1->Down;
 Form3 -> SpeedButton1 -> Caption = "Опять начать";
   COMOpen();                   //если кнопка нажата - открыть порт
      Form3->Button1->Caption = "Приостановить" ;
      counter = 0;  //сбрасываем счётчик байтов
 
  }
 
 
//---------------------------------------------------------------------------
void __fastcall TForm3::FormClose(TObject *Sender, TCloseAction &Action)
{
if(reader)reader->Terminate();  //завершить поток чтения из порта, проверка if(reader) обязательна, иначе возникают ошибки
  //завершить поток записи в порт, проверка if(writer) обязательна, иначе возникают ошибки
 if(COMport)CloseHandle(COMport);       //закрыть порт
 if(handle)close(handle);               //закрыть файл, в который велась запись принимаемых данных
}
//---------------------------------------------------------------------------
    //=============================================================================
//........................... реализации функций ..............................
//=============================================================================
 
//---------------------------------------------------------------------------
 
//функция открытия и инициализации порта
void COMOpen()
{
 AnsiString portname;        //имя порта (например, "COM1", "COM2" и т.д.)
 DCB dcb;                //структура для общей инициализации порта DCB
 COMMTIMEOUTS timeouts;  //структура для установки таймаутов
 
 portname = Form3->ComboBox1->Text.c_str(); //получить имя выбранного порта
 
 //открыть порт, для асинхронных операций обязательно нужно указать флаг FILE_FLAG_OVERLAPPED
 COMport = CreateFile(portname.c_str(),GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
 //здесь:
 // - portname.c_str() - имя порта в качестве имени файла, c_str() преобразует строку типа String в строку в виде массива типа char, иначе функция не примет
 // - GENERIC_READ | GENERIC_WRITE - доступ к порту на чтение/записть
 // - 0 - порт не может быть общедоступным (shared)
 // - NULL - дескриптор порта не наследуется, используется дескриптор безопасности по умолчанию
 // - OPEN_EXISTING - порт должен открываться как уже существующий файл
 // - FILE_FLAG_OVERLAPPED - этот флаг указывает на использование асинхронных операций
 // - NULL - указатель на файл шаблона не используется при работе с портами
 
 if(COMport == INVALID_HANDLE_VALUE)            //если ошибка открытия порта
  {
   Form3->SpeedButton1->Down = false;           //отжать кнопку
   ShowMessage("Не удалось открыть порт");       //вывести сообщение в строке состояния
   return;
  }
 
 //инициализация порта
 
 dcb.DCBlength = sizeof(DCB);   //в первое поле структуры DCB необходимо занести её длину, она будет использоваться функциями настройки порта для контроля корректности структуры
 
 //считать структуру DCB из порта
 if(!GetCommState(COMport, &dcb))   //если не удалось - закрыть порт и вывести сообщение об ошибке в строке состояния
  {
   COMClose();
 ShowMessage("Не удалось считать DCB");
   return;
  }
 
 //инициализация структуры DCB
 dcb.BaudRate = StrToInt(Form3->ComboBox2->Text);       //задаём скорость передачи 115200 бод
 dcb.fBinary = TRUE;                                    //включаем двоичный режим обмена
 dcb.fOutxCtsFlow = FALSE;                              //выключаем режим слежения за сигналом CTS
 dcb.fOutxDsrFlow = FALSE;                              //выключаем режим слежения за сигналом DSR
 dcb.fDtrControl = DTR_CONTROL_DISABLE;                 //отключаем использование линии DTR
 dcb.fDsrSensitivity = FALSE;                           //отключаем восприимчивость драйвера к состоянию линии DSR
 dcb.fNull = FALSE;                                     //разрешить приём нулевых байтов
 dcb.fRtsControl = RTS_CONTROL_DISABLE;                 //отключаем использование линии RTS
 dcb.fAbortOnError = FALSE;                             //отключаем остановку всех операций чтения/записи при ошибке
 dcb.ByteSize = 8;                                      //задаём 8 бит в байте
 dcb.Parity = 0;                                        //отключаем проверку чётности
 dcb.StopBits = 0;                                      //задаём один стоп-бит
 
 //загрузить структуру DCB в порт
 if(!SetCommState(COMport, &dcb))   //если не удалось - закрыть порт и вывести сообщение об ошибке в строке состояния
  {
   COMClose();
   ShowMessage("Не удалось установить DCB");
   return;
  }
 
 //установить таймауты
 timeouts.ReadIntervalTimeout = 1;      //таймаут между двумя символами
 timeouts.ReadTotalTimeoutMultiplier = 10;  //общий таймаут операции чтения
 timeouts.ReadTotalTimeoutConstant = 100;         //константа для общего таймаута операции чтения
 timeouts.WriteTotalTimeoutMultiplier = 0;      //общий таймаут операции записи
 timeouts.WriteTotalTimeoutConstant = 0;        //константа для общего таймаута операции записи
 
 //записать структуру таймаутов в порт
 if(!SetCommTimeouts(COMport, &timeouts))   //если не удалось - закрыть порт и вывести сообщение об ошибке в строке состояния
  {
   COMClose();
   ShowMessage("Не удалось установить тайм-ауты");
   return;
  }
 
 //установить размеры очередей приёма и передачи
 SetupComm(COMport,2000,2000);
 
 //создать или открыть существующий файл для записи принимаемых данных
// handle = open("test.txt", O_CREAT | O_APPEND | O_BINARY | O_WRONLY, S_IREAD | S_IWRITE);
 
 if(handle==-1)     //если произошла ошибка открытия файла
  {
   ShowMessage("Ошибка открытия файла"); //вывести сообщение об этом в командной строке
  }
 else { ShowMessage( "Файл открыт успешно");
 } //иначе вывести в строке состояния сообщение об успешном открытии файла
 
 PurgeComm(COMport, PURGE_RXCLEAR); //очистить принимающий буфер порта
 
 reader = new ReadThread(false);    //создать и запустить поток чтения байтов
 reader->FreeOnTerminate = true;        //установить это свойство потока, чтобы он автоматически уничтожался после завершения
 
 
}
 
//---------------------------------------------------------------------------
 
//функция закрытия порта
void COMClose()
{
 if(reader)reader->Terminate();         //если поток чтения работает, завершить его; проверка if(reader) обязательна, иначе возникают ошибки
 CloseHandle(COMport);                  //закрыть порт
 COMport=0;             //обнулить переменную для дескриптора порта
 close(handle);             //закрыть файл для записи принимаемых данных
 handle=0;              //обнулить переменную для дескриптора файла
}
 
//---------------------------------------------------------------------------
 
void __fastcall TForm3::Button2Click(TObject *Sender)
{
reader->Suspend();
}
//---------------------------------------------------------------------------
__________________
Помощь в написании контрольных, курсовых и дипломных работ здесь
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
06.04.2016, 16:45
Ответы с готовыми решениями:

Потеря кодировки при выводе модального окна
Подскажи плз., куда искра уходит. Ситуация следующая: 1. Броузер - Хром 2. Открываю модальное...

При выводе декодированных байтов выводится ошибка
Всем привет! При написании парсера столкнулся с такой проблемой from urllib.request import...

ограничение длины при выводе MEMO-поля
Здравствуйте, ВСЕ, возникла проблема при выводе MEMO-поля большого поля. Вывожу поле таким...

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

4
0 / 0 / 2
Регистрация: 28.10.2015
Сообщений: 36
06.04.2016, 16:51  [ТС] 2
Вот как приходят байты. Вот схема поиска температуры :
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
 AnsiString GG = "";
  int i;
    Form3->Memo1->Lines->Add(String().sprintf(L"First 16 bytes: " "%.2X %.2X %.2X %.2X %.2X %.2X %.2X %.2X %.2X",
    bufrd[0],bufrd[1],bufrd[2],bufrd[3],bufrd[4],bufrd[5],bufrd[6],bufrd[7], bufrd[8], bufrd[9]));
for (i = 0; i < 12; i++) {
if (IntToHex((BYTE)bufrd[i],2)= "14")
 {
      if (IntToHex((BYTE)bufrd[i+1],2)= "FF")
      {
       GG += " "+IntToHex((BYTE)bufrd[i+2],2);
    Form3->Memo1->Lines->Add(GG);
}
}
}
Миниатюры
Потеря байтов при выводе в Memo (потоки)  
0
+1
342 / 175 / 53
Регистрация: 24.08.2010
Сообщений: 1,028
09.04.2016, 07:55 3
Цитата Сообщение от popal Посмотреть сообщение
вот пачка:FF 00 00 FF 14 FF 2C FF 2E. На самом деле начинаться пачка может с любого байта
Я думаю, что нужно здесь думать как определить начало.
Получается же, что прибор тебе выдаёт эти строки сплошным потоком?
0
0 / 0 / 2
Регистрация: 28.10.2015
Сообщений: 36
11.04.2016, 12:28  [ТС] 4
+1, получается да,начало не определено . Я не знала как написать так,чтобы например "FF 00 00" считалось началом строки и она только с нее и выводилась, но мне же только температура нужна, так что я делала так: в строке ищется сначала байт ,который точно не изменяется - bufrd[i] , и если он найден,то bufrd[i+2] - будет нашей температурой.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
 AnsiString Temp ;
AnsiString L1 ;
//AnsiString G1 ;
int i;
 Form3->Memo1->Lines->Add(String().sprintf(L"First 16 bytes: " "%.2X %.2X %.2X %.2X %.2X %.2X %.2X %.2X ",
bufrd[0],bufrd[1],bufrd[2],bufrd[3],bufrd[4],bufrd[5],bufrd[6],bufrd[7], bufrd[8]));
    for (i = 0; i < 12; i++) {
        L1= IntToHex((BYTE)bufrd[i],2);
        if (L1==14) {
            Temp=IntToHex((BYTE)bufrd[i+2],2);
            Form3->Memo2->Lines->Add(Temp);
        }
    }
    memset(bufrd, 0, BUFSIZE);          //очистить буфер (чтобы данные не накладывались друг на друга)
return;
Добавлено через 3 минуты
+1, только вот прога виснет после того 3 циклов. То есть у меня данные с обновлением на комп приходят там 20 раз в секунду , вот прога снимет их 3 раза подряд (там как раз окно мемо заканчивается на 3 строчках) и больше не хочет. Может подскажете,в чем дело?
0
0 / 0 / 0
Регистрация: 09.12.2017
Сообщений: 1
09.12.2017, 11:27 5
Можно попробовать дожидаться прихода всей пачки из 9 байт, и только потом вычитывать из буфера. Тогда не будет происходить потеря байт.

C++
1
2
3
4
5
6
7
btr = comstat.cbInQue;                              //и получить из неё количество принятых байтов
        if(btr==9)                                     //если действительно есть байты для чтения
        {
         ReadFile(COMport, bufrd, btr, &temp, &overlapped);     //прочитать байты из порта в буфер программы
         counter+=btr;                                          //увеличиваем счётчик байтов
         Synchronize(Printing);                             //вызываем функцию для вывода данных на экран и в файл
        }
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
09.12.2017, 11:27

Почему не отображается 0 перед запятой в real при выводе в memo?
собственно сабж. исходник: procedure TForm1.Button1Click(Sender: TObject); var...

При выводе текста в Memo добавляется пустая строка (без пробелов, просто курсор стоит)
вот код как я пытался убрать этот курсор: procedure FullShowText(l:TLabel); var s:string; begin...

Потеря пути в выводе команды
Набросал для себя небольшое приложение вроде линуксового which (код ниже), но есть один странный...

Ошибка в выводе данных в Memo
Всем привет! Не могу разобраться, где криво накодил... Тема избитая - совершенные числа. Само...


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

Или воспользуйтесь поиском по форуму:
5
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2021, vBulletin Solutions, Inc.