最近有遇到编码器计数的计数处理,抓取编码器锁存的数值只能在DINT类型范围内,是从-2147483648到2147483647数值,但是现场会有正向多圈的情况。此时需要记录这个数的位置值。就需要记录多圈计数下,圈数的处理。
PROGRAM FB_DintCirAcc
VAR
currentCount : DINT; // 当前计数器的值,DINT类型的范围是从-2147483648到2147483647
circle1 : ULINT := 0; // 经过的极限值圈数
circle2 : ULINT := 0; // 经过的一次16位最大值的圈数
maxThreshold : DINT := 2147470000; // 接近最大值的阈值
minThreshold : DINT := -2147470000; // 接近最小值的阈值
ZeroThreshold : DINT := -10000; // 接近零值的阈值
approachingMax : BOOL := FALSE; // 标志位,表示是否接近最大值
approachingMin : BOOL := FALSE; // 标志位,表示是否接近最小值
approachingZero : BOOL := FALSE; // 标志位,表示是否接近零值
LastCount:DINT;//记录上一周的计数。
bInit:BOOL:=TRUE; //初始化
bCountStrat:BOOL; //模拟开始周期计数
EncoderPos:LREAL;//编码器位置
CalcPos:LREAL;//计数值累加位置
ulCurrentCount:ULINT;//累加计数值
DiffData:DINT;//负向累加差值
UlCirData:ULINT;//负向时圈数值
END_VAR
//模拟先给最大值,跑到第一圈的最大值
IF bInit THEN
currentCount:=2147400000;
Encoder.diEncoderPosition:=currentCount;
bInit:=FALSE;
END_IF
// 假设currentCount在每个周期更新
IF bCountStrat THEN
currentCount := currentCount+10000;
Encoder.diEncoderPosition:=currentCount;
END_IF
// 检测是否接近最大值或最小值
IF (currentCount > maxThreshold) AND NOT approachingMax THEN
// 开始接近最大值
approachingMax := TRUE;
ELSIF currentCount>0 AND (currentCount <= maxThreshold) AND approachingMax THEN
// 不再接近最大值
approachingMax := FALSE;
END_IF
// 检测是否接近最大值或最小值
IF (currentCount < minThreshold) AND NOT approachingMin THEN
// 开始接近最小值
approachingMin := TRUE;
ELSIF currentCount<0 AND (currentCount >= minThreshold) AND approachingMin THEN
// 不再接近最小值
approachingMin := FALSE;
END_IF
// 检测负值累加是否接近0值。
IF (currentCount < ZeroThreshold)
AND (currentCount>(ZeroThreshold*2))
AND NOT approachingZero THEN
// 开始接近最小值
approachingZero := TRUE;
END_IF
// 检测是否从接近最大值过渡到接近最小值,累加一次计数
IF approachingMax AND approachingMin THEN
// 从最大值过渡到最小值,计为一圈
circle1 := circle1 + 1;
circle2 := circle2 + 1;
approachingMax := FALSE; // 重置接近最大值的标志
approachingMin := FALSE; // 重置接近最小值的标志
END_IF
// 检测是否从接近0值,累加一次计数
IF approachingZero AND currentCount>0 THEN
circle2 := circle2 + 1;
approachingZero:=FALSE;
END_IF
Encoder.iTurn;
IF circle1 = 0 THEN
ulCurrentCount:=(currentCount);
ELSE
IF currentCount>0 THEN
ulCurrentCount:=(circle2*2147483647)+DINT_TO_ULINT(currentCount);
ELSE
IF circle1=1 THEN
DiffData:=ABS((2147483647-currentCount));
UlCirData:=(circle1*2147483647);
ulCurrentCount:=DINT_TO_ULINT(DiffData)+UlCirData;
ELSIF circle1>1 THEN
DiffData:=ABS((2147483647-currentCount));
UlCirData:=(((circle1*2)-1)*2147483647);
ulCurrentCount:=DINT_TO_ULINT(DiffData)+UlCirData;
END_IF
END_IF
END_IF
EncoderPos:=Encoder.fActPosition;
CalcPos:=(ulCurrentCount*97.456)/10000;