Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Для новичков > Принять данные от машины по k-line


Автор: mr_smit 12.10.2011, 08:28
Здравствуйте. Давно я не программировал на Delphi. А тут задался целью сделать для своей машины (ВАЗ 11183) считыватель ошибок на микроконтроллере. Чтобы разобраться с протоколом, хочу для начала из своего приложения на ПК посмотреть/почитать данные. Диагностическая линия (k-line) представляет из себя "обычный ком порт" только с измененными логическими уровнями. 0 вольт - это логический 0, +12 вольт - это логическая единица. У ком порта 0 это минус 12 вольт. Собственно все переходники для машины и представляют собой просто согласователи этих самых уровней.
Скачал бесплатную программу Diagnostic Tools. Подключился к машине. Всё работает. Всё показывает. Взял снифер ком порта, посмотрел что шлет программа. Скачал описание протокола обмена. Чуда не произошло, всё строго по пунктам smile

Не буду сильно вдаваться в подробности протокола. Собственно что меня интересует:

1. Чтобы начать диагностику, нам надо отправить:

Запрос startCommunication:
  81 10  F1 81 03
Ответ:
  83 F1 10 C1 6B 8F 3F

В ответе C1  означяет что ЭБУ готов с нами работать.

Поставил компонент AsyncFree104 для работы с com портом:
Код

var
  startCommunication: array [0..4] of byte = ($81, $10, $f1, $81, $03);

...

procedure TForm1.Button1Click(Sender: TObject);
begin
  AfComPort1.Open;
  AfComPort1.WriteData(startCommunication, sizeof(startCommunication));
end;


Как мне прочитать ответ? И как оттуда вытащить C1 ?

2. Сдернул клемму. Прочитал ошибки свои. Для определения значений данного параметра используется десятичная (BCD) кодировка.

Запрос ошибок readDTCByStatus:
  84 10 F1 18 00 00 00 9D
Ответ:
  88 F1 10 58 02 04 43 E0 14 26 E0 24
  
P0443  -  всё верно, 2 ошибки появилось.
P1426

Первые 3 байта нас не интересуют. Нам интересно: 58 - положительный ответ, 02 - число ошибок, дальше ошибки разделенные E0. Последняя цифра во всех запросах/ответах - контрольная сумма (2 младших разряда).

Как вытащить ошибки из этого ответа?

У компонента есть:
Код

AfComPort1.ReadData (var Buf; Size: Integer);

Как принимать в этот Buf ? Если длинна его меняется. И как разобрать данные?

Автор: bems 12.10.2011, 08:34
1. В чем вопрос-то? Как вытащить четвертый байт из буффера?
2. Выделять с запасом

Автор: mr_smit 12.10.2011, 08:56
Пока писал, сам сообразил. Вроде так:

Код

procedure TForm1.Button1Click(Sender: TObject);
begin
AfComPort1.Open;
AfComPort1.WriteData(startCommunication, sizeof(startCommunication));
AfComPort1.ReadData(ReadBuffer, Length(ReadBuffer));
if ReadBuffer[3] = $C1 then
  begin
  Label1.Caption:='ЭБУ на связи';
  end;
end;

Так?

Автор: bems 12.10.2011, 09:04
зависит от того что такое ReadBuffer, но похоже, да

Автор: mr_smit 12.10.2011, 09:05
Цитата(bems @ 12.10.2011,  09:04)
зависит от того что такое ReadBuffer, но похоже, да

Да, забыл написать
Код

ReadBuffer: array of byte;


Если так, то тогда ещё вопрос:

BCD кодировка, как с ней работать? Как мне, например, в Memo отобразить ошибки?

Автор: bems 12.10.2011, 09:05
ну и там же наверное чтонить и возвращается из WriteData и ReadData

Автор: mr_smit 12.10.2011, 09:32
Хочу прочитать ошибки из тестового массива. 
Код

TestArray: array[0..11] of byte = ($88,$f1,$10,$58,$02,$04,$43,$E0,$14,$26,$E0,$24);
...
procedure TForm1.Button2Click(Sender: TObject);
var i:integer;
      j:integer;
begin
j:=5;
for i:=0 to TestArray[4]-1 do     // 5-й байт - число ошибок
  begin
  Memo1.Lines.Add('P'+IntToStr(TestArray[j])+IntToStr(TestArray[j+1]));
  j:=j+3;
  end;
end;


В мемо получается:
P467
P2038

А должно:
P0443
P1426

Как перевести из BCD формата в String?

Автор: AndreyIQ 12.10.2011, 09:49
Код

Memo1.Lines.Add('P'+IntToHex(TestArray[j],2)+IntToHex(TestArray[j+1],2));

Автор: mr_smit 12.10.2011, 10:15
Цитата(AndreyIQ @ 12.10.2011,  09:49)
Код

Memo1.Lines.Add('P'+IntToHex(TestArray[j],2)+IntToHex(TestArray[j+1],2));

Оооооо....!!!! Спасибо! Работает.

Кстати. Вот запрос параметров:
  82 10 F1 21 01 A5
ЭБУ моей машины отвечает:
 80 F1 10 26 61 01 3B 90 41 04   
 00 00 00 00 47 80 00 00 00 52 52 80 18 00 8E 00   
 5C 00 00 00 00 00 00 00 00 00 FF FF DD A4 47 02

 CE

61 - Положительный ответ readDataByLocalIdentifier
01 - afterSalesServiceRecordLocalIdentifier (что то там....)
....
11-й байт - Температура охлаждающей жидкости
....


Формула для расчета: N=E-40 [°C]
  E - передаваемое значение
  N - физическая величина
У меня это значение 47. Берем windows калькулятор. Переводим 47 hex в dec. Получаем 71. Дальше 71-40=31°C. Соглашусь. На момент снятия данных машина часа полтора простояла на улице. До конца не остыла.

Как бы мне теперь на Delphi так конвертнуть?

Автор: AndreyIQ 12.10.2011, 10:26
Цитата(mr_smit @ 12.10.2011,  10:15)
47 hex в dec

Код

StrToInt('$' + IntToStr(47))

Автор: mr_smit 12.10.2011, 11:48
Чего то у меня в ошибку вываливается на строке:
Код

if ReadBuffer[3] = $C1 then


Может где то длинну массиву назначать?

Автор: AndreyIQ 12.10.2011, 11:58
Цитата(mr_smit @ 12.10.2011,  11:48)
Может где то длинну массиву назначать?

SetLength.

Автор: mr_smit 12.10.2011, 11:58
Кажется понял, ReadBuffer у меня сейчас пустой, а я пытаюсь 4-й элемент массива прочитать.

А где её задавать? Сразу после чтения?
Код

SetLength(ReadBuffer, Length(ReadBuffer));


Добавлено @ 12:07
Код

AfComPort1.ReadData(ReadBuffer, sizeof(ReadBuffer));
SetLength(ReadBuffer, Length(ReadBuffer));
try
if ReadBuffer[3] = $C1 then
  begin
  Label1.Caption:='ЭБУ на связи';
  end;
except
  Label1.Caption:='нет ответа от ЭБУ';
end;


Так?

И нужно ли буфер обнулять перед каждым вызовом? Или он автоматически каждый раз с нулевого значения записывается?

Автор: northener 12.10.2011, 14:00
Цитата(mr_smit @  12.10.2011,  11:58 Найти цитируемый пост)
AfComPort1.ReadData(ReadBuffer, sizeof(ReadBuffer));
SetLength(ReadBuffer, Length(ReadBuffer));

1. Размер массиву ReadBuffer задавать ДО передачи его в качестве параметра функции ReadData.
2. Размер массива это Length, а SizeOf это размер переменной, которая хранит адрес массива в памяти.
3. Первый параметр в функции ReadData должен быть передан как ReadBuffer[0].

Автор: mr_smit 12.10.2011, 15:34
Чего то у меня не работает код smile

Дело в том что, как я понимаю, поскольку по K-Line обмен идет по одному проводу, то в момент передачи, принимать ничего не надо! Закончили передавать - начинаем линию слушать. Вот как этот момент реализовать?

Добавлено @ 15:39
Я когда сниффером обмен смотрю:
Запрос startCommunication:
  81 10  F1 81 03
Ответ:
  81 10  F1 81 03 83 F1 10 C1 6B 8F 3F

Реальный ответ это только 83 F1 10 C1 6B 8F 3F. А в начале идет запрос, просто он автоматом попадает на вход. Провод то связи один.  Он и на передачу работает и на прием.

Автор: northener 12.10.2011, 16:30
Цитата(mr_smit @  12.10.2011,  15:34 Найти цитируемый пост)
поскольку по K-Line обмен идет по одному проводу, то в момент передачи, принимать ничего не надо! Закончили передавать - начинаем линию слушать. Вот как этот момент реализовать?

Слушать постоянно. Отделять ответ от своего же "эха" потом.

Автор: northener 12.10.2011, 23:48
Цитата(mr_smit @  12.10.2011,  15:34 Найти цитируемый пост)
Чего то у меня не работает код smile

Какой именно код не работает?

1. Вы смогли самостоятельно разработать или где-то купить преобразователь СОМ-"однопроводная линия"? Это не так сложно теоретически, но я сомневаюсь, что вы его хоть как-то получили. А без него вы ничего не сможете сделать.
2. Вы изучили полностью тот компонент, который вы решили использовать? Наверняка нет.
  Все эти компоненты созданы по одному лекалу. И у них, у всех есть событие типа OnRxChar. Вот в нём, в этом событии и надо вызывать функцию ReadData. Кстати, заметьте. Это наверняка именно функция, а не процедура!
3. Умение пользоваться "сниффером" и т.п. очень  полезное умение. Но оно мало помогает при недостаточном уровне знаний.

Автор: mr_smit 13.10.2011, 07:44
Я сам спаял преобразователь USB <-> K-Line. Там ничего сложного. Он работает! Я несколько программ диагностики уже использовал. Все видят контроллер. Все параметры в режиме реального времени. С этим нет проблем.
http://radikal.ru/F/i060.radikal.ru/1109/48/d2378ce3b7d4.jpg.html
Цитата(northener @ 12.10.2011,  23:48)
у них, у всех есть событие типа OnRxChar

Да, я уже тоже про это подумал. Просто с наскока разобраться не получилось. Буду копать глубже теперь. Сниффер классная вещь когда под рукой описание протокола. Наглядно всё видишь.
Код

AfComPort1.WriteData(startCommunication, sizeof(startCommunication));
AfComPort1.ReadData(ReadBuffer, Length(ReadBuffer));
if ReadBuffer[3] = $C1 then
  begin

  end;

Теперь я понимаю что это точно работать не будет. Надо принимать только после окончания передачи.

P.S. ReadData - это процедура, а не функция. Справку на компонент прилагаю.

Автор: mr_smit 13.10.2011, 08:09
Код

property OnOutBufFree: TNotifyEvent;
//Occurs when all the data in output buffer was sent.

Код

procedure PurgeRX;
//Clears device driver's input buffer

Код

property OnDataRecived: TAfCPTDataReceivedEvent;
TAfCPTDataReceivedEvent = procedure(Sender: TObject; Count: Integer) of object;
//Occurs when a data is received by communication port. Count is the actual number of bytes avaiable to read. 
//You should read the whole number of bytes given in Count parameter. 


Стало быть как только выходной буффер освободился, т.е. все данные переданы - очищаем входной буффер, и читаем из него данные по событию DataRecived:
Код

procedure TForm1.AfComPort1OutBufFree(Sender: TObject);
begin
AfComPort1.PurgeRX;
end;

procedure TForm1.AfComPort1DataRecived(Sender: TObject; Count: Integer);
begin
AfComPort1.ReadData(ReadBuffer[0], Count);
end;


Правильно?

Автор: mr_smit 13.10.2011, 09:05
Итак, нам надо отправить запрос startCommunication. При положительном ответе на него отправить startDiagnosticSession. При положительном ответе на него периодически отправлять testerPresent чтобы ЭБУ видел что тестер до сих пор подключен. Попробовал пока вот так это изобразить:
Код

...
Timer1: TTimer;
...
type Mode = (TesterOnline, ReadData, ReadError, Connect, Disconnect);

var
  Form1: TForm1;
  startCommunication:         array[0..4] of byte = ($81,$10,$f1,$81,$03);
  startDiagnosticSession:     array[0..6] of byte = ($83,$10,$f1,$10,$81,$0A,$1F);
  testerPresent:              array[0..5] of byte = ($82,$10,$f1,$3E,$01,$C2);
  ...
  ReadBuffer: array[0..99] of byte;
  TesterMode: Mode;
...

procedure TForm1.Button1Click(Sender: TObject);
begin
  AfComPort1.ComNumber:=AfPortComboBox1.ComPort.ComNumber;
  AfComPort1.Open;
  StatusBar1.Panels[0].Text:=AfComPort1.SettingsStr;
  TesterMode:= Connect;
  AfComPort1.PurgeTX; // очистили выходной буффер
  AfComPort1.WriteData(startCommunication, length(startCommunication));
  Timer1.Enabled:=true;
end;

procedure TForm1.AfComPort1DataRecived(Sender: TObject; Count: Integer);
begin
AfComPort1.ReadData(ReadBuffer[0], Count);
end;

procedure TForm1.AfComPort1OutBufFree(Sender: TObject);
begin
AfComPort1.PurgeRX; // как закончили передавать - очищаем входной буффер.
end;

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  if TesterMode = Connect then
  begin
    if ReadBuffer[3] = $C1 then   // положительный ответ на startCommunication
    begin
      AfComPort1.PurgeTX; // очистили выходной буффер
      AfComPort1.WriteData(startDiagnosticSession, length(startDiagnosticSession));
    end
    else if ReadBuffer[3] = $50 then   // положительный ответ на startDiagnosticSession
    begin
      TesterMode:= TesterOnline;
      StatusBar1.Panels[1].Text:='ЭБУ на связи';
    end;
  end

  else if TesterMode = TesterOnline then
  begin
    AfComPort1.PurgeTX; // очистили выходной буффер
    AfComPort1.WriteData(testerPresent, length(testerPresent));
    if ReadBuffer[3] = $7E then    // ответ ЭБУ на testerPresent
    begin
      StatusBar1.Panels[1].Text:='ЭБУ на связи';
    end
    else begin
      StatusBar1.Panels[1].Text:='Связь потеряна';
    end;
  end

  else if TesterMode = Disconnect then
  begin
    AfComPort1.WriteData(stopDiagnosticSession, length(stopDiagnosticSession));
    AfComPort1.WriteData(stopCommunication, length(stopCommunication));
    AfComPort1.Close;
  end
end;


Что скажете?

Автор: northener 13.10.2011, 11:25
Цитата(mr_smit @  13.10.2011,  08:09 Найти цитируемый пост)
Стало быть как только выходной буффер освободился, т.е. все данные переданы - очищаем входной буффер, и читаем из него данные по событию DataRecived:
...

Правильно?

Теоретически правильно. Но на практике почти всегда неправильно.
Ибо большинство таких компонент ххСОМPort игнорируют аппаратный FIFO СОМ-порта. А событие "Выходной буфер пуст" для них означает только то, что пуст выходной буфер драйвера СОМ-порта. Т.о. данное событие будет обработано гораздо раньше, чем СОМ-порт выдаст на линию всю предназначенную железяке посылку.

Советую вам очищать входной буфер непосредственно перед посылкой команды железяке. И постоянно читать в событии
Цитата(mr_smit @  13.10.2011,  08:09 Найти цитируемый пост)
property OnDataRecived: TAfCPTDataReceivedEvent;
TAfCPTDataReceivedEvent = procedure(Sender: TObject; Count: Integer) of object;

учитывая параметр Count.
Принятое "эхо" вы сможете легко вычленить из приемного буфера. Ведь вы знаете, что вы посылали железяке.

Автор: mr_smit 13.10.2011, 11:47
Цитата(northener @ 13.10.2011,  11:25)
И постоянно читать в событии OnDataRecived

А как???

Код

procedure TForm1.AfComPort1DataRecived(Sender: TObject; Count: Integer);
begin
AfComPort1.ReadData(ReadBuffer[0], Count);
end;

Если так, то постоянно перезаписываться будет [0] элемент. Как ReadBuffer получить заполненный моим запросом + ответ? Я чего то не пойму никак.

Автор: northener 13.10.2011, 12:56
Цитата(mr_smit @  13.10.2011,  11:47 Найти цитируемый пост)
Если так, то постоянно перезаписываться будет [0] элемент. 


Цитата(northener @  13.10.2011,  11:25 Найти цитируемый пост)
учитывая параметр Count.

Т.е. заведите переменную CurrentPos. Перед посылкой присваивайте ей 0. А затем
Код

  AfComPort1.ReadData(ReadBuffer[CurrentPos], Count);
  Inc(CurrentPos,Count);

Автор: mr_smit 13.10.2011, 15:47
Код

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  if TesterMode = Connect then
  begin
  showmessage(inttostr(ReadBuffer[3] ));
    if ReadBuffer[3] = $C1 then   // положительный ответ на startCommunication
    begin
      AfComPort1.PurgeTX; // очистили выходной буффер
      AfComPort1.WriteData(startDiagnosticSession, length(startDiagnosticSession));
    end
...


showmessage мне возвращает ноль  smile 

Обмен смотрю сниффером. ЭБУ отвечает. Но ответ распознать не могу  smile 

P.S. northener, сейчас попробую как вы говорите

Автор: northener 14.10.2011, 00:20
Цитата(mr_smit @  13.10.2011,  15:47 Найти цитируемый пост)
P.S. northener, сейчас попробую как вы говорите

Можете обращаться ко мне в личку.

Автор: mr_smit 14.10.2011, 09:01
Цитата(northener @ 13.10.2011,  12:56)
Код

  AfComPort1.ReadData(ReadBuffer[CurrentPos], Count);
  Inc(CurrentPos,Count);

Из справки:
Код

procedure ReadData(var Buf; Size: Integer);
//Reads the specified number of bytes from input buffer. If there aren't enough data to read, an exception is raised

Перевод: Читает  указанное число байт из  входного буфера. Если не достаточно данных для чтения, вызывается исключение

Код

function InBufUsed: Integer;
//Returns the number of bytes in device driver's input buffer

Количество байт во входном буфере

Получается вот так что ли?
Код

  AfComPort1.ReadData(ReadBuffer[CurrentPos], AfComPort1.InBufUsed);
  Inc(CurrentPos, AfComPort1.InBufUsed);

Автор: northener 14.10.2011, 11:37
Цитата(mr_smit @  14.10.2011,  09:01 Найти цитируемый пост)
Получается вот так что ли?

Может быть так. Может быть нет. Надо пробовать и смотреть что получается. 
Поймите меня правильно. Я не знаком с именно этим компонентом xxCOMport.
Как правило "ReadData" в подобных компонентах - функция возвращающая количество байт реально вычитанных из приемного буфера.

Автор: mr_smit 14.10.2011, 13:43
Я взял этот компонент потому что у него можно задать произвольную скорость обмена. Мне нужна 10400. Может подскажите знакомый вам компонент. Может что попроще.

Автор: northener 14.10.2011, 21:44
Цитата(mr_smit @  14.10.2011,  13:43 Найти цитируемый пост)
Я взял этот компонент потому что у него можно задать произвольную скорость обмена. Мне нужна 10400. 

Вообще-то произвольную скорость должен уметь ставить любой компонент. Особенно если он с исходниками.
Посоветовать ничего не могу, потому что никаким никогда не пользовался. Только смотрел. Кроме библиотеки AsyncPro, но это слишком тяжелая вещь.

Автор: northener 15.10.2011, 00:02
Ещё раз.

Цитата(northener @  14.10.2011,  11:37 Найти цитируемый пост)
Может быть так. Может быть нет. Надо пробовать и смотреть что получается.

Т.е. 
1. Создаём таймер. Его период выбираем исходя из скорости СОМ-порта, на которой работает железяка и из максимального количества байт посылки/команды и ответа. (Один байт - это как минимум 10 бит, как максимум 12 бит. Зависит от наличия/отсутствия бита чётности и от длины стоп-бита(1,1.5,2). Плюс запас 50-500 ms из-за того, что Винда не есть система реального времени.
2. Перед посылкой запроса/команды к железяке очищаем приемный/передающий буфер СОМ-порта методами компонента.
3. Сбрасываем в ноль переменную CurrentPos.
4. Посылаем запрос/команду железяке. Запускаем таймер. Читаем в событии OnDataRecived всё в буфер ReadBuffer по адресу ReadBuffer[CurrentPos].
5. По срабатыванию таймера смотрим, чему равен CurrentPos и что мы уже получили.  После анализа принятого возвращаться к пункту 2.
5-бис Смотреть "чему равен CurrentPos и что мы уже получили" можно уже в событии OnDataRecived после выполнения процедуры ReadData. И если всё уже принято, то сбрасывать/дизейблить таймер. И после анализа принятого переходить к пункту 2.

Автор: mr_smit 18.10.2011, 17:03
Вобщем вот так всё заработало:
Код

...

else if TesterMode = ReadData then
  begin
    {
      НЕТ ПРОВЕРКИ КОНТРОЛЬНОЙ СУММЫ!!!
    }
    Timer1.Interval:=330;
    AfComPort1.PurgeTX; // очистили выходной буффер
    AfComPort1.PurgeRX;
    CurrentPos:=0;
    AfComPort1.WriteData(readDataByLocalIdentifier, length(readDataByLocalIdentifier));

    Label6.Caption:=IntToStr(40*(StrToInt(IntToStr(ReadBuffer[23]))))+' об/мин';
    Label7.Caption:=IntToStr(StrToInt(IntToStr(ReadBuffer[25])))+' шаг.';
    Label8.Caption:=IntToStr(StrToInt(IntToStr(ReadBuffer[20]))-40)+' град.';
    Label9.Caption:=floatToStrF(5.2+(StrToInt(IntToStr(ReadBuffer[30]))*0.05),ffGeneral,4,2)+' B';
    Label11.Caption:=IntToStr(StrToInt(IntToStr(ReadBuffer[22])))+' %';
    Button1.Enabled:=false;
    Button2.Enabled:=true;
    Button5.Enabled:=true;
  end

...

procedure TForm1.AfComPort1DataRecived(Sender: TObject; Count: Integer);
begin
  AfComPort1.ReadData(ReadBuffer[CurrentPos], Count);
  Inc(CurrentPos, Count);
end;


http://radikal.ru/F/s010.radikal.ru/i314/1110/bf/f821caa1623c.jpg.html

northener, спасибо

Автор: northener 18.10.2011, 23:53
Цитата(mr_smit @  18.10.2011,  17:03 Найти цитируемый пост)
northener, спасибо 

Не за что.

Автор: mr_smit 19.10.2011, 09:49
Единственное я не пойму почему запрос ошибок у меня не работает.

Код

...
procedure TForm1.Button5Click(Sender: TObject);
begin
  TesterMode:= ReadError;
end;

...

  else if TesterMode = ReadError then
  begin
    AfComPort1.PurgeTX; // очистили выходной буффер
    AfComPort1.PurgeRX;
    CurrentPos:=0;
    AfComPort1.WriteData(readDTCByStatus, Length(readDTCByStatus));
    Memo1.Clear;

    for i:=0 to ReadBuffer[12]-1 do  // количество ошибок
    begin
      Memo1.Lines.Add('P'+IntToHex(ReadBuffer[j],2)+IntToHex(ReadBuffer[j+1],2));
      j:=j+3;
    end;
    j:=13;
    TesterMode:=ReadData;
  end;
...

Сделал вывод массива на форму. Почему то запрос/ответ на чтение ошибок не проходит. Т.е. после нажатия на кнопку "ошибки" массив не обновляется. И в нем хранятся данные ещё с предыдущего запроса параметров. Странно. Вроде делаю CurrentPos:=0;

http://radikal.ru/F/s017.radikal.ru/i431/1110/d9/36d27f8868bb.jpg.html

Автор: northener 19.10.2011, 10:45
Цитата(mr_smit @  19.10.2011,  09:49 Найти цитируемый пост)
Почему то запрос/ответ на чтение ошибок не проходит. Т.е. после нажатия на кнопку "ошибки" массив не обновляется. И в нем хранятся данные ещё с предыдущего запроса параметров. Странно. Вроде делаю CurrentPos:=0;

В приведенном куске кода есть обнуление CurrentPos. Есть посылка команды WriteData. А где чтение ответа?

Автор: mr_smit 19.10.2011, 20:36
Код

procedure TForm1.AfComPort1DataRecived(Sender: TObject; Count: Integer);
begin
  AfComPort1.ReadData(ReadBuffer[CurrentPos], Count);
  Inc(CurrentPos, Count);
end;

Автор: northener 19.10.2011, 23:29
Цитата(northener @  19.10.2011,  10:45 Найти цитируемый пост)
В приведенном куске кода есть обнуление CurrentPos. Есть посылка команды WriteData. А где чтение ответа? 


Цитата(mr_smit @  19.10.2011,  20:36 Найти цитируемый пост)
procedure TForm1.AfComPort1DataRecived(Sender: TObject; Count: Integer);
begin
  AfComPort1.ReadData(ReadBuffer[CurrentPos], Count);
  Inc(CurrentPos, Count);
end;


Так. Я тогда не понимаю, чему вы радовались в 
Цитата(mr_smit @  18.10.2011,  17:03 Найти цитируемый пост)
Вобщем вот так всё заработало:
?
И за что вы мне плюсик дали?

Смотрим ваш кусок кода:
Код

else if TesterMode = ReadError then
  begin
    AfComPort1.PurgeTX; // очистили выходной буффер
    AfComPort1.PurgeRX;
    CurrentPos:=0;
    AfComPort1.WriteData(readDTCByStatus, Length(readDTCByStatus)); [I][color=blue]<---Вот тут вы посылаете запрос железяке.[/color][/I]
    Memo1.Clear;
    for i:=0 to ReadBuffer[12]-1 do  // количество ошибок  [I][color=blue]<---А тут, в цикле, уже выводите данные из вашего приемного буфера в Мемо! И что вы надеятесь увидеть в данный момент в вашем приёмном буфере?  Да. После вызова метода компонента WriteData, компонент запустил свой механизм по передаче драйверу СОМ-порта данных для выдачи на линию. Плюс запустил в отдельном потоке функцию WaitCommEvent для получения события о том, что драйвер СОМ-порта что-то прочитал. И возможно даже драйвер уже успел что-то прочитать и сообщить об этом компоненту. Но ваша программа не сможет НИЧЕГО об этом узнать до выхода из той процедуры, кусок которой вы привели! Ибо пока вы не вышли из этой процедуры вашей программы, ваша программа не сможет обработать событие компонента ReadData[/color][/I]
    begin
      Memo1.Lines.Add('P'+IntToHex(ReadBuffer[j],2)+IntToHex(ReadBuffer[j+1],2));
      j:=j+3;
    end;
    j:=13;
    TesterMode:=ReadData;
  end;


Добавлено через 13 минут и 27 секунд
То ли лыжи не едут, то ли я ...
Привожу полностью тот мой комментарий к коду, который начинался словами "А тут, в цикле, вы выводите из вашего приемного..."
А тут, в цикле, уже выводите данные из вашего приемного буфера в Мемо! И что вы надеетесь увидеть в данный момент в вашем приёмном
 буфере?  Да. После вызова метода компонента WriteData, компонент запустил свой механизм по передаче драйверу СОМ-порта данных для
 выдачи на линию. Плюс запустил в отдельном потоке функцию WaitCommEvent для получения события о том, что драйвер СОМ-порта что-то
 прочитал. И возможно даже драйвер уже успел что-то прочитать и сообщить об этом компоненту. Но ваша программа не сможет
 НИЧЕГО об этом узнать до выхода из той процедуры, кусок которой вы привели! Ибо пока вы не вышли из этой процедуры вашей
 программы, ваша программа не сможет обработать событие компонента ReadData.

Автор: mr_smit 20.10.2011, 01:02
Плюс поставил за кусок кода:
Код

procedure TForm1.AfComPort1DataRecived(Sender: TObject; Count: Integer);
begin
  AfComPort1.ReadData(ReadBuffer[CurrentPos], Count);
  Inc(CurrentPos, Count);
end;


В принципе я думал  что просто не успевает массив заполнится данными. Но в режиме реального времени параметры у меня отображаются. Таймер настроен на 330 мс. Т.е. 3 раза в секунду считываю параметры.

А как тогда тут поступить со считыванием ошибок по нажатию кнопки? Добавить как то задержку? Или 2 раза запрашивать?

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

Автор: northener 20.10.2011, 22:36
Цитата(mr_smit @  20.10.2011,  01:02 Найти цитируемый пост)
Но в режиме реального времени параметры у меня отображаются.


Цитата(mr_smit @  20.10.2011,  01:02 Найти цитируемый пост)
А как тогда тут поступить со считыванием ошибок по нажатию кнопки?


Приведите код вашей процедуры OnTimer. Я подскажу как её изменить.

Тогда хоть я смогу (если смогу), хоть как-то отработать тот плюсик, который вы мне добавили. :(

Автор: mr_smit 21.10.2011, 08:05
Вот:

Автор: Korod 24.10.2011, 11:51
На СОМ-портах персоналки -12в - это лог.1, а +12в - это лог.0.

Автор: northener 24.10.2011, 23:32
Цитата(mr_smit @  21.10.2011,  08:05 Найти цитируемый пост)
Вот: 

Чтобы не захламлять форум, ответил в личку.

Автор: Darkblue 20.1.2012, 18:33
Уважаемые подскажите пожалуйста procedure TForm1.AfComPort1DataRecived ставится на рабочее поле,или просто прописывается в процедурах. Никак не могу научиться байт ловить ,помогите пожалуйста

Автор: bems 20.1.2012, 20:39

M
bems
Один топик — один вопрос!

Пожалуйста, ознакомьтесь с правилами форума.




Тема закрыта. Создайте по одной теме для каждого интересующего вас вопроса.

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)