请教各大高手:在Trio中如何实现CRC_16的运算? 点击:1004 | 回复:4



KeyMan_HJH

    
  • 精华:0帖
  • 求助:0帖
  • 帖子:8帖 | 15回
  • 年度积分:0
  • 历史总积分:147
  • 注册:2006年3月12日
发表于:2007-07-26 14:27:00
楼主
在Trio与欧姆龙温控器通讯模块通讯时,遇到了要计算CRC_16校验码的问题,已在VB中编程实现了,但是在Trio中就感觉比较难实现,请大家给些思路,谢谢!

下面是CRC-16的计算过程:
CRC-16码由两个字节构成,在开始时CRC寄存器的每一位都预置为1,然后把CRC寄存器与8-bit的数据进行异或,之后对CRC寄存器从高到低进行移位,在最高位(MSB)的位置补零,而最低位(LSB,移位后已经被移出CRC寄存器)如果为1,则把寄存器与预定义的多项式码(&HA001)进行异或,否则如果LSB为零,则无需进行异或。重复上述的由高至低的移位8次,第一个8-bit数据处理完毕,用此时CRC寄存器的值与下一个8-bit数据异或并进行如前一个数据似的8次移位。所有的字符处理完成后CRC寄存器内的值即为最终的CRC值。

下面为CRC的计算过程:

1.设置CRC寄存器,并给其赋值FFFF(hex)。

2.将数据的第一个8-bit字符与16位CRC寄存器的低8位进行异或,并把结果存入CRC寄存器。

3.CRC寄存器向右移一位,MSB补零,移出并检查LSB。

4.如果LSB为0,重复第三步;若LSB为1,CRC寄存器与多项式码(&HA001)相异或。

5.重复第3与第4步直到8次移位全部完成。此时一个8-bit数据处理完毕。

6.重复第2至第5步直到所有数据全部处理完成。

7.最终CRC寄存器的内容即为CRC值。

例如:data=&H010600000101,通过计算,其对应的CRC_16码值为&9A49。
      data=&H010800001234,通过计算,其对应的CRC_16码值为&7CED。




Trio技术支持

  • 精华:0帖
  • 求助:0帖
  • 帖子:2帖 | 150回
  • 年度积分:0
  • 历史总积分:201
  • 注册:2004年7月28日
发表于:2007-07-26 15:22:00
1楼

'=========================================================================
' Customer:     Application Example
' Application:  Modbus Slave
' Module:       MODSLAVE.BAS
' Platform:     Trio Motion Coordinator
'-------------------------------------------------------------------------
' Version:      1.0           Issued: 20 OCT 2005
' Author:       Wang Ye
' Original:     8 OCT 2005
'-------------------------------------------------------------------------
'             Copyright (c) 1999-2005 Trio Motion Technology Ltd.
'
'                        Trio Motion Technology Ltd.
'                       Web site: www.triomotion.com
'=========================================================================
'=========================================================================
' Communication protocol - Modbus RTU
'
' Run this as a fast program and connect OMRON 3G3MV to Port #mport
' The inverter is at address 1 to 4.
'=========================================================================


'######################################
'Initialise the communication paramter
'######################################
mport=2
'######################################
'Initialise the number of inverter
'######################################
number=3

'##############################################
'Initialise the offset in table area
'##############################################
c_base=0 'suppose the device address=n
            'table(c_base+n) make order to device
            '  example: table(c_base+1,1)->enable inverter(address=1) accept the
            '           control order and setting pulse.This byte will be reset
            '           automatically.
            'table(c_base+(n-1)*2+11) current pulse value
            'table(c_base+(n-1)*2+12) current electrical current value
            'table(c_base+(n-1)*2+21) The control order ="0000" in inverter
            '                        =0 STOP command
            '                        =1 FORWARD command
            '                        =3 REVERSE command
            'table(c_base+(n-1)*2+22) The pulse value that you want to transfer

t_base=100
'#################################################
'RS485 OR RS422 SETTING; if the cable is two wires,
'set rs485=1, otherwise set rs485=0
'#################################################
rs485=0

'#################################################
'#################################################
GOSUB table_init

GOSUB set_crc_hi
GOSUB set_crc_lo

GOSUB com_init
GOSUB clr_buffer
TICKS=timeout

FOR num=1 TO number
    TABLE(c_base+num,0)
NEXT num

WHILE(1)
    FOR num=1 TO number
        'send order
        GOSUB clr_buffer
        enable=TABLE(c_base+num)
        order=TABLE(c_base+(num-1)*2+21)
        pulse=TABLE(c_base+(num-1)*2+22)
        IF(enable=1) THEN
            TABLE(t_base,num)
            TABLE(t_base+1,$10)
            TABLE(t_base+2,0)
            TABLE(t_base+3,1)
            TABLE(t_base+4,0)
            TABLE(t_base+5,2)
            TABLE(t_base+6,4)
            TABLE(t_base+7,0)
            TABLE(t_base+8,order)
            data=pulse*10
            IF(data<256) THEN
                TABLE(t_base+9,0)
                TABLE(t_base+10,data)
            ELSE
                data2=data MOD(256)
                data1=(data-data2)/256
                TABLE(t_base+9,data1)
                TABLE(t_base+10,data2)
            ENDIF
            orderlen=12
            GOSUB crc_send_calc
            GOSUB sendorder
            GoSub get_frame
            If frame_flag=2 Then
             TABLE(c_base+num,0) 'clear enable signal
             WA(200)
            endif
        ENDIF
        IF(enable=0) THEN
            WA(200)
            'receive the current data
            TABLE(t_base,num)
            TABLE(t_base+1,3)
            TABLE(t_base+2,0)
            TABLE(t_base+3,ordertype)
            TABLE(t_base+4,0)
            TABLE(t_base+5,1)
            orderlen=7
            GOSUB crc_send_calc
'            GOSUB clearbuf
            GOSUB sendorder
            mod_addr=num

            GOSUB get_frame
            IF frame_flag=2 THEN
                GOSUB chk_message
                IF(ordertype=$27) THEN
                    elec=result
                ELSE
                    pulse_read=result
                ENDIF
            ENDIF
        'write to table memory
         TABLE(c_base+(num-1)*2+11,pulse_read)
         TABLE(c_base+(num-1)*2+12,elec)
        ENDIF
    NEXT num
    IF(ordertype=$23) THEN
        ordertype=$27
    ELSE
        ordertype=$23
    ENDIF
    WA(200)
WEND


com_init:
ADDRESS=255
SETCOM(9600,8,1,2,mport,OFF)
rx_pt=0
tx_pt=0
timeout=100 'Quiet time between frames

result=0
orderlen=0
ordertype=$23
RETURN

table_init:
' uses table between t_base and t_base+1024
st=t_base+1000't_base ' crc look up (hi byte)
s2=t_base+1256't_base+256 ' crc look up (low byte)

ts=t_base+512 'table start
tt=ts+256
FOR i=ts TO ts+512
    TABLE(i,0)
NEXT i
RETURN

'=========================================================================
' GET_FRAME
' Call this routine when a character has been detected (KEY is TRUE)
' Tries to receive a frame and check the CRC
' frame_flag returns 2 for frame OK or 3 for frame error
' DATA is returned in TABLE(ts) to TABLE(ts+rx_pt-1)
'=========================================================================

get_frame:
IF(rs485=1) THEN
    flag1=0
    WHILE flag1=0
        IF(KEY#mport) THEN
            GET#mport,data
'             PRINT#5,data
            IF(data=sendlast1) THEN
                GET#mport,data
                IF(data=sendlast2) THEN flag1=1
            ENDIF
        ENDIF
    WEND
ENDIF
'GOSUB test
frame_flag=0
rx_pt=0
WA(100)
REPEAT
    IF KEY #mport THEN
        GET #mport,in_chr
        TICKS=timeout
'        PRINT #5,HEX(in_chr)
        IF rx_pt=0 AND frame_flag=0 THEN
            IF in_chr=mod_addr THEN
                TABLE(ts,in_chr)
                rx_pt=rx_pt+1
            ELSE
                frame_flag=1
            ENDIF
        ELSE
            IF rx_pt<255 THEN
                TABLE(ts+rx_pt,in_chr)
                rx_pt=rx_pt+1
            ENDIF
        ENDIF
    ELSE
        IF TICKS<0 THEN
            IF rx_pt>2 THEN
                GOSUB crc_check
            ELSE
                frame_flag=3
            ENDIF
        ENDIF
    ENDIF
UNTIL frame_flag>=2
RETURN

'=========================================================================
' CHK_MESSAGE
' Routine checks message for recognised commands and sends appropriate
' reply.
' Enter with ts at start of message in table and rx_pt at end+1
'
'=========================================================================

chk_message:
recog_flag=0
TICKS=timeout

result=(TABLE(ts+3)*256+TABLE(ts+4))/10
RETURN
'#############################################################################
sendorder:
FOR i=0 TO orderlen
    PRINT#mport,CHR(TABLE(t_base+i));
'    PRINT#5,TABLE(t_base+i)
NEXT i
sendlast1=TABLE(t_base+orderlen-1)
sendlast2=TABLE(t_base+orderlen)
RETURN

crc_send_calc:
te=t_base+orderlen-2
css=t_base
cse=te
GOSUB crc_calc

TABLE(te+1,crchi)
TABLE(te+2,crclo)
RETURN

'=========================================================================


clr_buffer:
WHILE KEY #mport
    GET #mport,in_chr
WEND

RETURN

crc_check:
te=ts+rx_pt-3
css=ts
cse=te
GOSUB crc_calc

IF TABLE(te+1)<>crchi THEN
    frame_flag=3
ELSE
    IF TABLE(te+2)=crclo THEN
        frame_flag=2
    ELSE
        frame_flag=3
    ENDIF
ENDIF
RETURN

crc_set:
css=tt
cse=tx_pt-3
GOSUB crc_calc

TABLE(tx_pt-2,crchi,crclo)
RETURN

crc_calc:
crchi=255 :crclo=255
FOR i=css TO cse
'    PRINT#5,HEX(TABLE(i))
    uindex=crchi XOR TABLE(i)
    crchi=crclo XOR TABLE(st+uindex)
    crclo=TABLE(s2+uindex)
NEXT i
crclo=crclo AND 255
'PRINT#5,HEX(crclo)
crchi=crchi AND 255
'PRINT#5,HEX(crchi)
RETURN

' Set up two look-up tables for fast crc
' generation.

set_crc_hi:
TABLE(st,0,193,129,64,1,192,128,65,1,192)
TABLE(st+10,128,65,0,193,129,64,1,192,128,65)
TABLE(st+20,0,193,129,64,0,193,129,64,1,192)
TABLE(st+30,128,65,1,192,128,65,0,193,129,64)
TABLE(st+40,0,193,129,64,1,192,128,65,0,193)
TABLE(st+50,129,64,1,192,128,65,1,192,128,65)
TABLE(st+60,0,193,129,64,1,192,128,65,0,193)
TABLE(st+70,129,64,0,193,129,64,1,192,128,65)
TABLE(st+80,0,193,129,64,1,192,128,65,1,192)
TABLE(st+90,128,65,0,193,129,64,0,193,129,64)
TABLE(st+100,1,192,128,65,1,192,128,65,0,193)
TABLE(st+110,129,64,1,192,128,65,0,193,129,64)
TABLE(st+120,0,193,129,64,1,192,128,65,1,192)
TABLE(st+130,128,65,0,193,129,64,0,193,129,64)
TABLE(st+140,1,192,128,65,0,193,129,64,1,192)
TABLE(st+150,128,65,1,192,128,65,0,193,129,64)
TABLE(st+160,0,193,129,64,1,192,128,65,1,192)
TABLE(st+170,128,65,0,193,129,64,1,192,128,65)
TABLE(st+180,0,193,129,64,0,193,129,64,1,192)
TABLE(st+190,128,65,0,193,129,64,1,192,128,65)
TABLE(st+200,1,192,128,65,0,193,129,64,1,192)
TABLE(st+210,128,65,0,193,129,64,0,193,129,64)
TABLE(st+220,1,192,128,65,1,192,128,65,0,193)
TABLE(st+230,129,64,0,193,129,64,1,192,128,65)
TABLE(st+240,0,193,129,64,1,192,128,65,1,192)
TABLE(st+250,128,65,0,193,129,64)
RETURN

set_crc_lo:
TABLE(s2,0,192,193,1,195,3,2,194,198,6)
TABLE(s2+10,7,199,5,197,196,4,204,12,13,205)
TABLE(s2+20,15,207,206,14,10,202,203,11,201,9)
TABLE(s2+30,8,200,216,24,25,217,27,219,218,26)
TABLE(s2+40,30,222,223,31,221,29,28,220,20,212)
TABLE(s2+50,213,21,215,23,22,214,210,18,19,211)
TABLE(s2+60,17,209,208,16,240,48,49,241,51,243)
TABLE(s2+70,242,50,54,246,247,55,245,53,52,244)
TABLE(s2+80,60,252,253,61,255,63,62,254,250,58)
TABLE(s2+90,59,251,57,249,248,56,40,232,233,41)
TABLE(s2+100,235,43,42,234,238,46,47,239,45,237)
TABLE(s2+110,236,44,228,36,37,229,39,231,230,38)
TABLE(s2+120,34,226,227,35,225,33,32,224,160,96)
TABLE(s2+130,97,161,99,163,162,98,102,166,167,103)
TABLE(s2+140,165,101,100,164,108,172,173,109,175,111)
TABLE(s2+150,110,174,170,106,107,171,105,169,168,104)
TABLE(s2+160,120,184,185,121,187,123,122,186,190,126)
TABLE(s2+170,127,191,125,189,188,124,180,116,117,181)
TABLE(s2+180,119,183,182,118,114,178,179,115,177,113)
TABLE(s2+190,112,176,80,144,145,81,147,83,82,146)
TABLE(s2+200,150,86,87,151,85,149,148,84,156,92)
TABLE(s2+210,93,157,95,159,158,94,90,154,155,91)
TABLE(s2+220,153,89,88,152,136,72,73,137,75,139)
TABLE(s2+230,138,74,78,142,143,79,141,77,76,140)
TABLE(s2+240,68,132,133,69,135,71,70,134,130,66)
TABLE(s2+250,67,131,65,129,128,64)
RETURN


test:
WHILE(KEY#2)
    GET#2,daf
    PRINT#5,daf
WEND
RETURN

Trio技术支持

  • 精华:0帖
  • 求助:0帖
  • 帖子:2帖 | 150回
  • 年度积分:0
  • 历史总积分:201
  • 注册:2004年7月28日
发表于:2007-07-26 15:22:00
2楼
实际上和VB上的编程思路是一样的,以下是TRIO控制器通过Modbus协议控制OMRON(安川)变频器的事例,里面有CRC交验的完全代码,你可以挑出来自行修改使用,Good Luck!

KeyMan_HJH

  • 精华:0帖
  • 求助:0帖
  • 帖子:8帖 | 15回
  • 年度积分:0
  • 历史总积分:147
  • 注册:2006年3月12日
发表于:2007-07-27 12:22:00
3楼
真是太感谢:Trio技术支持!先谢谢啦!

问根

  • 精华:0帖
  • 求助:0帖
  • 帖子:0帖 | 1回
  • 年度积分:0
  • 历史总积分:11
  • 注册:2010年9月19日
发表于:2010-10-14 18:24:03
4楼
各位前辈。我现有一台三菱QPLC要与欧姆龙温控仪通讯,实现温度读取功能。用的是C24N串口模块232通讯,请教各位怎么编程来读取

热门招聘
相关主题

官方公众号

智造工程师