Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Начинающим";
Текущий архив: 2009.09.20;
Скачать: [xml.tar.bz2];

Вниз

WriteBuffer - error - Access violation at addr... почему???   Найти похожие ветки 

 
Zheksonz   (2009-07-14 17:38) [0]

Всем привет)) Сергей М., персональный.
решил всё-таки общаться с портом без помощи строк. В сабже ошибка выдаваемая на записи в буфер. Что это может быть???

Код:
procedure TForm1.Button1Click(Sender: TObject);
const
CmdHZ: array[0..3] of byte = (01, 06, 00, 04);
var
CmdData: Word;
CmdCRC16: Word;
ms: TMemoryStream;
begin
// ComPort.Open;
CmdData := UpDown1.Position;
ms.WriteBuffer(CmdHZ, SizeOf(CmdHZ));
CmdData := Swap(CmdData);
ms.WriteBuffer(CmdData, SizeOf(CmdData));
CmdCRC16 := Swap(GetCRC16(ms.Memory, ms.Size));
ms.WriteBuffer(CmdCRC16, SizeOf(CmdCRC16));
ComPort.Write(ms.Memory^, ms.Size);
ComPort.Close;
end;


function TForm1.GetCRC16(P: PChar; Len: Word): Word;
var
iByte, i: Word;
B: Byte;
begin
{$R-}
Result := $FFFF;
for iByte := 0 to Len-1 do
  begin
   B := Byte(Pointer(LongInt(P)+iByte)^);
   Result := (Result and $FF00) + (B xor Lo(Result));
   for i := 1 to 8 do
     begin
      if ((Result and $0001) <> 0) then
        Result := (Result shr 1) xor $A001
      else Result := (Result shr 1);
     end;
  end;
{$R+}
end;


на всякий случай привожу и ф-цию вычисления контрольной суммы.


 
Игорь Шевченко ©   (2009-07-14 17:45) [1]


> Что это может быть???


Invalid user. Replace and strike any key when ready


 
Rouse_ ©   (2009-07-14 17:48) [2]

А ms создавать кто будет?


 
Palladin ©   (2009-07-14 17:50) [3]

Пушкин вестимо


 
Zheksonz   (2009-07-14 18:28) [4]


> Invalid user. Replace and strike any key when ready

бан отменили???

procedure TForm1.Button1Click(Sender: TObject);
const
CmdHZ: array[0..3] of byte = (01, 06, 00, 04);
var
CmdData: Word;
CmdCRC16: Word;
ms: TMemoryStream;
begin
ComPort.Open;
ms := TMemoryStream.Create;
CmdData := UpDown1.Position;
ms.WriteBuffer(CmdHZ, SizeOf(CmdHZ));
CmdData := Swap(CmdData);
ms.WriteBuffer(CmdData, SizeOf(CmdData));
CmdCRC16 := Swap(GetCRC16(ms.Memory, ms.Size));
ms.WriteBuffer(CmdCRC16, SizeOf(CmdCRC16));
ComPort.Write(ms.Memory^, ms.Size);
ms.Free;
ComPort.Close;
end;


сейчас код проходит, но устройство не воспринимает создаваемую команду... буду разбираться...


 
Zheksonz   (2009-07-14 21:40) [5]

странно... просматриваю в отладчике значение ms.Memory, оно не меняется вне зависимости от присвоений... всегда равно $14A058 может я неправильно пишу в буфер???


 
Loginov Dmitry ©   (2009-07-14 21:44) [6]


> странно... просматриваю в отладчике значение ms.Memory,
> оно не меняется вне зависимости от присвоений... всегда
> равно $14A058 может я неправильно пишу в буфер???


Оно само изменится когда ему будет надо!


 
Zheksonz   (2009-07-14 22:01) [7]


> Оно само изменится когда ему будет надо!

кому, ему???


 
Rouse_ ©   (2009-07-14 22:15) [8]


> просматриваю в отладчике значение ms.Memory, оно не меняется
> вне зависимости от присвоений... всегда равно $14A058

А зачем менять указатель на буффер?


 
Loginov Dmitry ©   (2009-07-14 22:23) [9]


> кому, ему???


значению ms.Memory


 
Sha ©   (2009-07-14 23:23) [10]

> Zheksonz   (14.07.09 17:38)
> решил всё-таки общаться с портом без помощи строк

Вот нафига тебя теперь в потоки занесло? Давай заюзай еще Мемо или файл.
Тебе ж в прошлой ветке было сказано, что достаточно packed record.

> на всякий случай привожу и ф-цию вычисления контрольной суммы

Судя по приведенной CRC у тебя используется Modbus протокол.
В нем при передаче CRC первым передается младший байт, а ты передаешь старший.


 
Zheksonz   (2009-07-14 23:28) [11]


> В нем при передаче CRC первым передается младший байт, а
> ты передаешь старший.

т.е. Swap не нужно делать???


> Вот нафига тебя теперь в потоки занесло? Давай заюзай еще
> Мемо или файл.Тебе ж в прошлой ветке было сказано, что достаточно
> packed record.


Сергей М. предложил этот вариант, я решил его попробовать...


 
Sha ©   (2009-07-14 23:31) [12]

> т.е. Swap не нужно делать???

Да, для CRC не надо


 
Zheksonz   (2009-07-14 23:52) [13]


> Sha ©   (14.07.09 23:23) [10]


const
CmdPref: array[0..3] of byte = (01, 06, 00, 04);
type
 CmdPack = packed record
   c_Pref: array[0..3] of byte;
   c_Data: array[0..1] of byte;
   c_crc16: array[0..1] of byte;
 end;


оно???


 
Sha ©   (2009-07-15 00:06) [14]


const
  CmdPref = $04000601;
type
  CmdPack = packed record
    Pref: integer;
    Data: word;
    crc16: word;
  end;
var
  cp: CmdPack;
begin
  cp.Pref:=CmdPref;
  cp.Data:=Swap(UpDown1.Position);
  cp.CRC16:=GetCRC16(cp, SizeOf(cp.Pref) + SizeOf(cp.Data));
 
  ComPort.Open;
  ComPort.Write(cp, SizeOf(cp));
  ComPort.Close;
end;


 
Zheksonz   (2009-07-15 00:10) [15]


> Sha ©   (15.07.09 00:06) [14]

красота... а я уже массивы подключил, для наполнения)))

а CRC16 Swap_нуть не нужно???


 
Zheksonz   (2009-07-15 00:17) [16]

всмысле Swap(GetCRC16(cp, SizeOf(cp.Pref) + SizeOf(cp.Data)));

и ещё, ф-ция GetCrc16 у меня принимает GetCRC16(P: PChar; Len: Word) а cp у нас имеет тип CmdPack

как проще привести их к одному типу???


 
Sha ©   (2009-07-15 00:18) [17]

> а CRC16 Swap_нуть не нужно???

Нет. В твоем процессоре целочисленные данные (например, типа word) хранятся в low-endian представлении (дословно: младшим концом вперед),
т.е. младший байт - в младшем адресе. А это как раз то, что тебе надо, если, конечно, у тебя используется протокол Modbus.


 
Zheksonz   (2009-07-15 00:21) [18]

да, протокол ModBus


 
Sha ©   (2009-07-15 00:22) [19]

> Zheksonz   (15.07.09 00:17) [16]
> как проще привести их к одному типу???

тогда надо так:
cp.CRC16:=GetCRC16(@cp, SizeOf(cp.Pref) + SizeOf(cp.Data));

ЗЫ. Вообще-то, GetCRC16 очень причудливо написана )


 
Германн ©   (2009-07-15 00:24) [20]


> Rouse_ ©   (14.07.09 22:15) [8]
>
>
> > просматриваю в отладчике значение ms.Memory, оно не меняется
> > вне зависимости от присвоений... всегда равно $14A058
>
> А зачем менять указатель на буффер?
>

А ты, Саш сначала попробуй объяснить автору что такое буфер, что такое указатель и что он (автор) видит в отладчике.
Даже твой богатый опыт на других форумах тебе не поможет. :)


 
Zheksonz   (2009-07-15 00:26) [21]

а то, что GetCRC16 считает контрольную сумму не от всего cp , а от cp.Pref и cp.Data не страшно???


 
Zheksonz   (2009-07-15 00:27) [22]


> А ты, Саш сначала попробуй объяснить автору что такое буфер,
>  что такое указатель и что он (автор) видит в отладчике.
>  Даже твой богатый опыт на других форумах тебе не поможет.
>  :)

0


 
Zheksonz   (2009-07-15 00:28) [23]


> а то, что GetCRC16 считает контрольную сумму не от всего
> cp , а от cp.Pref и cp.Data не страшно???

виноват... длина же указана...


 
Sha ©   (2009-07-15 00:29) [24]

> Zheksonz   (15.07.09 00:26) [21]
> от всего cp , а от cp.Pref и cp.Data

А разве там, кроме них, есть еще что-то?
Я не представляю, как можно считать по-другому.


 
Zheksonz   (2009-07-15 00:42) [25]


> Sha ©   (15.07.09 00:29) [24]


в отладчике, перед записью в порт:
cp = (67110401, 34835, 24005)

это и есть четыре байта префикса = 01 06 00 04
два байта передаваемого значения = 5000
и два байта контрольной суммы???


 
Sha ©   (2009-07-15 00:47) [26]

Проверить на калькуляторе?


 
Zheksonz   (2009-07-15 00:49) [27]

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


 
Sha ©   (2009-07-15 00:52) [28]

Думаю, 3 оператора присваивания выполнились верно.


 
Zheksonz   (2009-07-15 00:58) [29]

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


 
Sha ©   (2009-07-15 01:02) [30]

В калькуляторе переведи данные в hex и выпиши байты от младшего к старшему.
Почитай про представление целых в архитектуре I-32.


 
Zheksonz   (2009-07-15 01:07) [31]


> Sha ©   (15.07.09 01:02) [30]


Ок.

спасибо


 
Sha ©   (2009-07-15 07:19) [32]

> I-32
правильно, конечно, так: IA-32.


 
Slym ©   (2009-07-15 08:17) [33]

из под полы... через анонимные прокси пробиваюсь...
unit MVUComm;
interface
uses SysUtils,ComPortCtrl;
type
 TMVUPort=class(TComPort)
 public
   function GetState(Adr:byte;Reg:word;out State:boolean):boolean;
   function SetState(Adr:byte;Reg:word;State:boolean):boolean;
 end;

implementation
{
ASCII MODBUS- :CMD#13#10
MODBUS proto
1.adr:byte
2.Fn:byte =  read:$03, write:$10
3.Adr}

type
 TWordRec = packed record
   Hi,Lo:Byte;
 end;
 TMBRegReadCmd=packed record
   Adr:byte;
   Fn:byte;
   RegAdr:TWordRec;
   RegCnt:TWordRec;
   CRC:byte;
 end;
 TMBRegReadAnswer=packed record
   Adr:byte;
   Fn:byte;
   Len:byte;
   Data:TWordRec;
   CRC:byte;
 end;

 TMBRegWriteCmd=packed record
   Adr:byte;
   Fn:byte;
   RegAdr:TWordRec;
   RegCnt:TWordRec;
   Len:byte;
   Data:TWordRec;
   CRC:byte;
 end;
 TMBRegWriteAnswer=packed record
   Adr:byte;
   Fn:byte;
   RegAdr:TWordRec;
   RegCnt:TWordRec;
   CRC:byte;
 end;

//ModBus CRC routines
//Check ModBus command CRC
function MBCheckCRC(MBCmd:PByte;Size:integer):boolean;
var LRC:byte;
begin
 LRC:=0;
 repeat
   LRC:=LRC+MBCmd^;
   inc(MBCmd);
   Dec(Size);
 until Size=0;
 result:=(LRC=0);
end;

//Set ModBus command CRC
procedure MBSetCRC(MBCmd:PByte;Size:integer);
var LRC:byte;
begin
 Dec(Size);
 LRC:=0;
 repeat
   LRC:=LRC+MBCmd^;
   inc(MBCmd);
   Dec(Size);
 until Size=0;
 MBCmd^:=-LRC;
end;

//ModBus string routines
//Convert cmd to string with calc CRC
function MBCmdToStr(MBCmd:PByte;Size:integer):string;
begin
 MBSetCRC(MBCmd,Size);
 result:=&#39;&#39;;
 repeat
   result:=result+IntToHex(MBCmd^,2);
   inc(MBCmd);
   Dec(Size);
 until Size=0;
 result:=&#39;:&#39;+result+#13#10;
end;

//Convert string to cmd with checking CRC
function StrToMBCmd(Str:string;MBCmd:PByte;Size:integer):boolean;
var LRC:byte;
begin
 FillChar(MBCmd^,Size,0);
 result:=false;
 if copy(Str,1,1)<>&#39;:&#39; then exit;
 if copy(Str,length(Str)-1,2)<>#13#10 then exit;
 Str:=copy(Str,2,length(Str)-3);
 if (length(Str) mod 2)<>0 then exit;
 if (length(Str) div 2)<>Size then exit;

LRC:=0;
 repeat
   MBCmd^:=byte(StrToInt(&#39;$&#39;+copy(Str,1,2)));
   Delete(Str,1,2);
   LRC:=LRC+MBCmd^;
   inc(MBCmd);
   Dec(Size);
 until Size=0;
 result:=(LRC=0);
end;

{ MVUPort }

function TMVUPort.GetState(Adr: byte; Reg: word;
 out State: boolean): boolean;
var
 Query:TMBRegReadCmd;
 Answer:TMBRegReadAnswer;
 QueryStr,AnswerStr,Str:string;
begin
 result:=false;
 FillChar(Query,SizeOf(Query),0);
 Query.Adr:=Adr;
 Query.Fn:=$03;
 Query.RegAdr.Lo:=Reg;
 Query.RegCnt.Lo:=1;
 QueryStr:=MBCmdToStr(@Query,SizeOf(Query));

 AnswerStr:=&#39;&#39;;
 Lock;
 try
   Purge;
   WriteBuffer(PChar(QueryStr)^,Length(QueryStr));
   repeat
     SetLength(Str,256);
     SetLength(Str,Read(PChar(Str)^, Length(Str)));
     if Str=&#39;&#39; then break;
     AnswerStr:=AnswerStr+Str;
   until (pos(#13#10,AnswerStr)=0) and (length(AnswerStr)<256);
 finally
   Unlock;
 end;
 if StrToMBCmd(AnswerStr,@Answer,SizeOf(Answer)) then
 begin
   if (Answer.Adr<>Query.Adr) or (Answer.Fn<>Query.Fn) then exit;
   result:= (Answer.Data.Lo=Lo(1000)) and (Answer.Data.Hi=Hi(1000));
end;
end;

function TMVUPort.SetState(Adr: byte; Reg: word;
 State: boolean): boolean;
var
 Query:TMBRegWriteCmd;
 Answer:TMBRegWriteAnswer;
 QueryStr,AnswerStr,Str:string;
begin
 result:=false;
 FillChar(Query,SizeOf(Query),0);
 Query.Adr:=Adr;
 Query.Fn:=$10;
 Query.RegAdr.Lo:=Reg;
 Query.RegCnt.Lo:=1;
 Query.Len:=SizeOf(Query.Data);
ifState then
 begin
   Query.Data.Lo:=Lo(1000);
   Query.Data.Hi:=Hi(1000);
 end else
 begin
   Query.Data.Lo:=Lo(0);
   Query.Data.Hi:=Hi(0);
 end;
 QueryStr:=MBCmdToStr(@Query,SizeOf(Query));
 AnswerStr:=&#39;&#39;;
 Lock;
 try
   Purge;
   WriteBuffer(PChar(QueryStr)^,Length(QueryStr));
   repeat
     SetLength(Str,256);
     SetLength(Str,Read(PChar(Str)^, Length(Str)));
     if Str=&#39;&#39; then break;
     AnswerStr:=AnswerStr+Str;
   until (pos(#13#10,AnswerStr)=0) and (length(AnswerStr)<256);
 finally
   Unlock;
 end;

 if StrToMBCmd(AnswerStr,@Answer,SizeOf(Answer)) then
   result:=CompareMem(@Answer,@Query,SizeOf(Answer)-1);
end;

end.


 
Slym ©   (2009-07-15 08:40) [34]

итоговая процедурка должна выглядеть примерно так
procedure writedata(data:word);
type
 TMBSingleRegWriteCmd=packed record
   Adr:byte;
   Fn:byte;
   RegAdr:TWordRec;
   Data:TWordRec;
   CRC:byte;
 end;
var
 Query:TMBSingleRegWriteCmd;
begin
 Query.Adr:=$01;
 Query.Fn:=$06;
 Query.RegAdr.Lo:=$04;
 Query.RegAdr.Hi:=$00;
 Query.Data.Lo:=Lo(data);
 Query.Data.Hi:=Hi(data);
 MBSetCRC(@Query,SizeOf(Query));
 ComPort.Write(Query, SizeOf(Query));
end;


 
Slym ©   (2009-07-15 09:27) [35]

финальный релиз
procedure MBSetCRC16(MBCmd:PByte;Size:integer);
var
 CRC:word;
 i:integer;
 loCRC:byte;
begin
 Dec(Size,SizeOf(word));
 CRC:= $FFFF;
 repeat
   WordRec(CRC).Lo:=MBCmd^ xor WordRec(CRC).Lo;
   for i := 1 to 8 do
   begin
     loCRC:=lo(CRC);
     CRC := (CRC shr 1);
     if (loCRC and $01)<>0 then
       CRC:=CRC xor $A001;
    end;
   inc(MBCmd);
   Dec(Size);
 until Size=0;
 PWord(MBCmd)^:=Swap(CRC);
end;

procedure WriteData(data:word);
type
 TWordRec = packed record
   Hi,Lo:Byte;
 end;
 TMBSingleRegWriteCmd=packed record
   Adr:byte;
   Fn:byte;
   RegAdr:TWordRec;
   Data:TWordRec;
   CRC:word;
 end;
var
 Query:TMBSingleRegWriteCmd;
begin
 Query.Adr:=$01;
 Query.Fn:=$06;
 Query.RegAdr.Lo:=$04;
 Query.RegAdr.Hi:=$00;
 Query.Data.Lo:=Lo(data);
 Query.Data.Hi:=Hi(data);
 MBSetCRC16(@Query,SizeOf(Query));
 ComPort.Write(Query, SizeOf(Query));
end;


 
Sha ©   (2009-07-15 09:43) [36]

> Slym ©   (15.07.09 08:40) [34]

1. В протоколе Modbus все данные, кроме CRC, передаются в big-endian представлении. Поэтому у тебя вместо адреса устройства $0004 будет передан адрес $0400. Кроме того, передаваемые в процедуру данные придется предварительно свопить.

2. У автора CRC двухбайтовая и вычисляется по другому алгоритму.


 
Slym ©   (2009-07-15 09:56) [37]

Sha ©   (15.07.09 9:43) [36]
1. В протоколе Modbus все данные, кроме CRC, передаются в big-endian представлении. Поэтому у тебя вместо адреса устройства $0004 будет передан адрес $0400. Кроме того, передаваемые в процедуру данные придется предварительно свопить.

поэтому применена собственная TWordRec с переставленными байтами :)
Sha ©   (15.07.09 9:43) [36]
2. У автора CRC двухбайтовая и вычисляется по другому алгоритму.

это точно: я привел ASCII Modbus там LRC однобайтовый
но я поправился в [35] :) с ошибкой PWord(MBCmd)^:=Swap(CRC); Swap убрать


 
Sha ©   (2009-07-15 10:12) [38]

> Slym ©   (15.07.09 09:56) [37]
> поэтому применена собственная TWordRec

Извини, не заметил, имя типа очень похоже на WordRec из SysUtils


 
Zheksonz   (2009-07-15 10:20) [39]


> Sha ©   (15.07.09 07:19) [32]

Всё проверил, всё отлично работает. Спасибо.

ну а теперь самое вкусное)))

всё это дело нужно прикрутить к ДОСовской тачке(к сожалению без этого никак) + на языке программирования СИ.

Впринципе этапы инициализации порта и наполнения команды пройдены... но вот не воспринимаются эти команды инвертором. Может быть это связано с тем, что я просто в цикле посылал 8 байт не разворачивая их, т.е. не меняя верхний с нижним???

for(i=0;i<7;i++) out_byte(send[i]);

где send[] = 0x01, 0x06, 0x00, 0x04, 0x13, 0x88, 0xC5, 0x5D


 
Zheksonz   (2009-07-15 10:25) [40]


> Slym ©   (15.07.09 08:17) [33]

всё хорошо, но юнит требует ComPortCtrl.dcu



Страницы: 1 2 вся ветка

Форум: "Начинающим";
Текущий архив: 2009.09.20;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.57 MB
Время: 0.004 c
15-1248423609
Palladin
2009-07-24 12:20
2009.09.20
Неверный путь к оболочке у пользователя, FreeBSD


15-1246008636
Kolan
2009-06-26 13:30
2009.09.20
Чем заменить TChart?


2-1247646301
MZG
2009-07-15 12:25
2009.09.20
Форматирование диска


15-1248199056
Kerk
2009-07-21 21:57
2009.09.20
Предлагаю дополнение к ППД


1-1215539839
nordic3
2008-07-08 21:57
2009.09.20
Частая перерисовка image...





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский