Форум: "Начинающим";
Текущий архив: 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:='';
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)<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:='';
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)<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