最近在折腾树莓派pioc、STM32的micropython,准备做一个RS485接口的ModBus协议的小东东,找了半天也没有crc16-modbus的库,后开网上找了半天,自己攒了一个小程序,因为原来在python里有一个crcmod库很好用,通过研究终于搞定了,特发此帖留个记录。
修订了程序,适用于以下三种形式:
read= '31 32 33 34'
read= '0x31 0x32 0x33 0x34'
read= [0x31,0x32,0x33,0x34]
计算结果如下:
data= [0x31, 0x32, 0x33, 0x34]
CRC16校验: 0X30BA
增加Modbus CRC16校验:>>> [0x31, 0x32, 0x33, 0x34, 0xba, 0x30]
Array: [0x31, 0x32, 0x33, 0x34, 0xba, 0x30]
==========================================
data= 0x31 0x32 0x33 0x34
CRC16校验: 0X30BA
增加Modbus CRC16校验:>>> 0x31 0x32 0x33 0x34 0xBA 0x30
list with 0x: 0x31 0x32 0x33 0x34 0xBA 0x30
==========================================
data= 31 32 33 34
CRC16校验: 0X30BA
增加Modbus CRC16校验:>>> 31 32 33 34 BA 30
list without 0x: 31 32 33 34 BA 30
第一步需要改造_crcfunpy.py如下:
def _get_buffer_view(in_obj):
if isinstance(in_obj, str):
raise TypeError('Unicode-objects must be encoded before calculating a CRC')
mv = memoryview(in_obj)
#if mv.ndim > 1:
# raise BufferError('Buffer must be single dimension') 因为没有ndim属性,这两行注释掉,反正基本用不到
return mv
def _crc8(data, crc, table):
mv = _get_buffer_view(data)
crc = crc & 0xFF
for x in bytes(mv): #原来的 mv.tobytes(),替换为bytes(mv),后面的都一样
crc = table[x ^ crc]
return crc
def _crc8r(data, crc, table):
mv = _get_buffer_view(data)
crc = crc & 0xFF
for x in bytes(mv):
crc = table[x ^ crc]
return crc
def _crc16(data, crc, table):
mv = _get_buffer_view(data)
crc = crc & 0xFFFF
for x in bytes(mv):
crc = table[x ^ ((crc>>8) & 0xFF)] ^ ((crc << 8) & 0xFF00)
return crc
def _crc16r(data, crc, table):
mv = _get_buffer_view(data)
crc = crc & 0xFFFF
for x in bytes(mv):
crc = table[x ^ (crc & 0xFF)] ^ (crc >> 8)
return crc
def _crc24(data, crc, table):
mv = _get_buffer_view(data)
crc = crc & 0xFFFFFF
for x in bytes(mv):
crc = table[x ^ (crc>>16 & 0xFF)] ^ ((crc << 8) & 0xFFFF00)
return crc
def _crc24r(data, crc, table):
mv = _get_buffer_view(data)
crc = crc & 0xFFFFFF
for x in bytes(mv):
crc = table[x ^ (crc & 0xFF)] ^ (crc >> 8)
return crc
def _crc32(data, crc, table):
mv = _get_buffer_view(data)
crc = crc & 0xFFFFFFFF
for x in bytes(mv):
crc = table[x ^ ((crc>>24) & 0xFF)] ^ ((crc << 8) & 0xFFFFFF00)
return crc
def _crc32r(data, crc, table):
mv = _get_buffer_view(data)
crc = crc & 0xFFFFFFFF
for x in bytes(mv):
crc = table[x ^ (crc & 0xFF)] ^ (crc >> 8)
return crc
def _crc64(data, crc, table):
mv = _get_buffer_view(data)
crc = crc & 0xFFFFFFFFFFFFFFFF
for x in bytes(mv):
crc = table[x ^ ((crc>>56) & 0xFF)] ^ ((crc << 8) & 0xFFFFFFFFFFFFFF00)
return crc
def _crc64r(data, crc, table):
mv = _get_buffer_view(data)
crc = crc & 0xFFFFFFFFFFFFFFFF
for x in bytes(mv):
crc = table[x ^ (crc & 0xFF)] ^ (crc >> 8)
return crc
第二步:__init__.py没用可以删掉;
第三步:自己编一个中间文件CRC_mod.py
'''
计算对应的crc可以用以下语句及crc预设名称,,如增加新的请修改predefined.py文件里的_crc_definitions_table:
crc32func = crcmod.predefined.mkPredefinedCrcFun("crc-32")
也可自定义如下:
crc16 =crcmod.mkCrcFun(0x18005, rev=True, initCrc=0xFFFF, xorOut=0x0000)
Name Identifier-name, Poly Reverse Init-value XOR-out Check
[ 'crc-8', 'Crc8', 0x107, NON_REVERSE, 0x00, 0x00, 0xF4, ],
[ 'crc-8-darc', 'Crc8Darc', 0x139, REVERSE, 0x00, 0x00, 0x15, ],
[ 'crc-8-i-code', 'Crc8ICode', 0x11D, NON_REVERSE, 0xFD, 0x00, 0x7E, ],
[ 'crc-8-1', 'Crc81', 0x11D, NON_REVERSE, 0xFF, 0x00, 0x7E, ],
[ 'crc-8-itu', 'Crc8Itu', 0x107, NON_REVERSE, 0x55, 0x55, 0xA1, ],
[ 'crc-8-maxim', 'Crc8Maxim', 0x131, REVERSE, 0x00, 0x00, 0xA1, ],
[ 'crc-8-rohc', 'Crc8Rohc', 0x107, REVERSE, 0xFF, 0x00, 0xD0, ],
[ 'crc-8-wcdma', 'Crc8Wcdma', 0x19B, REVERSE, 0x00, 0x00, 0x25, ],
[ 'crc-16', 'Crc16', 0x18005, REVERSE, 0x0000, 0x0000, 0xBB3D, ],
[ 'crc-16-buypass', 'Crc16Buypass', 0x18005, NON_REVERSE, 0x0000, 0x0000, 0xFEE8, ],
[ 'crc-16-dds-110', 'Crc16Dds110', 0x18005, NON_REVERSE, 0x800D, 0x0000, 0x9ECF, ],
[ 'crc-16-dect', 'Crc16Dect', 0x10589, NON_REVERSE, 0x0001, 0x0001, 0x007E, ],
[ 'crc-16-dnp', 'Crc16Dnp', 0x13D65, REVERSE, 0xFFFF, 0xFFFF, 0xEA82, ],
[ 'crc-16-en-13757', 'Crc16En13757', 0x13D65, NON_REVERSE, 0xFFFF, 0xFFFF, 0xC2B7, ],
[ 'crc-16-genibus', 'Crc16Genibus', 0x11021, NON_REVERSE, 0x0000, 0xFFFF, 0xD64E, ],
[ 'crc-16-maxim', 'Crc16Maxim', 0x18005, REVERSE, 0xFFFF, 0xFFFF, 0x44C2, ],
[ 'crc-16-mcrf4xx', 'Crc16Mcrf4xx', 0x11021, REVERSE, 0xFFFF, 0x0000, 0x6F91, ],
[ 'crc-16-riello', 'Crc16Riello', 0x11021, REVERSE, 0x554D, 0x0000, 0x63D0, ],
[ 'crc-16-t10-dif', 'Crc16T10Dif', 0x18BB7, NON_REVERSE, 0x0000, 0x0000, 0xD0DB, ],
[ 'crc-16-teledisk', 'Crc16Teledisk', 0x1A097, NON_REVERSE, 0x0000, 0x0000, 0x0FB3, ],
[ 'crc-16-usb', 'Crc16Usb', 0x18005, REVERSE, 0x0000, 0xFFFF, 0xB4C8, ],
[ 'x-25', 'CrcX25', 0x11021, REVERSE, 0x0000, 0xFFFF, 0x906E, ],
[ 'xmodem', 'CrcXmodem', 0x11021, NON_REVERSE, 0x0000, 0x0000, 0x31C3, ],
[ 'modbus', 'CrcModbus', 0x18005, REVERSE, 0xFFFF, 0x0000, 0x4B37, ],
[ 'kermit', 'CrcKermit', 0x11021, REVERSE, 0x0000, 0x0000, 0x2189, ],
[ 'crc-ccitt-false', 'CrcCcittFalse', 0x11021, NON_REVERSE, 0xFFFF, 0x0000, 0x29B1, ],
[ 'crc-aug-ccitt', 'CrcAugCcitt', 0x11021, NON_REVERSE, 0x1D0F, 0x0000, 0xE5CC, ],
[ 'crc-24', 'Crc24', 0x1864CFB, NON_REVERSE, 0xB704CE, 0x000000, 0x21CF02, ],
[ 'crc-24-flexray-a', 'Crc24FlexrayA', 0x15D6DCB, NON_REVERSE, 0xFEDCBA, 0x000000, 0x7979BD, ],
[ 'crc-24-flexray-b', 'Crc24FlexrayB', 0x15D6DCB, NON_REVERSE, 0xABCDEF, 0x000000, 0x1F23B8, ],
[ 'crc-32', 'Crc32', 0x104C11DB7, REVERSE, 0x00000000, 0xFFFFFFFF, 0xCBF43926, ],
[ 'crc-32-bzip2', 'Crc32Bzip2', 0x104C11DB7, NON_REVERSE, 0x00000000, 0xFFFFFFFF, 0xFC891918, ],
[ 'crc-32c', 'Crc32C', 0x11EDC6F41, REVERSE, 0x00000000, 0xFFFFFFFF, 0xE3069283, ],
[ 'crc-32d', 'Crc32D', 0x1A833982B, REVERSE, 0x00000000, 0xFFFFFFFF, 0x87315576, ],
[ 'crc-32-mpeg', 'Crc32Mpeg', 0x104C11DB7, NON_REVERSE, 0xFFFFFFFF, 0x00000000, 0x0376E6E7, ],
[ 'posix', 'CrcPosix', 0x104C11DB7, NON_REVERSE, 0xFFFFFFFF, 0xFFFFFFFF, 0x765E7680, ],
[ 'crc-32q', 'Crc32Q', 0x1814141AB, NON_REVERSE, 0x00000000, 0x00000000, 0x3010BF7F, ],
[ 'jamcrc', 'CrcJamCrc', 0x104C11DB7, REVERSE, 0xFFFFFFFF, 0x00000000, 0x340BC6D9, ],
[ 'xfer', 'CrcXfer', 0x1000000AF, NON_REVERSE, 0x00000000, 0x00000000, 0xBD0BE338, ],
[ 'crc-64', 'Crc64', 0x1000000000000001B, REVERSE, 0x0000000000000000, 0x0000000000000000, 0x46A5A9388A5BEFFE, ],
[ 'crc-64-we', 'Crc64We', 0x142F0E1EBA9EA3693, NON_REVERSE, 0x0000000000000000, 0xFFFFFFFFFFFFFFFF, 0x62EC59E3F1A4F00A, ],
[ 'crc-64-jones', 'Crc64Jones', 0x1AD93D23594C935A9, REVERSE, 0xFFFFFFFFFFFFFFFF, 0x0000000000000000, 0xCAA717168609F281, ],
'''
from binascii import *
from crcmod import *
import predefined
# CRC16-MODBUS
def crc16Add(read):
if isinstance(read, str):
arr = read
# print(type(array))
else:
arr=''
for i in read:
arr=arr+str(hex(i))[2:]+' '
crc16 =mkCrcFun(0x18005, rev=True, initCrc=0xFFFF, xorOut=0x0000)
data = arr.replace(" ", "")
data = data.replace("0x", "")
readcrcout = hex(crc16(unhexlify(data))).upper()
str_list = list(readcrcout)
#print(unhexlify(data))
if len(str_list) < 6:
str_list.insert(2, '0' * (6 - len(str_list))) # 位数不足补0
crc_data = "".join(str_list)
print('CRC16校验:',crc_data)
if isinstance(read, str):
if "0x" in read:
read = read.strip() + ' ' +'0x'+ crc_data[4:] + ' ' +'0x'+ crc_data[2:4]
else:
read = read.strip() + ' ' + crc_data[4:] + ' ' + crc_data[2:4]
print('增加Modbus CRC16校验:>>>', read)
else:
aaa=int('0x'+crc_data[4:],16)
read.append(aaa)
aaa=int('0x'+crc_data[2:4],16)
read.append(aaa)
print('增加Modbus CRC16校验:>>>','[{}]'.format(', '.join(hex(x) for x in read)))
return read
# CRC8
def crc08Add(read):
if isinstance(read, str):
arr = read
# print(type(array))
else:
arr=''
for i in read:
arr=arr+str(hex(i))[2:]+' '
crc08 =predefined.mkPredefinedCrcFun("crc8")
data = arr.replace(" ", "")
data = data.replace("0x", "")
readcrcout = hex(crc08(unhexlify(data))).upper()
str_list = list(readcrcout)
#print(unhexlify(data))
if len(str_list) < 4:
str_list.insert(2, '0' * (4 - len(str_list))) # 位数不足补0
crc_data = "".join(str_list)
print('CRC08校验:',crc_data)
if isinstance(read, str):
if "0x" in read:
read = read.strip() + ' ' +'0x'+ crc_data[2:4]
else:
read = read.strip() + ' ' + crc_data[2:4]
print('增加CRC8校验:>>>', read)
else:
aaa=int('0x'+crc_data[2:],16)
read.append(aaa)
print('增加CRC8校验:>>>','[{}]'.format(', '.join(hex(x) for x in read)))
return read
if __name__ == '__main__':
crc16Add("01 03 00 01 00 02")
第四步:直接调用这个crc_mod.py里面定义的函数即可
import CRC_mod
read= [0x31,0x32,0x33,0x34]
print('data=','[{}]'.format(', '.join(hex(x) for x in read)))
read=CRC_mod.crc16Add(read)
print('Array:','[{}]'.format(', '.join(hex(x) for x in read)))
print('==========================================')
read1='0x31 0x32 0x33 0x34'
print('data=',read1)
print('list with 0x:',CRC_mod.crc16Add(read1))
print('==========================================')
read2='31 32 33 34'
print('data=',read2)
print('list without 0x:',CRC_mod.crc16Add(read2))
运行结果如下:
>>> %Run -c $EDITOR_CONTENT
data= [0x31, 0x32, 0x33, 0x34]
CRC16校验: 0X30BA
增加Modbus CRC16校验:>>> [0x31, 0x32, 0x33, 0x34, 0xba, 0x30]
Array: [0x31, 0x32, 0x33, 0x34, 0xba, 0x30]
==========================================
data= 0x31 0x32 0x33 0x34
CRC16校验: 0X30BA
增加Modbus CRC16校验:>>> 0x31 0x32 0x33 0x34 0xBA 0x30
list with 0x: 0x31 0x32 0x33 0x34 0xBA 0x30
==========================================
data= 31 32 33 34
CRC16校验: 0X30BA
增加Modbus CRC16校验:>>> 31 32 33 34 BA 30
list without 0x: 31 32 33 34 BA 30
软件包下载:
mycropython可用的crcmod-Python文档类资源-CSDN文库
还有一个最精简的crc_16_ModBus: