How do I Convert Dec to Hex in a plc?

ganutenator

Lifetime Supporting Member
Join Date
May 2002
Location
kansas
Posts
1,440
I actually solved this, but I thought this info may help others.

Condition which prompted this need:
I was using a function provided to me by wago to read the serial number and MAC address of the plc. The IT/PC Programmer at work requested this information to help solve a production problem. We are an OEM.

Disclaimer: Most unlike every single plc programming job that I have ever had, No One gets to see the code. But I do realize that comments are also for myself and for the next guy when I die.

The function block that I can't edit, spits out the MAC address as an array [0..5] of bytes in decimal representing the MAC address.
My IT guy wanted that in a string delimited by a hyphen.

Tech support sent me this code. It confused me at first, so I rewrote it differently at the bottom (for others, cuz I care):
Code:
Do_Convert(CLK:=Convert_Enab);

IF Do_Convert.Q = TRUE THEN
	HexMask := 16#000F;
	Rotate := 0;

	FOR I := 0 TO 3 DO
		HexNum[I] := DecNumber AND HexMask;
		HexNum[I] := ROR(HexNum[I] , Rotate);
		HexNumByte[I] := WORD_TO_BYTE(HexNum[I]);
		Rotate := Rotate + 4;
		HexMask := ROL(HexMask , 4);

		CASE HexNumByte[I] OF
			0 :  CharVal[I] := '0';
			1 :  CharVal[I] := '1';
			2 :  CharVal[I] := '2';
			3 :  CharVal[I] := '3';
			4 :  CharVal[I] := '4';
			5 :  CharVal[I] := '5';
			6 :  CharVal[I] := '6';
			7 :  CharVal[I] := '7';
			8 :  CharVal[I] := '8';
			9 :  CharVal[I] := '9';
			10 : CharVal[I] := 'A';
			11 : CharVal[I] := 'B';
			12 : CharVal[I] := 'C';
			13 : CharVal[I] := 'D';
			14 : CharVal[I] := 'E';
			15 : CharVal[I] := 'F';
		END_CASE
	END_FOR
END_IF

I rewrote it as this:

Code:
(*AND's w/ 0000 1111 to process the least significant byte*)
HexNum[0]:= DecNumber AND 16#F;
HexNumByte[0]:= WORD_TO_BYTE(HexNum[0]);

(*AND's w/ 1111 0000 to process the most significant byte*)
HexNum[1]:= DecNumber AND 16#F0;
HexNumByte[1]:= WORD_TO_BYTE((HexNum[1] /16));

FOR i:= 0 TO 1 DO
		CASE HexNumByte[i] OF
			0 :  CharVal[i] := '0';
			1 :  CharVal[i] := '1';
			2 :  CharVal[i] := '2';
			3 :  CharVal[i] := '3';
			4 :  CharVal[i] := '4';
			5 :  CharVal[i] := '5';
			6 :  CharVal[i] := '6';
			7 :  CharVal[i] := '7';
			8 :  CharVal[i] := '8';
			9 :  CharVal[i] := '9';
			10 : CharVal[i] := 'A';
			11 : CharVal[i] := 'B';
			12 : CharVal[i] := 'C';
			13 : CharVal[i] := 'D';
			14 : CharVal[i] := 'E';
			15 : CharVal[i] := 'F';
		END_CASE
END_FOR
 
I wonder if you can replace all of that with

charVal[0] := MID('0123456789ABCDEF',1,(DecNumber AND 16#000F)+1);
charVal[1] := MID('0123456789ABCDEF',1,((DecNumber AND 16#00F0)/16)+1);


but it depends if MID returns the same type as a single element of the charVal array.

Or, if the OUT charVal, instead of an array of characters (of strings?), can be a two-character string:

charVal := CONCAT(MID('0123456789ABCDEF',1,(DecNumber AND 16#000F)+1),MID('0123456789ABCDEF',1,((DecNumber AND 16#00F0)/16)+1));


Or even

charVal := ''; (* or charVal := '-'; *)
FOR I := 0 TO 1
charVal := CONCAT(charVal,MID('0123456789ABCDEF',(DecNumber AND 16#000F)+1));
DecNumber := (DecNumber AND 16#FFF0) / 16;
END_FOR;


Or even, back in the main caller with the [0..5] MAC address array:

charVal := '';
FOR I:= 0 TO 5
DecNumber = MAC_array;
IF I > 0 THEN
charVal := CONCAT(charVal,'-');
END_IF;
charVal := CONCAT(charVal,MID('0123456789ABCDEF',1,(DecNumber AND 16#000F)+1));
DecNumber := (DecNumber AND 16#FFF0) / 16;
charVal := CONCAT(charVal,MID('0123456789ABCDEF',1,(DecNumber AND 16#000F)+1));
END_FOR


or

MACstring := 'XX-XX-XX-XX-XX-XX';
J := 1;
FOR I:= 0 TO 5
DecNumber = MAC_array;
MACstring := INSERT(MACstring,MID('0123456789ABCDEF',1,(DecNumber AND 16#000F)+1),J);
DecNumber := (DecNumber AND 16#FFF0) / 16;
MACstring := INSERT(MACstring,MID('0123456789ABCDEF',1,(DecNumber AND 16#000F)+1),J+1);
J := J + 3;
END_FOR


 
I wonder if you can replace all of that with

charVal[0] := MID('0123456789ABCDEF',1,(DecNumber AND 16#000F)+1);
charVal[1] := MID('0123456789ABCDEF',1,((DecNumber AND 16#00F0)/16)+1);


but it depends if MID returns the same type as a single element of the charVal array.

Or, if the OUT charVal, instead of an array of characters (of strings?), can be a two-character string:

charVal := CONCAT(MID('0123456789ABCDEF',1,(DecNumber AND 16#000F)+1),MID('0123456789ABCDEF',1,((DecNumber AND 16#00F0)/16)+1));


Or even

charVal := ''; (* or charVal := '-'; *)
FOR I := 0 TO 1
charVal := CONCAT(charVal,MID('0123456789ABCDEF',(DecNumber AND 16#000F)+1));
DecNumber := (DecNumber AND 16#FFF0) / 16;
END_FOR;


Or even, back in the main caller with the [0..5] MAC address array:

charVal := '';
FOR I:= 0 TO 5
DecNumber = MAC_array;
IF I > 0 THEN
charVal := CONCAT(charVal,'-');
END_IF;
charVal := CONCAT(charVal,MID('0123456789ABCDEF',1,(DecNumber AND 16#000F)+1));
DecNumber := (DecNumber AND 16#FFF0) / 16;
charVal := CONCAT(charVal,MID('0123456789ABCDEF',1,(DecNumber AND 16#000F)+1));
END_FOR


or

MACstring := 'XX-XX-XX-XX-XX-XX';
J := 1;
FOR I:= 0 TO 5
DecNumber = MAC_array;
MACstring := INSERT(MACstring,MID('0123456789ABCDEF',1,(DecNumber AND 16#000F)+1),J);
DecNumber := (DecNumber AND 16#FFF0) / 16;
MACstring := INSERT(MACstring,MID('0123456789ABCDEF',1,(DecNumber AND 16#000F)+1),J+1);
J := J + 3;
END_FOR




There are many ways to write this.
But I attempted to make it simpler.
And, there are ways to make it even simpler.
Maybe more examples like making it simpler?
 
I found a problem in my revised code already.
It works in my usage as my decimal number will never be larger than 255.
But since we are processing 1 nibble at a time (4 bits or half a bite [stet]), and we are acting on a 16 bit word......

P.S. Is there such a thing as a sandwich?
 
There are many ways to write this.
But I attempted to make it simpler.
And, there are ways to make it even simpler.
Maybe more examples like making it simpler?


LOL. Define "simpler."


To me, a single line of anything algorithmic e.g. MID('0123...',...) is simpler than a CASE clause with 16 cases.

And my first "or even" will expand to handling a sandwich by changing [FOR I := 0 TO 1] to [FOR I := 0 to 3].


Oh, and by the way: the MAC array and DecNumber values are not decimal numbers, they are binary; they may display as decimal by default, but they are not decimal internally.
 
Well, I would argue that the simplest form of this code would be a case statement with characters assigned to decimals 0 to 255. But to each his own.

Apparently there is such thing as a sandwich.
Someone sent me this:

sandwichDef.PNG
 
LOL. Define "simpler."


To me, a single line of anything algorithmic e.g. MID('0123...',...) is simpler than a CASE clause with 16 cases.

And my first "or even" will expand to handling a sandwich by changing [FOR I := 0 TO 1] to [FOR I := 0 to 3].


Oh, and by the way: the MAC array and DecNumber values are not decimal numbers, they are binary; they may display as decimal by default, but they are not decimal internally.

You mean that everything in a computer is stored as either a one or a zero?
It's becuz of dem darn transitor thingy ma bobbers huh!
 
Well, I would argue that the simplest form of this code would be a case statement with characters assigned to decimals 0 to 255. But to each his own.


to each his own indeed!

i found an old thread on the forum where you take the nibble result (0 to F), add 48 to it (ASCII 48 is '0', ASCII 49 is '1', etc.), and if the result is greater than 57 ('9'), then add another 7 to it (ASCII 65 is 'A' etc.).

The OSCAT library has functions to do INT => hex symbols also.
 
more troll ammunition for dirtboy?

Me trying to explain the code to the other programmer at work:

moderator: don't ban me. I was using 2's compliment.

dec to hex.PNG
 
I SMH. This is so simple. Back in the '80s I did it like this.
Code:
        mov ch,4   ; assuming printing 4 hex characters of a 16 bit number
rotate: mov cl,4     ; rotate 4 bits
        rol bx,cl           ; rotate the highest 4 bits in to the low bits
        mov al,bl           ; move the 4 bits into al register 
        and al,0fh          ; keep only the lower 4 bits
        add al,30h          ; add an ascii '0'
        cmp al,3ah          ; is the character < '9'+1
         jl printit
        add al,07h        ; add 7 to get the characters 'ABCDEF'
printit: mov dl,al
        mov ah,2
        int 21h
        dec ch
        jne rotate
        ret
 
Last edited:

Similar Topics

Gurus, I have a question for rslogix 5000, is there any command that can convert dec to hex value and then swap the bits around? For example...
Replies
4
Views
3,062
Hello all, I'm currently working on a servo motor linear positioning system (ball screw). I'm all set up regarding communication between my HMI...
Replies
1
Views
89
I have an application using an incremental encoder and then I convert it to degree (0-360) using calculation program. For a while, the calculation...
Replies
7
Views
238
Hi all. Me again still learning Rockwell. So I'll be polling an INT data array from a Modbus SE power meter with a L82 (with a Modbus ProSoft in...
Replies
56
Views
1,379
Hello, could someone kindly convert the attached RSP files that are currently used for SLC 5 PLC into PDF please
Replies
6
Views
524
Back
Top Bottom