【乌拉喵.教程】“多负载识别监控平台(上位机)”技术细节 之Unit1-Form1主界面

简介: 【乌拉喵.教程】“多负载识别监控平台(上位机)”技术细节 之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函数,参考用Delphi获取当前系统时间_乌拉大喵喵-CSDN博客_delphi获取当前时间


使用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.串口中断

参考:Comport4 CPort for delphi2010串口应用程序_乌拉大喵喵-CSDN博客

即自己编写一个过程,将这个过程与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.数据库连接

参考:InterBase7.0数据库的建立且与Delphi2010的连接_乌拉大喵喵-CSDN博客

Char显示数据参考:使用TDBChart显示InterBase数据库的一行数据_乌拉大喵喵-CSDN博客

还是笨方法:

//==========================================================================================
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。


相关文章
WRF模式案例运行初体验--飓风示例全过程记录
本文主要记录一下首次学习WRF并运行官网案例的全过程。
WRF模式案例运行初体验--飓风示例全过程记录
|
7月前
|
JavaScript Java 测试技术
基于微信小程序的外卖点餐系统的设计与实现(源码+lw+部署文档+讲解等)
基于微信小程序的外卖点餐系统的设计与实现(源码+lw+部署文档+讲解等)
130 0
|
7月前
|
安全 Java 测试技术
在线音乐播放系统的设计与实现(论文+源码)_kaic
在线音乐播放系统的设计与实现(论文+源码)_kaic
|
7月前
|
存储
医院PACS系统全套源码 强大的三维重建功能
对非DICOM影像,如超声、病理、心电图等进行了集成,做到了可以同时处理DICOM标准图像和非DICOM图像。
62 1
|
测试技术
【测试平台系列】第一章 手撸压力机(十)-定义场景
上一章,咱们对http请求进行了一些优化,本章节我们将组成场景去运行。首先场景就是一连串的http接口的请求,我们使用list(列表)来组装成一个场景
【测试平台系列】第一章 手撸压力机(十)-定义场景
|
存储 JSON 搜索推荐
【测试平台系列】第一章 手撸压力机(十二)-初步实现提取功能
上一章节,我们主要实现了基础的并发测试场景的能力。本章节,我们实现一下,如何对响应进行提取,使用正则/json对响应信息提取,并赋值给我们定义的变量。
|
存储 BI 数据安全/隐私保护
PACS系统源码 大型医院PACS/RIS源码 支持专业三维影像后处理功能,演示文档齐全
PACS系统可实现检查预约、病人信息登记、计算机阅片、电子报告书写、胶片打印、报表统计、数据备份等一系列满足影像科室日常工作的功能,并且由于影像数字化存储,用户可利用影像处理与测量技术辅助诊断、方便快捷地查找资料或利用网络将资料传输至临床科室,还可与医院HIS、LIS无缝连接。集成专业三维影像后处理功能:三维多平面重建、三维容积重建、三维表面重建、三维虚拟内窥镜、最大/小密度投影、心脏动脉钙化分析等。
158 0
PACS系统源码 大型医院PACS/RIS源码 支持专业三维影像后处理功能,演示文档齐全
|
监控 数据库
【乌拉喵.教程】“多负载识别监控平台(上位机)”技术细节 之Unit4-Form4系统设置界面
【乌拉喵.教程】“多负载识别监控平台(上位机)”技术细节 之Unit4-Form4系统设置界面
118 0
|
SQL 监控 数据库
【乌拉喵.教程】“多负载识别监控平台(上位机)”技术细节 之Unit2-Form2用户电量查询显示界面
【乌拉喵.教程】“多负载识别监控平台(上位机)”技术细节 之Unit2-Form2用户电量查询显示界面
100 0
|
监控
【乌拉喵.教程】“多负载识别监控平台(上位机)”技术细节 之Unit3-Form3用户负载类型查询界面
【乌拉喵.教程】“多负载识别监控平台(上位机)”技术细节 之Unit3-Form3用户负载类型查询界面
100 0