delphi2010调用HC RF 非接触式 IC 卡读写器代码

本文代码仅适用于GH-230Z -YKT型号读卡器,用来读写感应式M1卡。一般都可以从硬件购买店铺获得对应的sdk开发包,我这个算是接收别人的项目,已经把读卡器的相关逻辑做了二次封装,现在有些操作逻辑需要更原始的数据操作实现不了,后面就直接想办法联系到了这款读卡器的厂家要到了相关SDK开发包,但是里面的delphi demo是基于delphi7的,我现在测试用的delphi是2010版本,有的dll函数可以调用有的又不行,就花了几天时间改动了下(其实dll调用都是比较标准的方法,主要还是delphi不同版本 函数参数类型的问题导致的)。

一、密钥加载函数rf_load_key_hex改动如下

 far;external 'hcrf32.dll' name 'rf_load_key';
  //function rf_load_key_hex(icdev:longint;mode,secnr:smallint;nkey:pchar):smallint;stdcall;        // 原来的

  function rf_load_key_hex(icdev:Integer;mode,secnr:Short;nkey:PAnsiChar):Short;stdcall;

二、写卡rf_write_hex函数改动如下(hex方式)


 // function rf_write_hex(icdev:longint;adr:smallint;data:PChar):smallint;stdcall;        // 原来的
  function rf_write_hex(icdev:Integer;adr:Short;data:PAnsiChar):Short;stdcall;
  far;external 'hcrf32.dll' name 'rf_read_hex';

三、使用对应函数片段

var 
     nkeynew,StrPtr: PAnsiChar; 
     StrPtr: PAnsiChar;
begin
     nkeynew:='FFFFFFFFFFFF';
     st:=rf_load_key_hex(icdev,loadmode,sector, nkeynew);       //装载密钥到读卡器中
    //st:=0;
     if st<>0 then
        listbox1.items.add('load key error')
     else
        listbox1.items.add('load key Ok');
     //  ----这里省略一些验密等过程
     wdatanew:='b1b2b3b4ffffffffffffffffffffffff';         //0-9,A-F 的hex格式长度固定32
     AssignStringToAnsiChar(wdatanew,StrPtr);//转化函数
     st:=rf_write_hex(icdev,block,StrPtr);
     if st<>0 then
        listbox1.items.add('write hex error')
     else
        listbox1.items.add('write hex Ok');

用到的转化函数

  procedure AssignStringToAnsiChar(text: string; var AnsiCharVar: PAnsiChar);
var

  AnsiText: AnsiString;
begin

  // 将 Delphi 字符串转换为 ANSI 字符串
  AnsiText := AnsiString(text);

  // 分配内存来存储 ANSI 字符串(包括结尾的空字符)
  GetMem(AnsiCharVar, Length(AnsiText) + 1);

  // 将 ANSI 字符串复制到分配的内存中
  StrPCopy(AnsiCharVar, AnsiText);
end;

四、整个”HC RF开发包 V1.4ExampleDelphi7“中rfexamp.pas改编后的完整代码

unit rfexamp;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls,StrUtils;

type
  TForm1 = class(TForm)
    ListBox1: TListBox;
    Button1: TButton;
    Label1: TLabel;
    Button2: TButton;
    Edit1: TEdit;
    procedure FormShow(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure Button1Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);


  private
    { Private declarations }
  public
    { Public declarations }
  end;



var
  Form1: TForm1;
  icdev: longint;
  snr:longint;
  nkey,wdata,sendblock:pchar;
  st,sector,block,loadmode:smallint;
  status:Array[0..18]of Char;
  databuff:Array[0..15]of Char;
  ack:Array[0..255]of Char;
  datahex:Array[0..31]of Byte;
  wdatanew:string;
  MyWideChar: PWideChar;
    MyString: UnicodeString ;


  {a example for your to try using .dll. add_s return i+1}
  function add_s(i: smallint): smallint; stdcall;
  far;external 'hcrf32.dll' name 'add_s';
  {comm function.}
  //function hc_init(port: smallint;baud:longint): longint; stdcall;    // 原来的
   function hc_init(port: Short;baud:Integer): Integer; stdcall;
  far;external 'hcrf32.dll' name 'hc_init';
  function hc_exit(icdev: longint):smallint;stdcall;
  far;external 'hcrf32.dll'name 'hc_exit';
  function rf_encrypt(key:pchar;ptrsource:pchar;msglen:smallint;ptrdest:pchar):smallint;stdcall;
  far;external 'hcrf32.dll' name 'rf_encrypt';
  function rf_decrypt(key:pchar;ptrsource:pchar;msglen:smallint;ptrdest:pchar):smallint;stdcall;
  far;external 'hcrf32.dll' name 'rf_decrypt';
  //
  //function rf_card(icdev:longint;mode:smallint;snr:pChar):smallint;stdcall;  // 原来的
  function rf_card(icdev:Integer;mode:Short;snr:PAnsiChar):Short;stdcall;

  far;external 'hcrf32.dll'name 'rf_card';
  function rf_load_key(icdev:longint;mode,secnr:smallint;nkey:pchar):smallint;stdcall;
  far;external 'hcrf32.dll' name 'rf_load_key';
  //function rf_load_key_hex(icdev:longint;mode,secnr:smallint;nkey:pchar):smallint;stdcall;        // 原来的
  function rf_load_key_hex(icdev:Integer;mode,secnr:Short;nkey:PAnsiChar):Short;stdcall;

  far;external 'hcrf32.dll' name 'rf_load_key_hex';
  function rf_authentication(icdev:longint;mode,secnr:smallint):smallint;stdcall;
  far;external 'hcrf32.dll' name 'rf_authentication';
  //
  function rf_read(icdev:longint;adr:smallint;data:pchar):smallint;stdcall;
  far;external 'hcrf32.dll' name 'rf_read';
  //function rf_read_hex(icdev:longint;adr:smallint;data:pchar):smallint;stdcall; //原来的
   function rf_read_hex(icdev:Integer;adr:Short;data:PAnsiChar):Short;stdcall;

  far;external 'hcrf32.dll' name 'rf_read_hex';
  function rf_write(icdev:longint;adr:smallint;data:pchar):smallint;stdcall;
  far;external 'hcrf32.dll' name 'rf_write';
 // function rf_write_hex(icdev:longint;adr:smallint;data:PChar):smallint;stdcall;        // 原来的
  function rf_write_hex(icdev:Integer;adr:Short;data:PAnsiChar):Short;stdcall;

  far;external 'hcrf32.dll' name 'rf_write_hex';
  function rf_halt(icdev:longint):smallint;stdcall;
  far;external 'hcrf32.dll' name 'rf_halt';
  function rf_reset(icdev:longint;msec:smallint):smallint;stdcall;
  far;external 'hcrf32.dll' name 'rf_reset';
  //M1 CARD
  function rf_initval(icdev:longint;adr:smallint;value:longint):smallint;stdcall;
  far;external 'hcrf32.dll' name 'rf_initval';
  function rf_readval(icdev:longint;adr:smallint;value:pchar):smallint;stdcall;
  far;external 'hcrf32.dll' name 'rf_readval';
  function rf_increment(icdev:longint;adr:smallint;value:longint):smallint;stdcall;
  far;external 'hcrf32.dll' name 'rf_increment';
  function rf_decrement(icdev:longint;adr:smallint;value:longint):smallint;stdcall;
  far;external 'hcrf32.dll' name 'rf_decrement';
  function rf_restore(icdev:longint;adr:smallint):smallint;stdcall;
  far;external 'hcrf32.dll' name 'rf_restore';
  function rf_transfer(icdev:longint;adr:smallint):smallint;stdcall;
  far;external 'hcrf32.dll' name 'rf_transfer';
  function rf_check_write(icdev,snr:longint;adr,authmode:smallint;data:pchar):smallint;stdcall;
  far;external 'hcrf32.dll' name 'rf_check_write';
  function rf_check_writehex(icdev,snr:longint;adr,authmode:smallint;data:pchar):smallint;stdcall;
  far;external 'hcrf32.dll' name 'rf_check_writehex';
  function rf_changeb3(Adr:pchar;keyA:pchar;B0:pchar;B1:pchar;B2:pchar;B3:pchar;Bk:pchar;KeyB:pchar):smallint;stdcall;
  far;external 'hcrf32.dll' name 'rf_changeb3';
  //DEVICE
  //function rf_get_status(icdev:longint;status:pchar):smallint;stdcall;  // 原来的
  function rf_get_status(icdev:Integer;status: PAnsiChar):Short;stdcall;

  far;external 'hcrf32.dll' name 'rf_get_status';
  function rf_beep(icdev:longint;time:smallint):smallint;stdcall;
  far;external 'hcrf32.dll' name 'rf_beep';
  function rf_ctl_mode(icdev:longint;ctlmode:smallint):smallint;stdcall;
  far;external 'hcrf32.dll' name 'rf_ctl_mode';
  function rf_disp_mode(icdev:longint;mode:smallint):smallint;stdcall;
  far;external 'hcrf32.dll' name 'rf_disp_mode';
  function rf_disp8(icdev:longint;len:longint;disp:pchar):smallint;stdcall;
  far;external 'hcrf32.dll' name 'rf_disp8';
  function rf_disp(icdev:longint;pt_mode:smallint;disp:longint):smallint;stdcall;
  far;external 'hcrf32.dll' name 'rf_disp';
  //
  function rf_settimehex(icdev:longint;dis_time:pchar):smallint;stdcall;
  far;external 'hcrf32.dll' name 'rf_settimehex';
  function rf_gettimehex(icdev:longint;dis_time:pchar):smallint;stdcall;
  far;external 'hcrf32.dll' name 'rf_gettimehex';
  function rf_swr_eeprom(icdev:longint;offset,len:smallint;data:pchar):smallint;stdcall;
  far;external 'hcrf32.dll' name 'rf_swr_eeprom';
  function rf_srd_eeprom(icdev:longint;offset,len:smallint;data:pchar):smallint;stdcall;
  far;external 'hcrf32.dll' name 'rf_srd_eeprom';
  //ML CARD
  function rf_authentication_2(icdev:longint;mode,keyNum,secnr:smallint):smallint;stdcall;
  far;external 'hcrf32.dll' name 'rf_authentication_2';
  function rf_initval_ml(icdev:longint;value:longint):smallint;stdcall;
  far;external 'hcrf32.dll' name 'rf_initval_ml';
  function rf_readval_ml(icdev:longint;rvalue:pchar):smallint;stdcall;
  far;external 'hcrf32.dll' name 'rf_readval_ml';
  function rf_decrement_transfer(icdev:longint;adr:smallint;value:longint):smallint;stdcall;
  far;external 'hcrf32.dll' name 'rf_decrement_transfer';



  function rf_pro_rst(icdev:longint;_Data:pChar):smallint;stdcall;
  far;external 'hcrf32.dll' name 'rf_pro_rst';
  function rf_pro_trn(icdev:longint;problock,recv:pChar):smallint;stdcall;
  far;external 'hcrf32.dll' name 'rf_pro_trn';
  function rf_pro_halt(icdev:longint):smallint;stdcall;
  far;external 'hcrf32.dll' name 'rf_pro_halt';
  function hex_a(hex,a:pChar;length:smallint):smallint;stdcall;
  far;external 'hcrf32.dll' name 'hex_a';
  function a_hex(a,hex:pChar;length:smallint):smallint;stdcall;
  far;external 'hcrf32.dll' name 'a_hex';
implementation

{$R *.DFM}
  Function Trans(Msg: string): string;
  var
    TempPchar: Pchar;
    i: integer;
    Str: string;
  begin
    TempPchar := Pchar(Msg); //将字符串 Char数组化
    i := 0;
    Str := '';
    while i < length(TempPchar) do begin
      Str :=  TempPchar[i] + TempPchar[i+1]+ Str ;
      i := i + 2;
    end;
    result := Str;
  end;

 procedure AssignEditTextToAnsiChar(Edit: TEdit; var AnsiCharVar: PAnsiChar);
var
  EditText: string;
  AnsiText: AnsiString;
begin
  // 获取 TEdit 控件中的文本
  EditText := Edit.Text;

  // 将 Delphi 字符串转换为 ANSI 字符串
  AnsiText := AnsiString(EditText);

  // 分配内存来存储 ANSI 字符串(包括结尾的空字符)
  GetMem(AnsiCharVar, Length(AnsiText) + 1);

  // 将 ANSI 字符串复制到分配的内存中
  StrPCopy(AnsiCharVar, AnsiText);
end;

  procedure AssignStringToAnsiChar(text: string; var AnsiCharVar: PAnsiChar);
var

  AnsiText: AnsiString;
begin

  // 将 Delphi 字符串转换为 ANSI 字符串
  AnsiText := AnsiString(text);

  // 分配内存来存储 ANSI 字符串(包括结尾的空字符)
  GetMem(AnsiCharVar, Length(AnsiText) + 1);

  // 将 ANSI 字符串复制到分配的内存中
  StrPCopy(AnsiCharVar, AnsiText);
end;



 function AnsiCharToHex(AnsiChar: PAnsiChar): string;
var
  i: Integer;
  Byte1: Byte;
  HexStr: string;
begin
  Result := '';
  if AnsiChar <> nil then
  begin
    // 遍历 ANSI 字符串中的每个字节
    i := 0;
    while AnsiChar[i] <> #0 do // #0 是 ANSI 字符串的结束符
    begin
      Byte1 := Byte(AnsiChar[i]); // 获取当前字节的值
      HexStr := IntToHex(Byte1, 2); // 将字节转换为两位十六进制字符串
      Result := Result + HexStr; // 添加到结果字符串中
      Inc(i); // 继续下一个字节
    end;
  end;
end;

function AnsiStringToHex(const Input: AnsiString): string;
var
  i: Integer;
  Byte1: Byte;
  HexStr: string;
begin
  Result := '';
  for i := 1 to Length(Input) do
  begin
    Byte1 := Byte(Input[i]); // 获取当前字符的 ANSI 编码字节
    HexStr := IntToHex(Byte1, 2); // 将字节转换为两位十六进制字符串
    Result := Result + HexStr; // 添加到结果字符串中
  end;
end;


function ByteArrayToHex(const data: array of Byte): string;
var
    hexString: string;
    i: Integer;
begin
  Result := '';
    SetLength(hexString, 2 * Length(data)); // 预先分配足够的空间
    for i := Low(data) to High(data) do
    begin
        // 使用位操作获取高位和低位十六进制数字,并转换为字符串
        //hexString[2 * i + 1] := IntToHex(data[i] ,2); // 低位字符
       // hexString[2 * i] := IntToHex(data[i] shr 4)[1]; // 高位字符
     //  hexString := IntToHex(data[i], 2); // 将字节转换为两位十六进制字符串
     // Result := Result + hexString; // 添加到结果字符串中
     //  Result := Result +'['+IntToStr(i)+']'+IntToHex(Integer(data[i]),1)+'----intstr'+char(data[i]);
        Result := Result +char(data[i]);
    // Writeln(data[i]);

    end;
     //i :=i+1;
   // Result := hexString;
end;




procedure TForm1.FormShow(Sender: TObject);
begin
  //icdev:=hc_init(0,115200);              //串口1 波特率115200
  icdev:=hc_init(1000,115200);         //:取值为 0~19 时,表示串口 1~20;为 100 或大于 100,表示 USB 口通讯,此时波特率参数无效。
  if icdev<=0 then
      listbox1.Items.Add('Init error');

  st:=rf_get_status(icdev,@status);
   if st<>0 then
      listbox1.Items.Add('Init ERR')
   else
      listbox1.Items.Add('Init OK');
      listbox1.Items.Add('Hard Ver: '+ status);
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
if icdev>0 then
st:=hc_exit(icdev);
end;

procedure TForm1.Button1Click(Sender: TObject);
var
    value:longint;
    DelphiString: string;
  AnsiStringPtr: PAnsiChar;
  nkeynew,StrPtr: PAnsiChar;
  HexValue: string;
  dataread: array[0..31] of Byte; // 读取的数据,16个字节
    //nkey: TArray<Byte>;
begin
     snr:=0;
     sector:=1;
     block:=sector*4;                     // 0=a  4=b
     loadmode:=0;
   //  nkey:= Chr(160) + Chr(161) + Chr(162) + Chr(163) + Chr(164) + Chr(165);
   //  st:=rf_load_key(icdev,loadmode,sector, nkey);

  // nkey:=  Chr(255)+Chr(255)+Chr(255)+Chr(255)+Chr(255)+Chr(255);
//st:=rf_load_key(icdev,0,1,nkey);

    // nkey:='ffffffffffff';
     nkey:='FFFFFFFFFFFF';
     nkeynew:='FFFFFFFFFFFF';
     st:=rf_load_key_hex(icdev,loadmode,sector, nkeynew);       //装载密钥到读卡器中
    //st:=0;
     if st<>0 then
        listbox1.items.add('load key error')
     else
        listbox1.items.add('load key Ok');

     st:=rf_card(icdev,1,@snr);
     if st<>0 then
        listbox1.items.add('card snr error')
     else
        listbox1.items.add('card snr Ok:'+Trans(format('%x',[snr])));


     st:=rf_authentication(icdev,loadmode,sector);
     if st<>0 then
        listbox1.items.add('authentication error')
     else
        listbox1.items.add('authentication Ok');




      begin     // hex写入形式
        // 读取输入内容并转换格式
        AssignEditTextToAnsiChar(Edit1, StrPtr);
        try
          // 在这里你可以使用 AnsiText 变量,它现在指向包含 Edit1 文本内容的 ANSI 字符串
           st:=rf_write_hex(icdev,block,StrPtr ) ;
          // ...
        finally
          // 释放之前分配的内存
          FreeMem(StrPtr);
      end;


     if st<>0 then
        listbox1.items.add('write hex error')
     else
        listbox1.items.add('write hex Ok');


     st:=rf_read_hex(icdev,block,@dataread);
     if st<>0 then
        listbox1.items.add('read  hex error')
     else
       // listbox1.items.add('read Ok:');
         listbox1.items.add('read hex Ok:'+ ByteArrayToHex(dataread));


        wdata:=('这里是染卷ranjuana1a2a3a4a5a6a7a8a1a2a3a4a5a6a7a8');      // 字符串写入  ,最长8个字符 ,截取前面8个字符
    st:=rf_write(icdev,block,wdata);
    if st<>0 then
        listbox1.items.add('write 字符串 error')
    else
        listbox1.items.add('write 字符串 Ok');

     st:=rf_read(icdev,block,@databuff);
     if st<>0 then
        listbox1.items.add('read 字符串 error')
     else
        listbox1.items.add('read 字符串 Ok:'+databuff);







     st:=rf_halt(icdev);
     if st<>0 then
        listbox1.items.add('halt error')
     else
        listbox1.items.add('halt Ok');

     st:=rf_reset(icdev,10);
     if st<>0 then
         listbox1.items.add('reset error')
     else
          listbox1.items.add('reset OK');
 end;

end;



procedure TForm1.Button3Click(Sender: TObject);
var
      value:longint;
      nkeynew:PAnsiChar;
      StrPtr: PAnsiChar;
begin
     loadmode:=0;

     sector:=1;          //选择0-15扇区的1扇区
     block:=sector*4;         //选择块号,0-15扇区 包含了 0-63块;
     nkey:='ffffffffffff';
     nkeynew:='ffffffffffff';
     st:=rf_load_key_hex(icdev,loadmode,sector, nkeynew);
     if st<>0 then
        listbox1.items.add('load keyhex error')
     else
        listbox1.items.add('load keyhex Ok');

     st:=rf_card(icdev,1,@snr);
     if st<>0 then
        listbox1.items.add('card snr error')
     else
        listbox1.items.add('card snr Ok:'+inttostr(snr));

     st:=rf_authentication_2(icdev,loadmode,sector,block);
     if st<>0 then
        listbox1.items.add('authentication_2 error')
     else
        listbox1.items.add('authentication_2 Ok');

     wdatanew:='b1b2b3b4ffffffffffffffffffffffff';         //Only write 4 byte  per time
     AssignStringToAnsiChar(wdatanew,StrPtr);
     st:=rf_write_hex(icdev,block,StrPtr);
     if st<>0 then
        listbox1.items.add('write hex error')
     else
        listbox1.items.add('write hex Ok');

     wdatanew:='b5b6b7b8ffffffffffffffffffffffff';         //Only write 4 byte per time
     AssignStringToAnsiChar(wdatanew,StrPtr);
     st:=rf_write_hex(icdev,block+1,StrPtr);
     if st<>0 then
        listbox1.items.add('write hex error')
     else
        listbox1.items.add('write hex Ok');

     st:=rf_read_hex(icdev,block,@databuff);   //Only read 8 byte per time
     if st<>0 then
        listbox1.items.add('read hex error')
     else
        listbox1.items.add('read hex Ok:'+databuff);

 //Value Operation
    st:=rf_initval_ml(icdev,100);          //initvlaue 100       文档无此函数
     if st<>0 then
       listbox1.items.add('initval_ml error.')
     else
       listbox1.items.add('initval_ml Ok');

       st:=rf_load_key_hex(icdev,loadmode,sector, nkeynew);
       //  st:=rf_transfer(icdev,block+1);
         st:=rf_initval(icdev,sector*4+1,100);
          st:=rf_increment(icdev,sector*4+1,100);
     //st:=rf_decrement_transfer(icdev,sector*4+1,1);   //decrement 10        减少1
     st:=rf_decrement(icdev,sector*4+1,1);
     if st<>0 then
        listbox1.items.add('decrement_transfer error.')
     else
        listbox1.items.add('decrement_transer Ok');

     st:=rf_readval_ml(icdev,@value);   //文档无此函数
     if st<>0 then
        listbox1.items.add('readval_ml error.')
     else
        listbox1.items.add('readval_ml Ok: '+inttostr(value));



      st:=rf_readval(icdev,sector*4+1,@value);   //读取块值
     if st<>0 then
        listbox1.items.add('readval error.')
     else
        listbox1.items.add('readval Ok: '+inttostr(value));

      st:=rf_halt(icdev);
end;


end.

PS:这款GH-230Z-YKT是不支持安卓的,如果想要安卓开发可以让客服或供货商推荐别的型号;另外x宝上也有一些性价比更好的读卡器。

下载完整代码包:

https://gitee.com/rorgent/delphi/tree/master/GH-230Z-YKT%E8%AF%BB%E5%8D%A1%E5%99%A8

基于互联网精神,在注明出处的前提下本站文章可自由转载!

本文链接:https://ranjuan.cn/delphi2010-hc-rf-m1card/

赞赏

微信赞赏支付宝赞赏

如何设计简单的php在线考试系统
ali-android-push-huawei
php报错undefined-index解决