全國最多中醫師線上諮詢網站-台灣中醫網
發文 回覆 瀏覽次數:2550
推到 Plurk!
推到 Facebook!

請教大大高手們,幫小弟想一下有沒有更精簡的寫法

答題得分者是:hagar
wychen57
一般會員


發表:32
回覆:77
積分:21
註冊:2003-10-04

發送簡訊給我
#1 引用回覆 回覆 發表時間:2005-05-16 16:18:50 IP:61.66.xxx.xxx 未訂閱
延續之前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

發送簡訊給我
#2 引用回覆 回覆 發表時間:2005-05-16 19:57:46 IP:202.39.xxx.xxx 未訂閱
小弟改成如下
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

發送簡訊給我
#3 引用回覆 回覆 發表時間:2005-05-16 20:45:41 IP:61.66.xxx.xxx 未訂閱
引言: 小弟改成如下 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 ;,但大大已經整個改寫副程式,就用不到啦 // >>]); <>//> > > >>; ^^^^<>有> >//如果這副程式要改成直接運算> >//,會不會有問題? >//要改成轉換> >//寫法一樣嗎 >//例如> >//例如> >//例如> >//例如> >< face="Verdana, Arial, Helvetica"> 問了那麼多白爛問題,請大大海涵一下,再指導一下嚕,謝謝 發表人 -
hagar
版主


發表:143
回覆:4056
積分:4445
註冊:2002-04-14

發送簡訊給我
#4 引用回覆 回覆 發表時間:2005-05-16 20:56:30 IP:202.39.xxx.xxx 未訂閱
了解以下這個觀念就可知道怎麼運用 假設有 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

發送簡訊給我
#5 引用回覆 回覆 發表時間:2005-05-16 22:47:05 IP:211.76.xxx.xxx 未訂閱
謝謝大大指導,我先試一下再請教您
wychen57
一般會員


發表:32
回覆:77
積分:21
註冊:2003-10-04

發送簡訊給我
#6 引用回覆 回覆 發表時間:2005-05-17 01:51:25 IP:211.76.xxx.xxx 未訂閱
小弟試了一下,發現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

發送簡訊給我
#7 引用回覆 回覆 發表時間:2005-05-17 08:17:15 IP:202.39.xxx.xxx 未訂閱
HexToSignInt 這個函式是要做什麼用的? 另外貼程式碼的時候請在程式碼的前面加上[code] 在程式碼的後面加上[/code], 以利閱讀 -- hagar. 發表人 - hagar 於 2005/05/17 08:17:45
wychen57
一般會員


發表:32
回覆:77
積分:21
註冊:2003-10-04

發送簡訊給我
#8 引用回覆 回覆 發表時間:2005-05-17 09:33:13 IP:61.66.xxx.xxx 未訂閱
一般電表通訊,數值是用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

發送簡訊給我
#9 引用回覆 回覆 發表時間:2005-05-17 19:46:25 IP:202.39.xxx.xxx 未訂閱
先說明小弟對這樣的用法並不清楚 所以您自己要測試一下
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

發送簡訊給我
#10 引用回覆 回覆 發表時間:2005-05-17 21:47:23 IP:211.76.xxx.xxx 未訂閱
引言: 先說明小弟對這樣的用法並不清楚 所以您自己要測試一下
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

發送簡訊給我
#11 引用回覆 回覆 發表時間:2005-05-18 08:37:52 IP:202.39.xxx.xxx 未訂閱
指定 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

發送簡訊給我
#12 引用回覆 回覆 發表時間:2005-05-18 09:22:07 IP:61.66.xxx.xxx 未訂閱
謝謝大大,問題已全數解決
系統時間:2024-04-20 21:22:02
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!