請教大大高手們,幫小弟想一下有沒有更精簡的寫法 |
答題得分者是:hagar
|
wychen57
一般會員 ![]() ![]() 發表:32 回覆:77 積分:21 註冊:2003-10-04 發送簡訊給我 |
延續之前apdcomport的議題,小弟寫了一段通訊程式,但我的程式執行起來效率不佳,主要問題在命令字串是array of byte, ApdComPort的Output,小弟寫了迴圈做轉換,但ApdComPort的input也是字元,卻找不到函式可以把它轉回byte型態,這樣小的的hextoflot跟crc16兩個function就無法正常使用了,小弟附上程式,請大大們指導一下,小弟的寫法有何改進方式,感恩
unit main;
//中間省略
procedure TForm1.Timer1Timer(Sender: TObject);
var
OutByte : array[0..7] of byte ;
i : integer;
s: string;
CrcData : word;
begin
OutByte[0] := $01;
OutByte[1] := $03;
OutByte[2] := $00;
OutByte[3] := $01;
OutByte[4] := $00;
OutByte[5] := $01;
CrcData := Crc16(OutByte,6); //或者改變副程式讓它直接處理字串
for i :=0 to 7 do
s := s char(Outbyte[i]);
end;
procedure TForm1.Comm1TriggerAvail(CP: TObject; Count: Word);
var
InByte : array of Byte;
i : integer;
s : string ;
begin
for i := 0 to Count-1 do
s := s comm1.GetChar ;
for i := 0 to Count-1 do
InByte[i] := StrToInt(s[i]); //就是這不正確,會有錯誤
end;
end.
以下為兩個副程式
unit Func;
interface
type
pSingle = ^TSingle ;
TSingle = record
Case Integer Of
0: (AsSingle:Single);
1: (FirstHi,FirstLo,SecondHi,SecondLo:Byte);
End;
implementation
function CRC16(CRCData: array of Byte; Datalen: Integer):Word;
var
CRC16Lo: Byte;
CRC16Hi: Byte;
SaveLo:Byte;
SaveHi:Byte;
GLo:Byte;
GHi:Byte;
i:Integer;
Flag:Integer;
begin
CRC16Lo:=$ff;
CRC16Hi:=$ff;
GLo:=$01;
GHi:=$a0;
for i:=0 to Datalen -1 do
begin
CRC16Lo:=CRC16Lo xor CRCData[i];
for Flag :=0 to 7 do
begin
SaveLo:=CRC16Lo;
SaveHi:=CRC16Hi;
CRC16Hi:=CRC16Hi shr 1;
CRC16Lo:=CRC16Lo shr 1;
if (SaveHi and $01) = $01 then
CRC16Lo:=CRC16Lo or $80;
if (SaveLo and $01) = $01 then
begin
CRC16Hi:=CRC16Hi xor GHi;
CRC16Lo:=CRC16Lo xor GLo;
end;
end;
end;
CRC16 := CRC16Lo * 256 CRC16Hi;
end;
function HexToFloat(aryData: array of Byte; Datalen: Integer):Single;
Var
p : PSingle;
S : Single ;
begin
S := 23 ;
P := @S ; // ÅýP «ü¦VS ªº¦ì§}(¨Ï¥Î¦P¤@¶ô°O¾ÐÅé)
P.FirstHi := aryData[2];
P.FirstLo := aryData[3];
P.SecondHi := aryData[4];
P.SecondLo := aryData[5];
end;
end.
|
hagar
版主 ![]() ![]() ![]() ![]() ![]() ![]() 發表:143 回覆:4056 積分:4445 註冊:2002-04-14 發送簡訊給我 |
小弟改成如下
unit main; procedure TForm1.Timer1Timer(Sender: TObject); var OutByte : string; i : integer; s: string; CrcData : word; begin OutByte := #1#3#0#1#0#1; CrcData := Crc16(OutByte); //for i :=0 to 7 do // 不知這個變數 s 的用意是? // s := s char(Outbyte[i]); end; procedure TForm1.Comm1TriggerAvail(CP: TObject; Count: Word); var InByte : array of Byte; i : integer; s : string ; begin for i := 0 to Count-1 do s := s comm1.GetChar ; for i := 0 to Count-1 do InByte[i] := StrToInt(s[i 1]); //delphi 的字串是由 1 開始 end; end. //以下為兩個副程式 [blue] unit Func; interface type pSingle = ^TSingle ; TSingle = record Case Integer Of 0: (AsSingle:Single); 1: (FirstHi,FirstLo,SecondHi,SecondLo:Byte); end; implementation function CRC16(CRCData: string): Word; var CRC16Lo: Byte; CRC16Hi: Byte; SaveLo:Byte; SaveHi:Byte; GLo:Byte; GHi:Byte; i:Integer; Flag:Integer; begin CRC16Lo:=$ff; CRC16Hi:=$ff; GLo:=$01; GHi:=$a0; for i:=1 to Length(CRCData) do begin CRC16Lo:=CRC16Lo xor Byte(CRCData[i]); for Flag :=0 to 7 do begin SaveLo:=CRC16Lo; SaveHi:=CRC16Hi; CRC16Hi:=CRC16Hi shr 1; CRC16Lo:=CRC16Lo shr 1; if (SaveHi and $01) = $01 then CRC16Lo:=CRC16Lo or $80; if (SaveLo and $01) = $01 then begin CRC16Hi:=CRC16Hi xor GHi; CRC16Lo:=CRC16Lo xor GLo; end; end; end; CRC16 := CRC16Lo * 256 CRC16Hi; end; function HexToFloat(aryData: array of Byte; Datalen: Integer):Single; Var p : PSingle; S : Single ; begin S := 23 ; P := @S ; // Ay P ?u| VS ao| i§}(?I¥I| P?@?o°O?DAe) P.FirstHi := aryData[2]; P.FirstLo := aryData[3]; P.SecondHi := aryData[4]; P.SecondLo := aryData[5]; end; end.-- hagar. 發表人 - hagar 於 2005/05/16 20:03:01 |
wychen57
一般會員 ![]() ![]() 發表:32 回覆:77 積分:21 註冊:2003-10-04 發送簡訊給我 |
引言: 小弟改成如下 unit main; procedure TForm1.Timer1Timer(Sender: TObject); var OutByte : string; i : integer; s: string; CrcData : word; begin OutByte := #1#3#0#1#0#1; //OutByte的第0、2、3、4、5位是個變數喔,分別是modbus設備的位 //址、要抓取的暫存器位址(佔兩個byte)、抓取的暫存器數量(佔兩個byte),運算出前6byte的crc值附加到尾端(2byte),成完整命令串再輸出給設備 //小弟知道要用char把它轉成字元,但抓回來的資料怎麼從字元再轉回byte, //以供HexToFloat函式運算成真正的數值,是用您下面提到的byte(...)嗎,謝謝 CrcData := Crc16(OutByte); //for i :=0 to 7 do // 不知這個變數 s 的用意是?<==就是把byte陣列轉成string啦,原本是要當Comm1.Output := s ;,但大大已經整個改寫副程式,就用不到啦 |
hagar
版主 ![]() ![]() ![]() ![]() ![]() ![]() 發表:143 回覆:4056 積分:4445 註冊:2002-04-14 發送簡訊給我 |
了解以下這個觀念就可知道怎麼運用
假設有 s 這個變數, 其值為 '12345'
則 s[1] 表示第 1 個字元, 其型態為 char
Byte(s[1]) 則表示將其轉型為 Byte
Byte 它不是一個 function
小弟之前寫 #1 就是 char($01)
以下是 OutBtye 的一些表示方法
1) OutByte := #1#3#0#1#0#1;
2) OutByte := char($01) char($03) char($00) char($01) char($00) char($01);
所以不需要什麼特別的轉換 --
hagar.
|
wychen57
一般會員 ![]() ![]() 發表:32 回覆:77 積分:21 註冊:2003-10-04 發送簡訊給我 |
|
wychen57
一般會員 ![]() ![]() 發表:32 回覆:77 積分:21 註冊:2003-10-04 發送簡訊給我 |
小弟試了一下,發現HexToSignInt這函式動作不正常,沒法運算傳回正確的值,應該要傳回一個負值,但卻傳回1,大大可以幫我看一下哪裡寫錯了嗎,小弟這副程式目的在把陣列中指定的2byte轉換成有號整數(-32768~32767),謝謝
主程式中的呼叫
var InByte : array[0..1] of byte ; InByte[0] := $80 ;
InByte[1] := $00 ;
MeterVal := HexToSignInt(InByte);
label1.Caption := IntToStr(MeterVal);
副程式的宣告及程式主體
type
pSmallInt = ^TSmallInt ;
TSmallInt = record
Case Integer Of
0: (AsSingle:SmallInt);
1: (FirstHi,FirstLo:Byte);
End; function HexToSignInt(aryData: array of Byte):SmallInt;
Var
p : PSmallInt;
S : SmallInt ;
begin
P := @S ; // ÅýP «ü¦VS ªº¦ì§}(¨Ï¥Î¦P¤@¶ô°O¾ÐÅé)
// ³vÓByte Âন16¶i¦ì¦r¦ê
P.FirstHi := aryData[0];
P.FirstLo := aryData[1];
end;
end.
發表人 - wychen57 於 2005/05/17 02:01:56
|
hagar
版主 ![]() ![]() ![]() ![]() ![]() ![]() 發表:143 回覆:4056 積分:4445 註冊:2002-04-14 發送簡訊給我 |
|
wychen57
一般會員 ![]() ![]() 發表:32 回覆:77 積分:21 註冊:2003-10-04 發送簡訊給我 |
一般電表通訊,數值是用hex分數byte傳回(int就2byte,long就4byte..),所以要寫一支函式將16進制的值轉成原本的數值,例如傳回integer就得將傳回的前一byte放到int的low byte,後一byte就放到int的hight byte,如果是long,分別將傳回的4byte依序放到inog變數的LoWLoByte,LOHightByte,HighLoByte,HighHiByte,所以要能指定要運算陣列中那個byte為起始,要運算2或4byte(視資料型態而定),小弟要依資料形態把程式改成HexToInt or HexToFloat or HexToLong,這樣講大大能了解嗎,小弟的問題在於陣列傳過去的不是陣列本身的元素,而是一堆奇怪的值,所以無法順利換算,然後傳回,所以請大大幫小弟看參數傳遞那出問題,小弟自己有單步追蹤過副程式,發現一開始陣列元素有傳過去,但一到宣告 P:PSmallInt ; & S:SmallInt兩行後,陣列就不見了,所以請大大幫忙囉,謝謝,感恩了
|
hagar
版主 ![]() ![]() ![]() ![]() ![]() ![]() 發表:143 回覆:4056 積分:4445 註冊:2002-04-14 發送簡訊給我 |
先說明小弟對這樣的用法並不清楚
所以您自己要測試一下
type PSmallInt = ^TSmallInt ; TSmallInt = record case Integer Of 0: (AsSingle: SmallInt); 1: (FirstHi, FirstLo: Byte); end; function HexToSignInt(aryData: array of Byte): SmallInt; Var p : PSmallInt; S : SmallInt; begin P := @S; // 先看上面這一行, P 變數宣告為 PSmallInt 型態 // 而 PSmallInt 為 TSmallInt 的指標 // 現在您將 P 的值指定為 S 這個變數的指標 // 但是 S 這個變數的型態是 SmallInt, 並不是 TSmallInt P.FirstHi := aryData[0]; P.FirstLo := aryData[1]; end;再來 HexToSignInt 宣告為 function, 其回傳值為 SmallInt 但從您的程式來看不出回傳值(Result)在哪? 最後, 所謂的 "陣列就不見了" 是什麼意思? -- hagar. |
wychen57
一般會員 ![]() ![]() 發表:32 回覆:77 積分:21 註冊:2003-10-04 發送簡訊給我 |
引言: 先說明小弟對這樣的用法並不清楚 所以您自己要測試一下type PSmallInt = ^TSmallInt ; TSmallInt = record case Integer Of 0: (AsSingle: SmallInt); 1: (FirstHi, FirstLo: Byte); end; function HexToSignInt(aryData: array of Byte): SmallInt; Var p : PSmallInt; S : SmallInt; begin P := @S; // 先看上面這一行, P 變數宣告為 PSmallInt 型態 // 而 PSmallInt 為 TSmallInt 的指標 // 現在您將 P 的值指定為 S 這個變數的指標 // 但是 S 這個變數的型態是 SmallInt, 並不是 TSmallInt 那請教一下該怎麼定義才對,謝謝 P.FirstHi := aryData[0]; P.FirstLo := aryData[1]; end;再來 HexToSignInt 宣告為 function, 其回傳值為 SmallInt 但從您的程式來看不出回傳值(Result)在哪? //大大抱歉啦,就是不知如何定義傳回值啦 最後, 所謂的 "陣列就不見了" 是什麼意思? 就是陣列元素[$80,$00]傳到那兩行宣告跑完後,內容就變成[.]我也不知這是啥意思,是watch視窗show的值 -- hagar. |
hagar
版主 ![]() ![]() ![]() ![]() ![]() ![]() 發表:143 回覆:4056 積分:4445 註冊:2002-04-14 發送簡訊給我 |
指定 function 回傳值的方法如下:
function funXXX(var1: integer): integer; begin // ... Result := var1 5; // 即是用 Result 這個關鍵字 end;最後, HexToSignInt 這個 function 的回傳值是 SmallInt 但小弟不懂如何從 TSmallInt 轉成 SmallInt 如果 function 的回傳型態改為 TSmallInt 的話 改成如下試試: function HexToSignInt(aryData: array of Byte): TSmallInt; begin Result.FirstHi := aryData[0]; Result.FirstLo := aryData[1]; end;-- hagar. |
wychen57
一般會員 ![]() ![]() 發表:32 回覆:77 積分:21 註冊:2003-10-04 發送簡訊給我 |
本站聲明 |
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。 2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。 3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇! |