“多負載識別監控平臺(上位機)”技術細節 之Unit1-Form1主界面

下面介紹Unit1主界面的實現。


1.Timer2

Timer2是用來顯示系統時間用的時鐘,每30秒刷新一次,因此係統時間只能顯示到分鐘了……

procedure TForm1.Timer2Timer(Sender: TObject);{---------------------顯示系統時間的 定時中斷2}
var                                                                                //定時30s
  Time:TDateTime;//系統時間
begin
  Time:=now;
  if copy(TimetoStr(time),5,1)=':' then
    TeStatusBar1.Panels[4].Text := Datetostr(time)+' '+leftstr(TimeToStr(Time),4)
  else
    TeStatusBar1.Panels[4].Text := Datetostr(time)+' '+leftstr(TimeToStr(Time),5);//在狀態欄顯示系統時間
end;

爲了完整的取出系統時間,在delphi中要使用now函數,參考http://blog.csdn.net/yorkworlddream/article/details/17500683

使用DatetoStr來取出time中的日期,即年月日,使用TimeToStr取出time中的時間,即時分秒。

copy函數舉例:Copy(Str,2,2)=el;//從Str字符串變量的中第2個字符開始取長度爲2個字符的字符串,即一個從指定位置截取指定長度字符的函數。

舉例兩種時間:18:26:00和12:3:4,對於第一個時間值,直接使用leftstr(TimeToStr(Time),4);即可直接取出time的時分爲18:26,但可以看到第二個時間中的“分”爲個位數,要是依然使用前面的語句,那就會取出12:3:這樣的顯示是不行的,所以要判斷time的“分”是不是爲個位,即使用語句if copy(TimetoStr(time),5,1)=':' then來判斷。

注:copy函數數字符串,起始計數爲1,即對於時間18:26中的8是第2位。

2.Timer1

Timer1用來每5分鐘刷新一次繼電器狀態。

procedure TForm1.Timer1Timer(Sender: TObject);{----------------------------------定時器中斷1}
var                                                                              //定時5分鐘
  Time:TDateTime;//系統時間
  nowDate,nowTime : string;
  nowMinute : integer;
begin
  Time:=now;//只有now才正確,參考http://blog.csdn.net/yorkworlddream/article/details/17500683
  nowTime := TimeToStr(Time);
  //5分鐘自動掃描繼電器狀態
  nowMinute := strtoint(copy(nowTime,4,2));//copy用於截取 http://blog.csdn.net/yorkworlddream/article/details/17500855
  if nowMinute > lastMinute then//lastMinute全局變量
    begin
      sysSendState := 0;//設置全局變量sysSendState爲0,即發送 查詢繼電器狀態 幀
      timer3.Enabled:=true;//開定時器3,讓它負責發送,發完讓它自己關掉自己
      lastMinute := nowMinute;
    end;
//  tememo1.Lines.Add(b0cxjdq);//對memo進行操作使用add方法
end;
Timer1只負責到時開timer3,自己不負責查詢幀的發送,查詢幀數據是由Timer3來發送的。

3.Timer3

Timer3用來發送繼電器的查詢命令幀、繼電器的控制命令幀,每500ms被觸發一次,每觸發一次發送一個表的查詢或控制命令幀。Timer3由其他定時器開啓,發送完成後被自身關閉。

procedure TForm1.Timer3Timer(Sender: TObject);{------用於串口發數,每500ms觸發一次 定時中斷3}
begin                                                                             //定時500ms
{0}
  if sysSendState =0  then//發送 查詢繼電器狀態 幀
  begin
    if bhindex = 9 then
      begin
        comport1.WriteStr(Hexstrtostr(b9cxjdq));//調用Hexstrtostr函數
        tememo1.Text:= b9cxjdq;//顯示要發出的數據
        bhIndex := 0;//表號歸0,=0表示下次要發送表號0的幀數據,即從新開始了
        timer3.Enabled:=false;//自己關斷自己,它的開要由timer1來決定
        timer1.Enabled:=true;//打開timer1
      end
    else if bhindex = 8 then
      begin
        comport1.WriteStr(Hexstrtostr(b8cxjdq));//調用Hexstrtostr函數
        tememo1.Text:= b8cxjdq;//顯示要發出的數據
        bhIndex := bhIndex +1;//表號加1,=9表示下次要發送表號9的幀數據
      end
    else if bhindex = 7 then
      begin
        comport1.WriteStr(Hexstrtostr(b7cxjdq));//調用Hexstrtostr函數
        tememo1.Text:= b7cxjdq;//顯示要發出的數據
        bhIndex := bhIndex +1;//表號加1,=8表示下次要發送表號8的幀數據
      end
    else if bhindex = 6 then
      begin
        comport1.WriteStr(Hexstrtostr(b6cxjdq));//調用Hexstrtostr函數
        tememo1.Text:= b6cxjdq;//顯示要發出的數據
        bhIndex := bhIndex +1;//表號加1,=7表示下次要發送表號7的幀數據
      end
    else if bhindex = 5 then
      begin
        comport1.WriteStr(Hexstrtostr(b5cxjdq));//調用Hexstrtostr函數
        tememo1.Text:= b5cxjdq;//顯示要發出的數據
        bhIndex := bhIndex +1;//表號加1,=6表示下次要發送表號6的幀數據
      end
    else if bhindex = 4 then
      begin
        comport1.WriteStr(Hexstrtostr(b4cxjdq));//調用Hexstrtostr函數
        tememo1.Text:= b4cxjdq;//顯示要發出的數據
        bhIndex := bhIndex +1;//表號加1,=5表示下次要發送表號5的幀數據
      end
    else if bhindex = 3 then
      begin
        comport1.WriteStr(Hexstrtostr(b3cxjdq));//調用Hexstrtostr函數
        tememo1.Text:= b3cxjdq;//顯示要發出的數據
        bhIndex := bhIndex +1;//表號加1,=4表示下次要發送表號4的幀數據
      end
    else if bhindex = 2 then
      begin
        comport1.WriteStr(Hexstrtostr(b2cxjdq));//調用Hexstrtostr函數
        tememo1.Text:= b2cxjdq;//顯示要發出的數據
        bhIndex := bhIndex +1;//表號加1,=3表示下次要發送表號3的幀數據
      end
    else if bhindex = 1 then
      begin
        comport1.WriteStr(Hexstrtostr(b1cxjdq));//調用Hexstrtostr函數
        tememo1.Text:= b1cxjdq;//顯示要發出的數據
        bhIndex := bhIndex +1;//表號加1,=2表示下次要發送表號2的幀數據
      end
    else if bhIndex = 0 then
      begin
        comport1.WriteStr(Hexstrtostr(b0cxjdq));//調用Hexstrtostr函數
        tememo1.Text:= b0cxjdq;//顯示要發出的數據
        bhIndex := bhIndex +1;//表號加1,=1表示下次要發送表號1的幀數據
      end;
  end;
{1}
  if sysSendState = 1 then//發送 開關繼電器 幀
  begin
    if gI=0 then
    begin
      if jdqRadioBtn0k.Checked = true then//00表設置爲開
        begin
          comport1.WriteStr(Hexstrtostr(b0kjdq)); //調用Hexstrtostr函數
          tememo1.Text:= b0kjdq;//顯示要發出的數據
        end//---------------------------------------------------------------注意else前無分號
      else
        begin
          comport1.WriteStr(Hexstrtostr(b0gjdq));
          tememo1.Text:= b0gjdq;
        end;
    end

    else if gI=1 then
    begin
      if jdqRadioBtn1k.Checked = true then//01表設置爲開
        begin
          comport1.WriteStr(Hexstrtostr(b1kjdq)); //調用Hexstrtostr函數
          tememo1.Text:= b1kjdq;//顯示要發出的數據
        end
      else
        begin
          comport1.WriteStr(Hexstrtostr(b1gjdq));
          tememo1.Text:= b1gjdq;
        end;
    end

    else if gI=2 then
    begin
      if jdqRadioBtn2k.Checked = true then//02表設置爲開
        begin
          comport1.WriteStr(Hexstrtostr(b2kjdq)); //調用Hexstrtostr函數
          tememo1.Text:= b2kjdq;//顯示要發出的數據
        end
      else
        begin
          comport1.WriteStr(Hexstrtostr(b2gjdq));
          tememo1.Text:= b2gjdq;
        end;
    end

    else if gI=3 then
    begin
      if jdqRadioBtn3k.Checked = true then//03表設置爲開
        begin
          comport1.WriteStr(Hexstrtostr(b3kjdq)); //調用Hexstrtostr函數
          tememo1.Text:= b3kjdq;//顯示要發出的數據
        end
      else
        begin
          comport1.WriteStr(Hexstrtostr(b3gjdq));
          tememo1.Text:= b3gjdq;
        end;
    end

    else if gI=4 then
    begin
      if jdqRadioBtn4k.Checked = true then//04表設置爲開
        begin
          comport1.WriteStr(Hexstrtostr(b4kjdq)); //調用Hexstrtostr函數
          tememo1.Text:= b4kjdq;//顯示要發出的數據
        end
      else
        begin
          comport1.WriteStr(Hexstrtostr(b4gjdq));
          tememo1.Text:= b4gjdq;
        end;
    end

    else if gI=5 then
    begin
      if jdqRadioBtn5k.Checked = true then//05表設置爲開
        begin
          comport1.WriteStr(Hexstrtostr(b5kjdq)); //調用Hexstrtostr函數
          tememo1.Text:= b5kjdq;//顯示要發出的數據
        end
      else
        begin
          comport1.WriteStr(Hexstrtostr(b5gjdq));
          tememo1.Text:= b5gjdq;
        end;
    end

    else if gI=6 then
    begin
      if jdqRadioBtn6k.Checked = true then//06表設置爲開
        begin
          comport1.WriteStr(Hexstrtostr(b6kjdq)); //調用Hexstrtostr函數
          tememo1.Text:= b6kjdq;//顯示要發出的數據
        end
      else
        begin
          comport1.WriteStr(Hexstrtostr(b6gjdq));
          tememo1.Text:= b6gjdq;
        end;
    end

    else if gI=7 then
    begin
      if jdqRadioBtn7k.Checked = true then//07表設置爲開
        begin
          comport1.WriteStr(Hexstrtostr(b7kjdq)); //調用Hexstrtostr函數
          tememo1.Text:= b7kjdq;//顯示要發出的數據
        end
      else
        begin
          comport1.WriteStr(Hexstrtostr(b7gjdq));
          tememo1.Text:= b7gjdq;
        end;
    end

    else if gI=8 then
    begin
      if jdqRadioBtn8k.Checked = true then//08表設置爲開
        begin
          comport1.WriteStr(Hexstrtostr(b8kjdq)); //調用Hexstrtostr函數
          tememo1.Text:= b8kjdq;//顯示要發出的數據
        end
      else
        begin
          comport1.WriteStr(Hexstrtostr(b8gjdq));
          tememo1.Text:= b8gjdq;
        end;
    end

    else if gI=9 then
    begin
      if jdqRadioBtn9k.Checked = true then//09表設置爲開
        begin
          comport1.WriteStr(Hexstrtostr(b9kjdq)); //調用Hexstrtostr函數
          tememo1.Text:= b9kjdq;//顯示要發出的數據
        end
      else
        begin
          comport1.WriteStr(Hexstrtostr(b9gjdq));
          tememo1.Text:= b9gjdq;
        end;
      timer1.Enabled:=true;//發送完成,打開timer1
      timer3.Enabled:=false;//發送完成,timer3關閉自己
      gI := 0;
      sysSendState :=0;//初始的系統發送狀態歸爲0,即 查詢繼電器 幀
    end;
    gI := gI + 1;
  end;
end;
由於查詢繼電器狀態和控制繼電器是由不同的控件觸發的,所以爲了區分是查詢還是控制,使用了一個全局變量sysSendState來進行判斷,當sysSendState=0時代表查詢,=1時爲控制。

gI的左右就是Timer3被觸發一次,自己加1,可以保證每次發送的只是一個表的數據,因爲我在剛開始寫這段程序的時候怕上位機發的太快,下面下位機搶佔485總線,使發送與應答衝突,就想着隔500ms發一個幀,由於開始用的不熟練,只想到了這個辦法,現在看,只要編寫一個delay函數即可。函數如下:

procedure Delay(dwMilliseconds:DWORD);//Longint
var
iStart,iStop:DWORD;
begin
    iStart :=   GetTickCount;
    repeat
    iStop  :=   GetTickCount;
    Application.ProcessMessages;
    until (iStop  -  iStart) >= dwMilliseconds;
end;
在Timer3中發送的幀代碼使用的全局字符串變量,直接將幀寫好,發的時候直接發字符串名即可,當然,這個方法也很浪費代碼,沒辦法,最先寫的Form1的程序,才入門也只能這樣了,幀的字符串變量如下:

  b0gjdq   : string[44]=  '68 00 30 00 00 00 00 68 04 03 e6 83 00 13 16';//關繼電器
  b0kjdq   : string[44]=  '68 00 30 00 00 00 00 68 04 03 e6 83 01 13 16';//開繼電器
  b0cxjdq  : string[41]=  '68 00 30 00 00 00 00 68 01 02 e7 83 13 16';   //查詢繼電器
  b0cxdn   : string[41]=  '68 00 30 00 00 00 00 68 01 02 44 c3 13 16';   //查詢電能
  b0cxgl   : string[41]=  '68 00 30 00 00 00 00 68 01 02 64 e9 13 16';   //查詢功率
  //表1
  b1gjdq   : string[44]=  '68 01 30 00 00 00 00 68 04 03 e6 83 00 13 16';//關繼電器
  b1kjdq   : string[44]=  '68 01 30 00 00 00 00 68 04 03 e6 83 01 13 16';//開繼電器
  b1cxjdq  : string[41]=  '68 01 30 00 00 00 00 68 01 02 e7 83 13 16';   //查詢繼電器
  b1cxdn   : string[41]=  '68 01 30 00 00 00 00 68 01 02 44 c3 13 16';   //查詢電能
  b1cxgl   : string[41]=  '68 01 30 00 00 00 00 68 01 02 64 e9 13 16';   //查詢功率
  //表2
  b2gjdq   : string[44]=  '68 02 30 00 00 00 00 68 04 03 e6 83 00 13 16';//關繼電器
  b2kjdq   : string[44]=  '68 02 30 00 00 00 00 68 04 03 e6 83 01 13 16';//開繼電器
  b2cxjdq  : string[41]=  '68 02 30 00 00 00 00 68 01 02 e7 83 13 16';   //查詢繼電器
  b2cxdn   : string[41]=  '68 02 30 00 00 00 00 68 01 02 44 c3 13 16';   //查詢電能
  b2cxgl   : string[41]=  '68 02 30 00 00 00 00 68 01 02 64 e9 13 16';   //查詢功率
  //表3
  b3gjdq   : string[44]=  '68 03 30 00 00 00 00 68 04 03 e6 83 00 13 16';//關繼電器
  b3kjdq   : string[44]=  '68 03 30 00 00 00 00 68 04 03 e6 83 01 13 16';//開繼電器
  b3cxjdq  : string[41]=  '68 03 30 00 00 00 00 68 01 02 e7 83 13 16';   //查詢繼電器
  b3cxdn   : string[41]=  '68 03 30 00 00 00 00 68 01 02 44 c3 13 16';   //查詢電能
  b3cxgl   : string[41]=  '68 03 30 00 00 00 00 68 01 02 64 e9 13 16';   //查詢功率
  //表4
  b4gjdq   : string[44]=  '68 04 30 00 00 00 00 68 04 03 e6 83 00 13 16';//關繼電器
  b4kjdq   : string[44]=  '68 04 30 00 00 00 00 68 04 03 e6 83 01 13 16';//開繼電器
  b4cxjdq  : string[41]=  '68 04 30 00 00 00 00 68 01 02 e7 83 13 16';   //查詢繼電器
  b4cxdn   : string[41]=  '68 04 30 00 00 00 00 68 01 02 44 c3 13 16';   //查詢電能
  b4cxgl   : string[41]=  '68 04 30 00 00 00 00 68 01 02 64 e9 13 16';   //查詢功率
  //表5
  b5gjdq   : string[44]=  '68 05 30 00 00 00 00 68 04 03 e6 83 00 13 16';//關繼電器
  b5kjdq   : string[44]=  '68 05 30 00 00 00 00 68 04 03 e6 83 01 13 16';//開繼電器
  b5cxjdq  : string[41]=  '68 05 30 00 00 00 00 68 01 02 e7 83 13 16';   //查詢繼電器
  b5cxdn   : string[41]=  '68 05 30 00 00 00 00 68 01 02 44 c3 13 16';   //查詢電能
  b5cxgl   : string[41]=  '68 05 30 00 00 00 00 68 01 02 64 e9 13 16';   //查詢功率
  //表6
  b6gjdq   : string[44]=  '68 06 30 00 00 00 00 68 04 03 e6 83 00 13 16';//關繼電器
  b6kjdq   : string[44]=  '68 06 30 00 00 00 00 68 04 03 e6 83 01 13 16';//開繼電器
  b6cxjdq  : string[41]=  '68 06 30 00 00 00 00 68 01 02 e7 83 13 16';   //查詢繼電器
  b6cxdn   : string[41]=  '68 06 30 00 00 00 00 68 01 02 44 c3 13 16';   //查詢電能
  b6cxgl   : string[41]=  '68 06 30 00 00 00 00 68 01 02 64 e9 13 16';   //查詢功率
  //表7
  b7gjdq   : string[44]=  '68 07 30 00 00 00 00 68 04 03 e6 83 00 13 16';//關繼電器
  b7kjdq   : string[44]=  '68 07 30 00 00 00 00 68 04 03 e6 83 01 13 16';//開繼電器
  b7cxjdq  : string[41]=  '68 07 30 00 00 00 00 68 01 02 e7 83 13 16';   //查詢繼電器
  b7cxdn   : string[41]=  '68 07 30 00 00 00 00 68 01 02 44 c3 13 16';   //查詢電能
  b7cxgl   : string[41]=  '68 07 30 00 00 00 00 68 01 02 64 e9 13 16';   //查詢功率
  //表8
  b8gjdq   : string[44]=  '68 08 30 00 00 00 00 68 04 03 e6 83 00 13 16';//關繼電器
  b8kjdq   : string[44]=  '68 08 30 00 00 00 00 68 04 03 e6 83 01 13 16';//開繼電器
  b8cxjdq  : string[41]=  '68 08 30 00 00 00 00 68 01 02 e7 83 13 16';   //查詢繼電器
  b8cxdn   : string[41]=  '68 08 30 00 00 00 00 68 01 02 44 c3 13 16';   //查詢電能
  b8cxgl   : string[41]=  '68 08 30 00 00 00 00 68 01 02 64 e9 13 16';   //查詢功率
  //表9
  b9gjdq   : string[44]=  '68 09 30 00 00 00 00 68 04 03 e6 83 00 13 16';//關繼電器
  b9kjdq   : string[44]=  '68 09 30 00 00 00 00 68 04 03 e6 83 01 13 16';//開繼電器
  b9cxjdq  : string[41]=  '68 09 30 00 00 00 00 68 01 02 e7 83 13 16';   //查詢繼電器
  b9cxdn   : string[41]=  '68 09 30 00 00 00 00 68 01 02 44 c3 13 16';   //查詢電能
  b9cxgl   : string[41]=  '68 09 30 00 00 00 00 68 01 02 64 e9 13 16';   //查詢功率

由於幀字符串是用字符串來表示十六進制,即“68”表示0x68,這樣直接下傳是不對的,所以要使用到HexStrToStr函數,將“68”真正的轉爲0x68

HexStrToStr:

{16進制字符串轉換成字符串}
function HexStrToStr(const S:string):string;//16進制字符串轉換成字符串
var
  t:Integer;
  ts:string;
  M,Code:Integer;
begin
  t:=1;
  Result:='';
  while t<=Length(S) do
  begin
    while not (S[t] in ['0'..'9','A'..'F','a'..'f']) do
      inc(t);
    if (t+1>Length(S))or(not (S[t+1] in ['0'..'9','A'..'F','a'..'f'])) then
      ts:='$'+S[t]
    else
      ts:='$'+S[t]+S[t+1];
    Val(ts,M,Code);
    if Code=0 then
      Result:=Result+Chr(M);
    inc(t,2);
  end;
end;


4.Timer4

Timer4用於記錄存儲用戶的電量到數據庫中。

4.1若數據庫中沒有本日的數據,那麼就要在每個表的數據表Table中新建一行當日的數據。

  ibquery1.SQL.Clear;
  ibquery1.SQL.Add('select count(*) from BH0 where U_year=:A and U_month=:B and U_day=:D');
  ibquery1.Params.ParamByName('A').Value := pNowYear;
  ibquery1.Params.ParamByName('B').Value := pNowMonth;
  ibquery1.Params.ParamByName('D').Value := pNowDay;
  ibquery1.Open;
  tempInt1 := ibquery1.FieldByName('count').Asinteger;//查詢看是否有用現在的年月做的行
  if tempInt1 = 0 then //如果等於0 說明沒有現在年月日的行
  begin
    for i := 0 to 9 do
    begin
      tempStr1 := inttoStr(i);//i代表表號
      ibquery1.SQL.Clear;
      ibquery1.SQL.Add('Insert into BH'+tempStr1+' Values(:B,:C,:D,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)');
      ibquery1.Params.ParamByName('B').Value := pNowYear;
      ibquery1.Params.ParamByName('C').Value := pNowMonth;
      ibquery1.Params.ParamByName('D').Value := pNowDay;
 ibquery1.ExecSQL; end;//部分代碼,不全

其中,爲SQL語句輸入變量的方法如上代碼段

      ibquery1.SQL.Add('Insert into BH'+tempStr1+' Values(:B,:C,:D,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)');
      ibquery1.Params.ParamByName('B').Value := pNowYear;
      ibquery1.Params.ParamByName('C').Value := pNowMonth;
      ibquery1.Params.ParamByName('D').Value := pNowDay;
      ibquery1.ExecSQL;

語句ibquery1.Params.ParamByName('B').Value :=?;中的?只需與數據表中的類型一致即可,不要求必須是字符型。
舉例來看:

    Form1.IBQuery1.sql.Add('Insert into loadmatrix(loadIndex,loadname,phase,har1,har3,har5,har7,har9)');
    Form1.IBQuery1.sql.Add('Values(:A,:B,:C,:D,:E,:F,:G,:H)');
    Form1.IBQuery1.Params.ParamByName('A').Value:=(maxIndex+1) ;//integer型
    Form1.IBQuery1.Params.ParamByName('B').Value:=editname.Text ;//char型
    Form1.IBQuery1.Params.ParamByName('C').Value:=strtofloat(editphase.Text) ;//float型

從這段代碼中不僅可以看出ibquery1.Params.ParamByName('B').Value :=?;語句的使用,也可以發現,使用IBQuery進行SQL語句傳輸時,還可以拆成兩句來書寫。

5.“開始”

工具欄中的“開始”按鈕,用來開啓串口,並且使能那些與串口有關的控件。

//==========================================================================================
procedure TForm1.toolButtonkaishiClick(Sender: TObject);{-----------------工具欄 開始 button}
begin
  comport1.Port := form4.ckCombo.Items[form4.ckCombo.ItemIndex];//由unit4選擇串口號
  comport1.BaudRate := br9600;
  ComPort1.Open;
  TeStatusBar1.Panels[1].Text := '運行';//在狀態欄顯示運行狀態
  timer3.Enabled:=true;
  timer4.enabled:=true;
  jdqButton.Enabled:=true;
  glckButton.Enabled:=true;
  glckjdqButton.Enabled:=true;
//timer1.Enabled:=true;
//上面這句在timer3中實現,即首次點擊“開始”,先發送一次數據,由timer3打開timer1
end;

因爲軟件串口的COM口和波特率是在form4(軟件設置)中設置的,因此串口控件Comport的port號要從form4中獲取,這裏我們看到了如何去下拉菜單的參數的方法。

從整體看,語句爲 Items[ ItemIndex ];

6.串口中斷

參考:http://blog.csdn.net/yorkworlddream/article/details/17384801

即自己編寫一個過程,將這個過程與ComPort1.ComPRxChar進行連接



之後在這個過程中對串口接收到的數進行處理即可。

這裏需要注意一下幾點:

1.若串口接收的是16進制數據,那麼使用ComPort1.ReadStr(Str, Count);語句將comport自動計數的count個數據存入了str中,comport的存儲方法是轉每一個16進制數爲一個字符,即收到十六進制68,存入str中的爲字符h,而不是字符串68。因此在後面使用copy的時候,要copy出68,只要copy(?,1);即可。

舉例,按照645規約的幀結構,取出表號的代碼爲:

  ComPort1.ReadStr(Str, Count);
  bhStr := copy(Str,2,1);//獲取表號。68算一個數,從第2個計算一個數,即爲表號00或01

2.對於功率等傳過來的4個字節16進制數,要轉爲float型,要使用一下函數:

  //64 e9 查功率幀返回
  if ansiSameText('64 e9',StrtoHexStr(orderStr)) then
  begin
    dataStr := copy(str,13,4);//取得該表數據字段,即功率
    dataStr := spaceprocess(StrToHexStr(dataStr));//先將16進制轉成字符串,之後去空格
    teedit1.Text := floattostr(HextoFloat(dataStr));//將十六進制字符轉成float,再成字符型進行顯示
  end;

先取出4字節的十六進制數據,之後將字符串轉成十六進制字符串,因爲就像上面說的,得到的十六進制68存的是h,並不是字符串68,因此要轉換一下,使用StrToHexStr,

之後去除字符串中的空格,比如C1 48 00 00字符串即被轉爲C1480000,

之後再使用十六進制字符串轉float函數,HexToFloat,將十六進制轉爲浮點型,

爲了顯示用,可以再將float轉爲字符串。

用流程表示上述轉換過程: 

收到的16進制數據---comport1.readStr---->

ascii對應的字符串----StrToHexStr----->

“68 00”這樣的字符串---spaceprocess---->

"6800"這樣的字符串----HexToFloat---->

float型數據------floatToStr------->

將float轉成字符串用於顯示

粘上各個函數的代碼:

StrToHexStr:

{字符串轉換成16進制字符串}
function StrToHexStr(const S:string):string;//字符串轉換成16進制字符串
var
  I:Integer;
begin
  for I:=1 to Length(S) do
  begin
    if I=1 then
      Result:=IntToHex(Ord(S[1]),2)
    else Result:=Result+' '+IntToHex(Ord(S[I]),2);
  end;
end;

spaceprocess:

{去字符串中的空格}
function SpaceProcess(S: String): String;
var
  i : Integer;
begin
  Result := '';
  for i := 1 to Length(S) do
  begin
    if S[i] <> ' ' then
    begin
      Result := Result + S[i];
    end;
  end;
end;
HexToFloat:

{二進制 to 十進制}
function BintoInt(Value: String): LongInt;
var
  i,Size: Integer;
begin
  Result:=0;
  Size:=Length(Value);
  for i:=Size downto 1 do
  begin
    if Copy(Value,i,1)='1' then
    Result:=Result+(1 shl (Size-i));
  end;
end;

function floatBintoInt(Value: String): real;
var
  i,Size: Integer;
begin
  Result:=0;
  Size:=Length(Value);
  for i:=Size downto 1 do
  begin
    if Copy(Value,i,1)='1' then
    Result:=Result+1/(1 shl i);
  end;
end;

{十六進制 to 二進制}
function HextoBinary(Hex:string):string;
const
  BOX: array [0..15] of string =
  ('0000','0001','0010','0011',
  '0100','0101','0110','0111',
  '1000','1001','1010','1011',
  '1100','1101','1110','1111');
var
  i:integer;
begin
  for i:=Length(Hex) downto 1 do
    Result:=BOX[StrToInt('$'+Hex[i])]+Result;
end;

{十六進制 to 十進制 浮點型}
function HextoFloat(s:string):real;
var
  b,temp:string;
  e:integer;
  f:real;
begin
  b:=HextoBinary(s);
  temp := copy(b,2,8);
  e:=BintoInt(temp)-127;
  temp := copy(b,10,23);
  f := 1+floatBintoInt(temp);
  if(copy(b,1,1)='0')then
    result := power(2,e)*f //------------------------------------------------要引用單元math
  else
    result :=-power(2,e)*f;
end;

7.數據庫連接

參考:http://blog.csdn.net/yorkworlddream/article/details/17473913

Char顯示數據參考:http://blog.csdn.net/yorkworlddream/article/details/17469487

還是笨方法:

//==========================================================================================
procedure TForm1.dlcxButtonClick(Sender: TObject);{-----------------電量曲線查詢 確定 button}
var
  i : integer;
  adayhour : array [1..24] of real;//設一個數組,用來放24小時的數據
  Time:TDateTime;//系統時間
  nowDate,nowYear,nowMonth,nowDay : string;//用來存放當前的系統時間
begin
  Time := now;//取當前時間
  nowDate := DateToStr(Time);
  nowYear:=leftStr(nowDate,4);//取年
  nowMonth:=copy(nowDate,6,2);//取月
  nowDay:=copy(nowDate,9,2);//取日
//  tememo2.Text := nowDate;
//  tememo1.Text := nowYear+nowMonth+nowDay;
  IBdatabase1.Connected:=true;
  IBquery1.Close;
  ibquery1.SQL.Clear;
  case dlcxCombo.ItemIndex of
    0:ibquery1.SQL.Add('select * from BH0 where u_day='+ nowDay +
                        'and u_month=' + nowMonth + 'and u_year=' + nowYear);//查詢當年月日的數據
    1:ibquery1.SQL.Add('select * from BH1 where u_day='+ nowDay +
                        'and u_month=' + nowMonth + 'and u_year=' + nowYear);
    2:ibquery1.SQL.Add('select * from BH2 where u_day='+ nowDay +
                        'and u_month=' + nowMonth + 'and u_year=' + nowYear);
    3:ibquery1.SQL.Add('select * from BH3 where u_day='+ nowDay +
                        'and u_month=' + nowMonth + 'and u_year=' + nowYear);
    4:ibquery1.SQL.Add('select * from BH4 where u_day='+ nowDay +
                        'and u_month=' + nowMonth + 'and u_year=' + nowYear);
    5:ibquery1.SQL.Add('select * from BH5 where u_day='+ nowDay +
                        'and u_month=' + nowMonth + 'and u_year=' + nowYear);
    6:ibquery1.SQL.Add('select * from BH6 where u_day='+ nowDay +
                        'and u_month=' + nowMonth + 'and u_year=' + nowYear);
    7:ibquery1.SQL.Add('select * from BH7 where u_day='+ nowDay +
                        'and u_month=' + nowMonth + 'and u_year=' + nowYear);
    8:ibquery1.SQL.Add('select * from BH8 where u_day='+ nowDay +
                        'and u_month=' + nowMonth + 'and u_year=' + nowYear);
    9:ibquery1.SQL.Add('select * from BH9 where u_day='+ nowDay +
                        'and u_month=' + nowMonth + 'and u_year=' + nowYear);
  end;
  ibquery1.Open;  //這時值已經放到IBQuery中了

  adayhour[1] := ibquery1.FieldByName('H1').AsFloat ;//按字段名取出數據,分別放到數組中
  adayhour[2] := ibquery1.FieldByName('H2').AsFloat ;//因爲數據類型不一樣,所以要加.asfloat
  adayhour[3] := ibquery1.FieldByName('H3').AsFloat ;
  adayhour[4] := ibquery1.FieldByName('H4').AsFloat ;
  adayhour[5] := ibquery1.FieldByName('H5').AsFloat ;
  adayhour[6] := ibquery1.FieldByName('H6').AsFloat ;
  adayhour[7] := ibquery1.FieldByName('H7').AsFloat ;
  adayhour[8] := ibquery1.FieldByName('H8').AsFloat ;
  adayhour[9] := ibquery1.FieldByName('H9').AsFloat ;
  adayhour[10] := ibquery1.FieldByName('H10').AsFloat ;
  adayhour[11] := ibquery1.FieldByName('H11').AsFloat ;
  adayhour[12] := ibquery1.FieldByName('H12').AsFloat ;
  adayhour[13] := ibquery1.FieldByName('H13').AsFloat ;
  adayhour[14] := ibquery1.FieldByName('H14').AsFloat ;
  adayhour[15] := ibquery1.FieldByName('H15').AsFloat ;
  adayhour[16] := ibquery1.FieldByName('H16').AsFloat ;
  adayhour[17] := ibquery1.FieldByName('H17').AsFloat ;
  adayhour[18] := ibquery1.FieldByName('H18').AsFloat ;
  adayhour[19] := ibquery1.FieldByName('H19').AsFloat ;
  adayhour[20] := ibquery1.FieldByName('H20').AsFloat ;
  adayhour[21] := ibquery1.FieldByName('H21').AsFloat ;
  adayhour[22] := ibquery1.FieldByName('H22').AsFloat ;
  adayhour[23] := ibquery1.FieldByName('H23').AsFloat ;
  adayhour[24] := ibquery1.FieldByName('H24').AsFloat ;
  series1.Clear;//要先清空series,要不他會總add
  with series1 do
  begin
    for i := 1 to 24 do
      add(adayhour[i]);
  end;
end;

取出數據庫返回的值使用語句 ibquery1.FieldByName('?'),要是返回的是 float 則加入 .AsFloat 即可。

8.IOComp工控指示燈

這個指示燈的關閉狀態和激發狀態是由

來控制的

使用語句

jdqled0.Active:=ansiSameText('01',strtohexstr(dataStr));//若數據字段爲01則說明jdq開

就可以開關指示燈,函數ansiSameText是字符串比較函數,返回值爲true或者false。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章