有关BCD码的问题(50分)

  • 主题发起人 主题发起人 gengxufeng
  • 开始时间 开始时间
G

gengxufeng

Unregistered / Unconfirmed
GUEST, unregistred user!
各位大侠,小弟正在作有关串口通信的项目,用的是SPCOMM控件。现在有个问题,就是要把发送的数据组织成BCD码的格式,但显示的还是整形数。例如:通信协议
头是:0A DO
中间的数据部分是XX XX ..... SUM , 每个XX是一个字节的整形数,例如:15、67等等,SUM是校验和,前面的若干个XX的或运算结果。
现在关键的是15的编码格式是按BCD码编码的,而不是计算机默认的16进制的,比如:
15 or 67 的运算结果必须是77 即01110111,而计算机默认的是按每个数的16进制的编码方式来作或运算的,所以计算机默认的15 or 67 的结果是79 ,即01001111。所以,我的问题是怎么才能使15 or 67 的结果是77 ,而不是79,当然SUM就是16进制的。因为我的程序是要和下位机通信,它要求的数据格式就是BCD格式的。DElphi提供的TBCD我也看了,但用了还是不行。那是不是要用到TBits,还望各位下侠指点,分不多了。谢谢!
 
小弟还有一个问题,我的Form上有100个Edit,每个Edit输入一个整数,范围是0到2的32次方,然后将每个Edit中的整数转为八字节的十六进制字符串,例如:输入1234,转为000004D2。接着再把转化后的十六进制字符串放到四个字节里,如:$00,$00,$04,$D2,这样总共下来就是400字节的十六进制数,最后通过串口发送。我想问的是,哪位大侠有好的算法,能比较好的将100个Edit的内容摆成400字节的十六进制数,小弟不胜感激,谢谢!小弟没分了,还望各位大侠谅解。
 
///////////////////////////////////////////////////////////
// 从文本字串中分解出16进制的数据,返回这些8位数据组成的字串
// 文本字串分解规则:
// 1.数据是用16进制表示的8位数据(如FC,3D等)
// 2.每个数据只取最后两个16进制字符,如1F3D只取3D,前面多余部分抛弃
// 3.每个数据之间用空格或回车换行等格式符号隔开
///////////////////////////////////////////////////////////
function GetDataFromText(str: string): string;
var
i, p1, p2: Integer;
begin
Result := '';
while str <> '' do
begin
i := 0;
p1 := Pos(' ', str);
p2 := Pos(#13#10, str);

if p1 = 1 then // 空格在最前面
begin
Delete(str, 1, 1);
continue;
end;
if p2 = 1 then // #13#10在最前面
begin
Delete(str, 1, 2);
continue;
end;

if (p1 = 0) and (p2 = 0) and (str <> '') then // 都没有找到,结束
begin
i := StrToIntDef('$' + str, 0);
Delete(str, 1, Length(str));
end;
if ((p1 > 0) and (p2 = 0)) or // 找到空格
((p1 > 0) and (p2 > 0) and (p1 < p2)) then // 或都找到,但空格在前
begin
i := StrToIntDef('$' + Copy(str, 1, p1 - 1), 0);
Delete(str, 1, p1);
end;
if ((p1 = 0) and (p2 > 0)) or // 找到#13#10
((p1 > 0) and (p2 > 0) and (p1 > p2)) then // 或都找到,但空格在后
begin
i := StrToIntDef('$' + Copy(str, 1, p2 - 1), 0);
Delete(str, 1, p2 + 1);
end;
Result := Result + Chr(i); // 8位数据转为字符
end; // while
end;



//写卡
procedure Tfrm_ICAccredit.btn_writeCardClick(Sender: TObject);
var
S: string;
Buf: array[0..$16] of Byte;
I: Integer;
begin //TODO:


FillChar(Buf, SizeOf(Buf), #0);
//扇区,块
Buf[0] := HexToInt(cbx_Writefan.Text) *4 + HexToInt(cbx_WriteBlock.Text);

//检查扇区块是否可写
I := ((Buf[0] + 1) mod 4);
if Buf[0] = 0 then begin
AppMsgBox(Format('该块[%2.2x]不能写入数据。', [Buf[0]]));
Exit;
end;
if I = 0 then begin
AppMsgBox(Format('该块[%2.2x]不能写入数据。', [Buf[0]]));
Exit;
end;

if CheckEditIsEmpty( edt_writePw) then Exit;
//检查数据有效性
if CheckEditIsEmpty( edt_writeData) then Exit;
//密码
S := GetDataFromText(edt_writePw.Text);
for I := 1 to Length(S) do
Buf := Ord(S);
S := GetDataFromText(edt_writeData.Text);
for I := 1 to Length(S) do
Buf[I + 6] := Ord(S);

try
if self.BaseComm.SendWriteICCardCmd($0F, Buf) then
self.UpdateLog('发送写卡数据命令成功', clGray)
else Self.UpdateLog('发送写卡数据命令成功失败', clGray);
except
on E: Exception do
self.UpdateLog(E.Message, clRed);
end;

end;
function BCDToInt(HighHex, LowHex: Integer): Integer;
begin
try
Result := StrToInt(IntToHex(HighHex, 1) + IntToHex(LowHex, 1));
except
Result := 0;
end;
end;

//取Word中的一个Byte类型转换成Byte Low
function GetBCDByLow(D: Word): Byte;
var
I: integer;
S: string;
M: string;
begin

Result := 0;
if D > 9999 then
raise Exception.Create('不能大于9999.');
S := IntToStr(D);

I := Length(S);
I := Length(S);
case I of
1, 2: M := Copy(S, 1, 2);
3: M := Copy(S, 2, 2);
4: M := Copy(S, 3, 2);
end;

Result := HexToInt(M);
end;




//取Word中的一个Byte类型转换成Byte High
function GetBCDByHigh(D: Word): Byte;
var
I: integer;
S: string;
M: string;
begin
Result := 0;
if D > 9999 then
raise Exception.Create('不能大于9999.');
S := IntToStr(D);

I := Length(S);
if I <=2 then Exit; //高位是0

if I = 4 then
M := Copy(S, 1, 2)
else M := Copy(S, 1, 1);

Result := HexToInt(M);
end;




//将array of Byte 格式化为Hex显示,2.2x格式:FF FE FF
function ArrayByteToHex(Buf: array of Byte; Count: Integer = 0): string;
var
I: Integer;
Len: Integer;
begin
if Count = 0 then
Len := High(Buf)
else Len := Count - 1;
Result := '';
for I := 0 to Len do
Result := Result + Format('%2.2x', [Buf]) + #32;
end;

//将String 格式化为Hex显示,2.2x格式:FF FE FF
function StringToHex(const S: string): string;
var
I: Integer;
begin
Result := '';
for I := 1 to Length(S) do
Result := Result + Format('%2.2x', [Ord(S)]) + #32;

end;

//十六进制字符串转换成十进制整型
function HexToInt(Astr: string): Integer;
function TransChar(AChar: Char): Integer;
begin
if AChar in ['0'..'9'] then
Result := Ord(AChar) - Ord('0')
else
Result := 10 + Ord(AChar) - Ord('A');
end;
var
I: Integer;
C: Integer;
ISqr: Integer;
begin
Result := 0;
for I := 1 to Length(Astr) do
begin
ISqr := Trunc(IntPower(16, Length(Astr) - I));
C := TransChar(AStr);
Result := Result + ISqr * C;
end;
end;
 
15 or 67 必须是77,为什么??那你还如直接将值指定77
 
jfyes,你好,谢谢你的帮助,但你的代码,我有点不懂,能不能麻烦你说的详细点。
至于 15 or 67 必须是77,是这样的:我这只是举的例子,因为,你看,15的BCD码是
00010101,67的BCD码是01100111,两者做or运算,结果不就是01110111,即77吗?
但Delphi本身是按照十六进制的编码方式来做的,即15 是00001111,67是 01000011,两者做or运算的结果是01001111,也就是10进制的79,但这不是我要的结果。
实际上是这个意思,在串行通信中,发送的15是10进制的,但15这个数内部的编码格式是BCD码格式的,而不是delphi默认的16进制的,因为我们定的通信协议就是发送BCD码,要不对方就不认识。就是这样。
 
小弟还有个小问题,用SPCOMM控件的WriteCommData发送数据,怎么判断相应长度的数据已经完全发送完毕,因为程序要和单片机通信,确认发送完毕后,还要进行下一步的操作,还望各位大侠指点。唉,没办法,我是个新手,最近被这个东西搞的晕头转向。
 
第一步:把16进制码(67)转换为10进制码(103)
第二步:做或的运算
 
第一个问题:
Bcd码,说白了就是人们习惯的10进制数,比如说,下位机传上来一串数据为:1234两个字节,一般我们会认为是0X12,0X34(十六进制),这两个0X12,0X34再转为人们习惯的10进制呢,就是0X12=18,0X34=52;
那么现在如果用bcd码协议传数据1234,那么我们就不要作转换了,他传上来1234两个字节,我们就可以把他看作是12,34的十进制数据,当然,你如果想再将这两个数转为计算机常用的十六进制的话,就加一个INTTOHEX(12,2)=0X0A,INTTOHEX(34,2)=0X22再进行保存,这就是BCD与十六进制的关系.看你能否理解.
第二个问题:
有100个EDIT,里面有一串数据,要将它转为十六进制发送,这个也好办,下面先举一个EDIT,然后你自已组合;
var Tmpbyte:array[0..3] of byte;
Tmphex :string;
I:Integer;
begin
Tmphex := Inttohex(Strtoint(Edit1.text),8);//转为十六进制
for I := 0 to 3 do
begin
Tmpbyte := Strtoint('$'+Copy(Tmphex,I*2+1,2));//放入四个字节
end;
end;
第三个问题:
在SPCOMM属性里有一个发送忙检测标识,发送完后,这个标识会有一个状态参数,这个我忘了,看到了再发上来.
 
后退
顶部