在DS28EC20 20Kb的 1-Wire EEPROM上进行32字节扩展读取并计算CRC16的方法
我正在使用AD DS28EC20 1-wire EEPROM(原厂似乎是Maxim的),并且我尝试使用带CRC的 32字节扩展读取功能(命令0xA5)。我希望能得到本板块的一些CRC专家的帮助。我希望实现一个Python、Perl或 C的实现。
https://www.analog.com/en/products/ds28ec20.html
![扩展读取内存[A5h] 命令描述](/uploadfile/blog2026/a241559e02f14564abc2f8b792707cd4.jpg)

我已经把数据写入内存的前32字节。以下是读取到的32字节数据,加上 0xA5 指令和两个 0x00 地址字节——以及计算得到的CRC。因此,我相信总共需要35字节,包括命令字节 0xA5 和两个 0x00 地址字节,才能重现CRC。
0xA5
0x00
0x00
0x03
0x04
0x05
0x06
0x07
0x08
0x09
0x10
0x11
0x12
0x13
0x14
0x15
0x16
0x17
0x18
0x19
0x20
0x21
0x22
0x23
0x24
0x25
0x26
0x27
0x28
0x29
0x30
0x31
0x32
0x33
0x34
CRC: 0x1181 4481 0001000110000001
我写了一个粗糙的Perl脚本来计算数据,它读取一个包含这35字节数据的文件。
要从文件中读取的数据,以及脚本:
0xA5
0x00
0x00
0x03
0x04
0x05
0x06
0x07
0x08
0x09
0x10
0x11
0x12
0x13
0x14
0x15
0x16
0x17
0x18
0x19
0x20
0x21
0x22
0x23
0x24
0x25
0x26
0x27
0x28
0x29
0x30
0x31
0x32
0x33
0x34
#!/usr/bin/env perl
use strict;
use warnings;
my($file_old, $file_new) = @ARGV;
my $index = 0;
my $num;
my $num2;
my @number_set_1;
my $crc;
my $crc_init = 0;
#my $crc_init = 0xFFFF;
my $crc_n;
my $poly = hex("0x8005");
my $poly_reflected = hex("0xA001");
die "$file_old name must have at least three chars, $!" if length($file_old) < 3;
die "$file_new name must have at least three chars, $!" if length($file_new) < 3;
open (IN, "<$file_old") or die "Can't open $file_old, $!";
open (OUT, ">$file_new") or die "Can't open $file_new, $!";
print "\nPOLY: $poly \n\n";
while(my $line = <IN>) {
if(!($line !~ /\S/)) {
chomp($line);
#print "At Line Number $.: $line";
#print OUT "$line";
$number_set_1[$index] = hex($line);
$num = pack("C", $number_set_1[$index]); # "C" = unsigned char (byte)
$num2 = unpack("C",$num);
#print "$index $number_set_1[$index] \n";
print "$index $number_set_1[$index] $num2 \n";
$index ++;
}
}
print"\n\n";
printf("POLY = 0X%04X:\n\n", $poly);
$crc = $crc_init;
for(my $i = 0; $i < 34; $i++) {
$crc ^= $number_set_1[$i];
$crc = $crc & 1 ? ($crc >> 1) ^ $poly : $crc >> 1;
$crc = $crc & 1 ? ($crc >> 1) ^ $poly : $crc >> 1;
$crc = $crc & 1 ? ($crc >> 1) ^ $poly : $crc >> 1;
$crc = $crc & 1 ? ($crc >> 1) ^ $poly : $crc >> 1;
$crc = $crc & 1 ? ($crc >> 1) ^ $poly : $crc >> 1;
$crc = $crc & 1 ? ($crc >> 1) ^ $poly : $crc >> 1;
$crc = $crc & 1 ? ($crc >> 1) ^ $poly : $crc >> 1;
$crc = $crc & 1 ? ($crc >> 1) ^ $poly : $crc >> 1;
print "$i $number_set_1[$i] $crc\n";
}
$crc_n = ~$crc & 0xFFFF;
print"\nCRC: $crc\nCRC_N: $crc_n\n";
printf("\nCRC: 0X%04X\nCRC_N: 0X%04X\n", $crc, $crc_n);
print"\n\n";
printf("POLY = 0X%04X:\n\n", $poly_reflected);
$crc = $crc_init;
for(my $i = 0; $i < 34; $i++) {
$crc ^= $number_set_1[$i];
$crc = $crc & 1 ? ($crc >> 1) ^ $poly_reflected : $crc >> 1;
$crc = $crc & 1 ? ($crc >> 1) ^ $poly_reflected : $crc >> 1;
$crc = $crc & 1 ? ($crc >> 1) ^ $poly_reflected : $crc >> 1;
$crc = $crc & 1 ? ($crc >> 1) ^ $poly_reflected : $crc >> 1;
$crc = $crc & 1 ? ($crc >> 1) ^ $poly_reflected : $crc >> 1;
$crc = $crc & 1 ? ($crc >> 1) ^ $poly_reflected : $crc >> 1;
$crc = $crc & 1 ? ($crc >> 1) ^ $poly_reflected : $crc >> 1;
$crc = $crc & 1 ? ($crc >> 1) ^ $poly_reflected : $crc >> 1;
print "$i $number_set_1[$i] $crc\n";
}
$crc_n = ~$crc & 0xFFFF;
print"\nCRC: $crc\nCRC_N: $crc_n\n";
printf("\nCRC: 0X%04X\nCRC_N: 0X%04X\n\n", $crc, $crc_n);
close IN;
close OUT;
下面是脚本的输出:
POLY: 32773
0 165 165
1 0 0
2 0 0
3 3 3
4 4 4
5 5 5
6 6 6
7 7 7
8 8 8
9 9 9
10 16 16
11 17 17
12 18 18
13 19 19
14 20 20
15 21 21
16 22 22
17 23 23
18 24 24
19 25 25
20 32 32
21 33 33
22 34 34
23 35 35
24 36 36
25 37 37
26 38 38
27 39 39
28 40 40
29 41 41
30 48 48
31 49 49
32 50 50
33 51 51
34 52 52
POLY = 0X8005:
0 165 43780
1 0 23721
2 0 20318
3 3 49992
4 4 9410
5 5 42272
6 6 37536
7 7 34199
8 8 44417
9 9 14508
10 16 62526
11 17 48624
12 18 36536
13 19 24973
14 20 57190
15 21 59865
16 22 7657
17 23 6685
18 24 51997
19 25 23753
20 32 36697
21 33 59529
22 34 25067
23 35 63591
24 36 31227
25 37 64127
26 38 40959
27 39 34970
28 40 16009
29 41 24637
30 48 29539
31 49 40566
32 50 40091
33 51 55451
CRC: 55451
CRC_N: 10084
CRC: 0XD89B
CRC_N: 0X2764
POLY = 0XA001:
0 165 31680
1 0 20603
2 0 8976
3 3 52578
4 4 10829
5 5 13866
6 6 56631
7 7 5341
8 8 40917
9 9 39326
10 16 25625
11 17 50789
12 18 9862
13 19 28646
14 20 34286
15 21 33732
16 22 23811
17 23 3933
18 24 62414
19 25 24243
20 32 27934
21 33 4141
22 34 1104
23 35 58693
24 36 59428
25 37 49193
26 38 1152
27 39 47685
28 40 60795
29 41 64876
30 48 14845
31 49 21817
32 50 50964
33 51 6791
CRC: 6791
CRC_N: 58744
CRC: 0X1A87
CRC_N: 0XE578
进行了两次运算,一次使用非反射多项式,一次使用反射多项式。我认为应该与设备计算结果匹配的应该是CRC_N值。正如你所看到的,任何结果都没有与设备输出的CRC 0x1181 相符。
预期应当发生:计算得到设备计算的CRC为 0x1181。
实际发生的是:用非反射多项式计算得到的CRC为 0x2764,用反射多项式计算得到的CRC为 0xE578,对应的多项式分别是 0x8001 和 0xA001。
欢迎任何帮助或想法。
解决方案
首先,你的Perl非反射CRC代码是错误的。
对于那部分,你需要把数据字节向上移位:
$crc ^= $number_set_1[$i] << 8;
并且你需要用 0x8000 进行测试,而不是 1,并且需要把数据向上移位:
$crc = $crc & 0x8000 ? ($crc << 1) ^ $poly : $crc << 1;
你的反射CRC代码是正确的。
然而你的输出有问题,即使是反射CRC也不对。你并没有对你指定的这35字节进行CRC计算,而是只对前34字节进行了计算。
在对这35个字节进行计算时,我得到非反射为 0xe6b5,反射为 0x4aa4。
即便CRC计算正确,这两者及其反码都与您声称的 0x1181 CRC不匹配。你可能需要更仔细地检查你是如何确定那就是CRC的。我预计应使用的是反射CRC。