![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
WriteBuffer - error - Access violation at addr... почему??? [D7, XP]
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
>
> А зачем менять указатель на буффер?
>
А ты, Саш сначала попробуй объяснить автору что такое буфер, что такое указатель и что он (автор) видит в отладчике.
Даже твой богатый опыт на других форумах тебе не поможет. :)