发布于 2011-07-21 03:43:42
50楼
单独开一个帖子吧,上个太长了。
这里跟上一个是一样的,不过那个直接照抄了相关的算法,不利于程序的阅读。下面就用良好的结构写一下,补充注释,去掉无关的注释。一方面以后阅读起来方便,另外一方面增加了通用性。
顺便也完成了无名大侠的答案,循环可以只用5次。
FUNCTION Fc600 : INT
(*
步骤 二进制变量/16进制变量 右移位数
一 2#0101_0101_0101_0101_0101_0101_0101_0101/DW#16#55555555 shr 1
二 2#0011_0011_0011_0011_0011_0011_0011_0011/DW#16#33333333 shr 2
三 2#0000_1111_0000_1111_0000_1111_0000_1111/DW#16#F0F0F0F shr 4
四 2#0000_0000_1111_1111_0000_0000_1111_1111/DW#16#FF00FF shr 8
五 2#0000_0000_0000_0000_0000_0000_1111_1111/DW#16#FF shr 16
求和后就是设备运行总数。
改进:可以改成fb或者增加db来初始化更灵活。
*)
VAR_INPUT
IDWord : DWORD; //输入的32位变量
END_VAR
VAR_IN_OUT
//预留
END_VAR
VAR_OUTPUT
//预留
END_VAR
VAR_TEMP
OutDWord : DWORD; //临时32位变量
i : INT; //循环临时变量
adw : ARRAY[1..5] OF DWORD; //相邻位定义数组
ashr : ARRAY[1..5] OF INT; //右移位定义数组
OneDint : DINT; //用来简化语句的临时变量
TwoDint : DINT; //用来简化语句的临时变量
END_VAR
//临时变量初始化
OutDWord:=IDWord;
//相邻位初始化
adw[1]:=DW#16#55555555;
adw[2]:=DW#16#33333333;
adw[3]:=DW#16#F0F0F0F;
adw[4]:=DW#16#FF00FF;
adw[5]:=DW#16#FF;
//移位初始化
ashr[1]:=1;
ashr[2]:=2;
ashr[3]:=4;
ashr[4]:=8;
ashr[5]:=16;
//求和部分
FOR i:=1 TO 5 BY 1 DO
OneDint:=DWORD_TO_DINT(OutDWord AND adw[i]); //取位
OutDWord:=SHR (IN:=OutDWord, N:=ashr[i]); //移位
TwoDint:=DWORD_TO_DINT(OutDWord AND adw[i]); //取位
(*TwoDint:=DWORD_TO_DINT(SHR (IN:=OutDWord, N:=ashr[i] ) AND adw[i]);*)
OutDWord:=DINT_TO_DWORD(OneDint+TwoDint); //求和
END_FOR;
//函数赋值
FC600 := DINT_TO_INT(DWORD_TO_DINT(OutDWord));
END_FUNCTION
就像找找偷懒的诀窍