wangzs728 发表于 2021-9-9 09:39:27

使用CF块写的高低位计算例程

用于计算某段数据中的高低位数量、最前一位最后一位的位置,应用于光幕、测量光栅,物件通过光幕时会遮住发射端的光点,接收端该光电io信号被取反。该例程用于收取光幕io信号集,反馈起始点、长度、结束点,用于物料尺寸检测、物料纠偏。
示例:
出于便于理解以及对于刚好64/32位数据的使用所以有两个CF块。其中CF_0位64/32bit版,CF_1为任意长度版
符号表对比:
64/32bit:

任意长度版:

程序整体:
64/32bit:

任意长度版:

几种计算结果:



↓↓↓↓↓↓↓↓原代码↓↓↓↓↓↓↓↓
64/32位:
/*判断某64位数内有多少个1,最低位是第几位、最高位是第几位;
**先对low、high、sum寄存器进行初始化(赋0);
**判断开始位为1则进行运算;
**使用右移和与来完成循环比较,对64位数中每一位依次判断是否为1;
**首次位为1则将 i 值存储到low寄存器中;每次位为1都更新high寄存器和sum寄存器;
**计算完成之后分别输出总和、低位、高位。                */

/*计算工作原理:
**将V区的值获取进来,然后进入循环
**在循环中从第一位到最后一位依次进行判断
**判断逻辑:从头到尾按位与1,与完还是1则说明此位为1,对寄存器依次更新
**当第一次碰到或当 i 值小于low值时1时将 i 赋值到low(低位)寄存器                //判断i < low 防止首次赋值了高32位数据后低32位中有更小值
**每次碰到1都对high(高位)、sum(总数)寄存器进行更新      */

#include "math.h"
#include "stdio.h"
#include "plc300.h"
S32 D_low, D_high;                //用于移位的计算寄存器
S16 sum, low, high;                //存储运算结果                sum:总和                low:低位                high:高位
U8 i;                //循环变量

void CF_0( S32 data_low, S32 data_high, BOOL start, S16 *onnum, S16 *rank_low, S16 *rank_high)
{
      low = high = sum = 0;                //初始化寄存器

      if(start)                //判断是否执行程序,start == 1 则执行27—50行的程序
      {
                D_low = data_low ,D_high = data_high;                        //将低、高位数据存储到计算寄存器
                for(i = 1; i <= 32; i++)                //使用for循环对1—32位数据逐个进行判断
                {
                        if((D_low&1) == 1)                //如果数据首位&1后等于1,则判断低位寄存器是否0或是否大于i,并更新寄存器
                        {
                              if(low == 0 || low > i) low = i;
                              if(i>high) high = i;
                              sum++;
                        }
                        if((D_high&1) == 1)//如果数据首位&1后等于1,则判断低位是否0,并更新寄存器
                        {
                              if(low == 0) low = i+32;
                              high = i+32;
                              sum++;
                        }
                        D_low >>=1;                //判断完成后将数据右移1位来更新首位
                        D_high >>=1;
                }
                //输出计算结果↓
                setS16(onnum,sum);
                setS16(rank_low,low);
                setS16(rank_high,high);
      }
}

不做长度限制版:
/*判断某64位数内有多少个1,最低位是第几位、最高位是第几位;
**先对low、high、sum寄存器进行初始化(赋0);
**判断开始位为1则进行运算;
**使用右移和与来完成循环比较,对数据中每一位依次判断是否为1;
**首次位为1则将 i 值存储到low寄存器中;每次位为1都更新high寄存器和sum寄存器;
**计算完成之后分别输出总和、低位、高位。                */

/*计算工作原理:
**将V区的值逐个字节获取进来,然后进入循环
**在循环中从第一位到最后一位依次进行判断
**判断逻辑:从头到尾按位与1,与完等于1则说明此位为1,对寄存器依次更新
**当第一次碰到1时将 i 赋值到low(低位)寄存器
**每次碰到1都对high(高位)、sum(总数)寄存器进行更新      */

#include "math.h"
#include "stdio.h"
#include "plc300.h"
U16 sum, low, high;                //存储运算结果                sum:总和                low:低位                high:高位
U8 i, D, L;                //循环变量

void CF_1( void* data, U8 len, BOOL start, S16 *onnum, S16 *rank_low, S16 *rank_high)
{
      low = high = sum = 0;                //初始化寄存器

      if(start)                //判断是否执行程序,start == 1 则执行27—50行的程序
      {
                for(L =len; L >0; L--)                //从最低个字节像高字节循环,依次获取V区进行计算
                {
                        D =getS8(data+L-1);                        //将低、高位数据存储到计算寄存器
                        for(i = 1; i <= 8; i++)                //使用for循环对字节内数据逐个进行判断
                        {
                              if((D&1) == 1)                //如果数据首位&1后等于1,则判断低位寄存器是否0或是否大于i,并更新寄存器
                              {
                                        if(low == 0) low = i+(len-L)*8;
                                        high = i+(len-L)*8;
                                        sum++;
                              }
                              D >>=1;
                        }
                }
      }

                //输出计算结果↓
                setS16(onnum,sum);
                setS16(rank_low,low);
                setS16(rank_high,high);
}




页: [1]
查看完整版本: 使用CF块写的高低位计算例程