找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 4097|回复: 0
打印 上一主题 下一主题
收起左侧

寝室电量提示系统(1)—上位机的编写

[复制链接]
跳转到指定楼层
楼主
ID:73735 发表于 2015-2-19 01:12 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 huge 于 2015-2-19 01:14 编辑

本例程的下位机单片机程序和视频详见:http://www.51hei.com/bbs/dpj-31602-1.html      本来这次是想写一个类似QQ尾巴的程序,不过好像有点难,所以就先缓一缓,做了个这个:寝室电量提示系统。大概流程:使用软件(上位机)打开一个记录有寝室电量信息的Access文件,查询低于一定电量的寝室,再将这些寝室号或时间信息通过RS232接口发送到点阵LED上显示;不使用时,点阵LED平时当作时钟使用。

首先是上位机的编写。和以往一样,我还是选delphi平台来编写。
【程序界面布局



整个程序分为串口和数据库查询两部分。其中通信协议设置(均以十六进制发送、接收):
①PC发送数据包格式:
   (1)  发送显示的数据组数:BB+AF+发送数据的组数(H)+00+00+00+00+00++00+AF+EE ;
   (2)  发送时间:                  BB+A2+14(20)+0C(12)+0B(11)+0A(10)+0D(13)+0E(14)+0B(11)+A2与月(0B)的异或+EE ;
                                             (即2012-11-10 13:14:11)
   (3)  发送寝室号:              BB+A8+00+03+06+02+03+00+00+A8与“寝室号03620”的“6”(06H)异或+EE ;
②单片机应答数据包格式:   BB+AA+00/01+00+00+00+00+00+00+AA+EE
                                             (其中第三个数据00/01:00表示显示成功;01表示显示失败)
【代码】

unit Unit1;
interface
uses
  Windows, Messages, SysUtils, Variants, Classes,
Graphics, Controls, Forms,
  Dialogs, ExtCtrls, SPComm, StdCtrls,  sBevel, Grids, DBGrids,
  dbcgrids, DB, ADODB, sSkinManager, SGridFunction, AdoConEd, sLabel,
  ComCtrls,Menus,ScrollText, acTitleBar, ImgList,
  acAlphaImageList, sCheckBox;
type
    TForm1 = class(TForm)
    Ports: TComboBox;
    Baud: TComboBox;
    Parity_bit: TComboBox;
    Data_bits: TComboBox;
    Label2: TLabel;
    Label3: TLabel;
    Label4: TLabel;
    Label5: TLabel;
    Senddisp: TButton;
    Connect: TButton;
    Stop_bit: TComboBox;
    Label6: TLabel;
    Comm1: TComm;
    Image1: TImage;
    Label7: TLabel;
    Label8: TLabel;
    Battery: TEdit;
    Total: TEdit;
    Image2: TImage;
    StringGrid1: TStringGrid;
    ADOQuery1: TADOQuery;
    sSkinManager1: TsSkinManager;
    ADOConnection1: TADOConnection;
    Time: TsLabelFX;
    Timer1: TTimer;
    Time_settle: TsCheckBox;
    MainMenu1: TMainMenu;
    Database_set: TMenuItem;
    Open_database: TMenuItem;
    About: TMenuItem;
    sBevel1: TsBevel;

    Search: TButton;
    Quit: TMenuItem;
    ScrollText1: TScrollText;
    sAlphaImageList1: TsAlphaImageList;
    Timer2: TTimer;
    procedure FormCreate(Sender: TObject);
    procedure PortsChange(Sender: TObject);
    procedure BaudChange(Sender: TObject);
    procedure Parity_bitChange(Sender: TObject);
    procedure Data_bitsChange(Sender: TObject);
    procedure Stop_bitChange(Sender: TObject);
    procedure ConnectClick(Sender: TObject);
    procedure SenddispClick(Sender: TObject);
    procedure BatteryKeyPress(Sender: TObject; var Key: Char);
    procedure Timer1Timer(Sender: TObject);
    procedure Open_databaseClick(Sender: TObject);
    procedure AboutClick(Sender: TObject);
    procedure SearchClick(Sender: TObject);
    procedure QuitClick(Sender: TObject);
    procedure Timer2Timer(Sender: TObject);
    procedure Comm1ReceiveData(Sender: TObject; Buffer: Pointer;
      BufferLength: Word);
  private
    { Private declarations }
    procedure EnumComPorts(Ports: TStrings);
    procedure SendString(const str:string);
    function StrToHexStr(const S:string):string;
    function HexStrToStr(const S:string):string;
  public
    { Public declarations }
  end;
var
  Form1: TForm1;
  SysTime:TSystemTime;
  i,i0:Integer;
implementation

{$R *.dfm}
{ TForm1 }

procedure TForm1.EnumComPorts(Ports: TStrings);       //获取当前可用的串口
var
  KeyHandle: HKEY;
  ErrCode, Index: Integer;
  ValueName, Data: string;
  ValueLen, DataLen, ValueType: DWORD;
  TmpPorts: TStringList;
  Tmp4,Tmp5:TStringList;
begin
  ErrCode:= RegOpenKeyEx(HKEY_LOCAL_MACHINE,'HARDWARE\DEVICEMAP\SERIALCOMM',0,KEY_READ,KeyHandle);  if ErrCode <> ERROR_SUCCESS then
    ShowMessage('打开串口列表的注册表项出错');
  TmpPorts := TStringList.Create;
  Tmp4:= TStringList.Create;
  Tmp5 := TstringList.Create;
  try
    Index := 0;
    repeat
      ValueLen := 256;
      DataLen := 256;
      SetLength(ValueName, ValueLen);
      SetLength(Data, DataLen);
      ErrCode := RegEnumValue(KeyHandle, Index, PChar(ValueName),
        Cardinal(ValueLen), nil, @ValueType, PByte(PChar(Data)), @DataLen);
      if ErrCode = ERROR_SUCCESS then
      begin
        SetLength(Data, DataLen);
        TmpPorts.Add(Trim(Data));
        Inc(Index);
      end
      else if ErrCode <> ERROR_NO_MORE_ITEMS then
        ShowMessage('打开串口列表的注册表项出错');
    until (ErrCode <> ERROR_SUCCESS);
    TmpPorts.Sort;
    For Index:=0 To TmpPorts.Count-1 do
       begin
       if Length(TmpPorts[Index])<=4 then  // 'COM3'
          Tmp4.Add(TmpPorts[Index])
         else Tmp5.Add(TmpPorts[Index]);
       end;
    Tmp4.AddStrings(Tmp5);
    //Ports.Assign(TmpPorts);
    Ports.Assign(Tmp4);
  finally
    RegCloseKey(KeyHandle);
    TmpPorts.Free;
    Tmp4.Free;
    Tmp5.Free;
  end;
end;

function TForm1.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 (t<=Length(S)) and (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;

procedure TForm1.SendString(const str: string);
begin
  Comm1.WriteCommData(Pchar(str),Length(str));
end;

function TForm1.StrToHexStr(const S: string): string;          //字符串转换成16进制字符串
var
  I:Integer;
begin
  for I:=1 to Length(S) do
  begin
    if I=1 then
      Result:=IntToHex(StrToInt(S[1]),2)
    else Result:=Result+' '+IntToHex(StrToInt(S[I]),2);
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);//初始化窗口
begin
  Self.DoubleBuffered:= True;
  ScrollText1.ScrollText:='------欢迎使用寝室电量提示系统 O(∩_∩)O~';
  StringGrid1.Cells[0, 0]:='序号';
  StringGrid1.Cells[1, 0]:='缺电寝室号';
  StringGrid1.Cells[2, 0]:='剩余电量(度)';
  EnumComPorts(Ports.Items);
  Ports.ItemIndex:=0;
  Comm1.CommName:=Ports.Text;
  Baud.ItemIndex:=5;
  Comm1.BaudRate:=StrToIntDef(Baud.Text,Comm1.BaudRate);
  Parity_bit.ItemIndex:=2;
  Comm1.Parity:=None;
  Data_bits.ItemIndex:=3;
  Comm1.ByteSize:=_8;
  Stop_bit.ItemIndex:=0;
  Comm1.StopBits:=_1;
end;

procedure TForm1.PortsChange(Sender: TObject);           //端口选项
begin
  Comm1.CommName:=Ports.Text;
end;

procedure TForm1.BaudChange(Sender: TObject);           //波特率选项
begin
  Comm1.BaudRate:=StrToIntDef(Baud.Text,Comm1.BaudRate)
end;

procedure TForm1.Parity_bitChange(Sender: TObject);       //校验位选项
begin
  case Parity_bit.ItemIndex of
    0:Comm1.Parity:=Even;
    1:Comm1.Parity:=Mark;
    2:Comm1.Parity:=None;
    3:Comm1.Parity:=Odd;
    4:Comm1.Parity:=Space;
  end;
end;

procedure TForm1.Data_bitsChange(Sender: TObject);     //数据位选项
begin
  case Data_bits.ItemIndex of
    0:Comm1.ByteSize:=_5;
    1:Comm1.ByteSize:=_6;
    2:Comm1.ByteSize:=_7;
    3:Comm1.ByteSize:=_8;
  end;
end;

procedure TForm1.Stop_bitChange(Sender: TObject);      //停止位选项
begin
  case Stop_bit.ItemIndex of
    0:Comm1.StopBits:=_1;
    1:Comm1.StopBits:=_1_5;
    2:Comm1.StopBits:=_2;
  end;
end;

procedure TForm1.ConnectClick(Sender: TObject);       //连接串口按钮事件
begin
  if Connect.Caption='连接串口' then
    begin
      Comm1.StartComm;
      Connect.Caption:='关闭串口';
      Image1.Visible:=false;
      Image2.Visible:=true;
      Ports.Enabled:=false;
      Baud.Enabled:=false;
      Parity_bit.Enabled:=false;
      Data_bits.Enabled:=false;
      Stop_bit.Enabled:=false;
      Senddisp.Enabled:=true;
    end
  else
    begin
      Comm1.StopComm;
      Connect.Caption:='连接串口';
      Image1.Visible:=true;
      Image2.Visible:=false;
      Ports.Enabled:=true;
      Baud.Enabled:=true;
      Parity_bit.Enabled:=true;
      Data_bits.Enabled:=true;
      Stop_bit.Enabled:=true;
      Senddisp.Enabled:=false;
    end;
end;

procedure TForm1.SenddispClick(Sender: TObject);
var
  strdata,stryear1,stryear0,strmonth,strday,strhour,strminute,strsecond:string;
begin
  if Time_settle.Checked=true then
    begin
      stryear1:=IntToHex(StrToInt(copy(IntToStr(SysTime.wYear),1,2)),2);
      stryear0:=IntToHex(StrToInt(copy(IntToStr(SysTime.wYear),3,2)),2);
      strmonth:=IntToHex(SysTime.wMonth,2);
      strday:=IntToHex(SysTime.wDay,2);
      strhour:=IntToHex(SysTime.wHour,2);
      strminute:=IntToHex(SysTime.wMinute,2);
      strsecond:=IntToHex(SysTime.wSecond,2);
      strdata:=HexStrToStr('BBA2'+stryear1+stryear0+strmonth+strday+strhour+strminute+strsecond+IntToHex(SysTime.wMonth Xor $A2,2)+'EE');
      if (trim(Total.Text) = '') or (trim(Total.Text) = '0') then
        begin
          SendString(HexStrToStr('BBAF01000000000000AFEE'));
            //格式 BB+AF+发送数据的组数(H)+00+00+00+00+00++00+AF+EE
          sleep(200);
          SendString(strdata);
            //格式 BB+A2+20+12+11+10+13+14+11+A2与月的异或+EE
          Timer2.Enabled:=false;
        end
      else
        begin
          i0:=StrToInt(Total.Text);
          SendString(HexStrToStr('BBAF'+IntToHex(i0+1,2)+'000000000000AFEE'));
            //格式 BB+AF+发送数据的组数(H)+00+00+00+00+00++00+AF+EE
          i:=1;
          sleep(200);
          SendString(strdata);
            //格式 BB+A2+14(20)+0C(12)+0B(11)+0A(10)+0D(13)+0E(14)+0B(11)+A2与月(0B)的异或+EE
          sleep(200);
          Timer2.Enabled:=true;
        end;
    end
  else
    begin
      if (trim(Total.Text) = '') or (trim(Total.Text) = '0') then
        Application.MessageBox('数据无效,无法发送!','警告',MB_ICONWARNING)
      else
        begin
          i0:=StrToInt(Total.Text);
          SendString(HexStrToStr('BBAF'+IntToHex(i0,2)+'000000000000AFEE'));
            //格式 BB+AF+发送数据的组数(H)+00+00+00+00+00++00+AF+EE
          i:=1;
          sleep(200);
          Timer2.Enabled:=true;
        end;
    end;
end;

procedure TForm1.BatteryKeyPress(Sender: TObject; var Key: Char);
begin
  if not (Key in ['0'..'9',#8]) then Key:=#0;
end;

procedure TForm1.Timer1Timer(Sender: TObject); //显示当前时间,每隔1s更新一次
begin
  GetLocalTime(SysTime);
  Time.Caption:=IntToStr(SysTime.wYear)+'年'+Format('%.2d',[SysTime.wMonth])+'月'+Format('%.2d',[SysTime.wDay])+'日  '+Format('%.2d',[SysTime.wHour])+':'+Format('%.2d',[SysTime.wMinute])+':'+Format('%.2d',[SysTime.wSecond]);
end;

procedure TForm1.Open_databaseClick(Sender: TObject);
var
  constr: string;
begin
  if ( constr <> '') then
    ADOConnection1.ConnectionString := constr;
  if (EditConnectionString(ADOConnection1)) then//调用数据源窗口,判断是否连接成功
    begin
      ADOConnection1.Connected:=False;
      ADOConnection1.Connected:=True;
      constr := ADOConnection1.ConnectionString;
      Search.Enabled:=true;
    end
  else
    begin
      constr := ADOConnection1.ConnectionString;
      ADOConnection1.ConnectionString := '';
    end;
end;


procedure TForm1.AboutClick(Sender: TObject);
begin
  Application.MessageBox('       ☆     寝室电量提示系统     ☆'+#13#13+
  '             Agent CopyRight@2012    '+#13+
  '                        by hun       ','关于',MB_OK);
end;

procedure TForm1.SearchClick(Sender: TObject);
begin
  ADOConnection1.Connected:=true;
  with ADOQuery1 do
  begin
    Close;
    SQL.Clear;
    SQL.Add('SELECT * FROM Sheet1  WHERE Battery <='+Battery.Text);  // 查询数据库
    Open;
  end;
  ShowQueryData(StringGrid1,ADOQuery1,0,1);
  if HaveData(StringGrid1, 1, 1)=false then
    Total.Text:='0'
  else
  Total.Text:=SetNumberFields(StringGrid1,0,1);
  ADOConnection1.Connected:=false;
end;

procedure TForm1.QuitClick(Sender: TObject);
begin
  if Application.MessageBox('您确定要退出吗?','警告',MB_YESNO or MB_DEFBUTTON1)=IDYES then
    begin
      Application.Terminate;
    end;
end;

procedure TForm1.Timer2Timer(Sender: TObject);

begin
  SendString(HexStrToStr('BBA8'+StrToHexStr(Format('%.5d',[StrToInt(StringGrid1.Cells[1, i])]))+'0000'+IntToHex(StrToInt('$'+StrToHexStr(copy(StringGrid1.Cells[1, i],Length(StringGrid1.Cells[1, i])-2,1))) Xor $A8,2)+'EE'));
    //格式 BB+A8+00+03+06+02+03+00+00+A8与03620的06h异或+EE
  i:=i+1;
  if i>i0 then
    Timer2.Enabled:=false;
end;

procedure TForm1.Comm1ReceiveData(Sender: TObject; Buffer: Pointer;
  BufferLength: Word);
var
  rbuf:array[0..10] of Byte;
begin
  move(Buffer^,pchar(@rbuf)^,BufferLength);
  if (rbuf[1]<>rbuf[9]) or (inttohex(rbuf[2],2)='01') then
    Application.MessageBox('显示失败!','提示信息',MB_OK)
  else
    begin
      if inttohex(rbuf[2],2)='00' then
        Application.MessageBox('显示成功!','提示信息',MB_OK)
      else
        Application.MessageBox('显示失败!','提示信息',MB_OK);
    end;
end;

end.

【查询效果】

在编写下位机的过程中,发现端口的设置有点多余,所以又重新布局,于是诞生了精简版:











分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表