Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

WriteBuffer - error - Access violation at addr... почему??? [D7, XP]


Страницы:   1 2 3

Zheksonz ©   (2009-07-14 17:38:00) 

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

Код:
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;


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


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


> 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


Sha   (2009-07-15 10:12:00) [22]

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

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


Slym   (2009-07-15 09:56:00) [23]

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 09:43:00) [24]

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

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

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


Slym   (2009-07-15 09:27:00) [25]

финальный релиз
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;


Slym   (2009-07-15 08:40:00) [26]

итоговая процедурка должна выглядеть примерно так
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 08:17:00) [27]

из под полы... через анонимные прокси пробиваюсь...
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:='';
 repeat
   result:=result+IntToHex(MBCmd^,2);
   inc(MBCmd);
   Dec(Size);
 until Size=0;
 result:=':'+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)':' 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('$'+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:='';
 Lock;
 try
   Purge;
   WriteBuffer(PChar(QueryStr)^,Length(QueryStr));
   repeat
     SetLength(Str,256);
     SetLength(Str,Read(PChar(Str)^, Length(Str)));
     if Str='' then break;
     AnswerStr:=AnswerStr+Str;
   until (pos(#13#10,AnswerStr)=0) and (length(AnswerStr)


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

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


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


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


Ок.

спасибо


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

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


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

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


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

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


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

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


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

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


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


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


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

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


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

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

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


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


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

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


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


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

0


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

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


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


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

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


Страницы:   1 2 3

Наверх

Титульная страница Поиск, карта сайта Написать письмо