tag 标签: crc

相关帖子
相关博文
  • 热度 6
    2020-8-9 11:57
    2807 次阅读|
    2 个评论
    一、介绍 CRC即循环冗余校验码(Cyclic Redundancy Check): 是一种根据网络数据包或计算机文件等数据产生简短固定位数校验码的一种信道编码技术,主要用来检测或校验数据传输或者保存后可能出现的错误。 数据通信领域中最常用的一种差错校验码,其信息字段和校验字段长度可以任意指定,但要求通信双方定义的CRC标准一致。 二、原理 基础原理来源于模2运算,通过除多项式取余数的方法得到CRC校验码。 多项式写法 例如 crc 16 ibm 多项式为: x 16 + x 15 + x 2 + 1 16进制形式为 0x18005 其简记形式为0x8005, 我们大部分看到的是0x8005。 因为 多项式的首尾必定为1。 1 xor 1 结果必定是0. 输入值反转的意思是在计算之前先将二项式反转,然后再用得到的新值和数据进行计算。 输入输出 初始值需异或。即 先将要计算的数据与初始值的最低字节进行异或,然后再与多项式进行计算。 三、在线计算工具 CRC(循环冗余校验)在线计算_ip33.com 网址:http://www.ip33.com/crc.html 特点:只有 crc 校验不过有个好处可以自定义crc 格式。 CRC校验工具-在线工具 网址:http://www.metools.info/code/c15.html 特点:不仅有crc 校验工具还有其他计算工具,不足是crc 只能选着标准格式,不能自定义格式。 总结:两个工具使用都很不错,支持16进制和ascii 对复制过来的文件也很友好。 四、编程实现 实现方式主要分为两种 查表法。优点速度快,缺点占用一定的内存空间。 直接计算法。 优点占用内存空间小,缺点需要一定的计算量。 源码实现(来源于网络没有找到原作者): uint8_t crc4_itu(uint8_t *data, uint_len length); uint8_t crc5_epc(uint8_t *data, uint_len length); uint8_t crc5_itu(uint8_t *data, uint_len length); uint8_t crc5_usb(uint8_t *data, uint_len length); uint8_t crc6_itu(uint8_t *data, uint_len length); uint8_t crc7_mmc(uint8_t *data, uint_len length); uint8_t crc8(uint8_t *data, uint_len length); uint8_t crc8_itu(uint8_t *data, uint_len length); uint8_t crc8_rohc(uint8_t *data, uint_len length); uint8_t crc8_maxim(uint8_t *data, uint_len length);//DS18B20 uint16_t crc16_ibm(uint8_t *data, uint_len length); uint16_t crc16_maxim(uint8_t *data, uint_len length); uint16_t crc16_usb(uint8_t *data, uint_len length); uint16_t crc16_modbus(uint8_t *data, uint_len length); uint16_t crc16_ccitt(uint8_t *data, uint_len length); uint16_t crc16_ccitt_false(uint8_t *data, uint_len length); uint16_t crc16_x25(uint8_t *data, uint_len length); uint16_t crc16_xmodem(uint8_t *data, uint_len length); uint16_t crc16_dnp(uint8_t *data, uint_len length); uint32_t crc32(uint8_t *data, uint_len length); uint32_t crc32_mpeg_2(uint8_t *data, uint_len length); /****************************************************************************** * Name: CRC-4/ITU x4+x+1 * Poly: 0x03 * Init: 0x00 * Refin: True * Refout: True * Xorout: 0x00 * Note: *****************************************************************************/ uint8_t crc4_itu(uint8_t *data, uint_len length) { uint8_t i; uint8_t crc = 0; // Initial value while(length--) { crc ^= *data++; // crc ^= *data; data++; for (i = 0; i < 8; ++i) { if (crc & 1) (8-4) else 1); } } return crc; } /****************************************************************************** * Name: CRC-5/EPC x5+x3+1 * Poly: 0x09 * Init: 0x09 * Refin: False * Refout: False * Xorout: 0x00 * Note: *****************************************************************************/ uint8_t crc5_epc(uint8_t *data, uint_len length) { uint8_t i; uint8_t crc = 0x48; // Initial value: 0x48 = 0x09<<(8-5) while(length--) { crc ^= *data++; // crc ^= *data; data++; for ( i = 0; i < 8; i++ ) { if ( crc & 0x80 ) crc = (crc << 1) ^ 0x48; // 0x48 = 0x09<<(8-5) else crc <<= 1; } } 3; } /****************************************************************************** * Name: CRC-5/ITU x5+x4+x2+1 * Poly: 0x15 * Init: 0x00 * Refin: True * Refout: True * Xorout: 0x00 * Note: *****************************************************************************/ uint8_t crc5_itu(uint8_t *data, uint_len length) { uint8_t i; uint8_t crc = 0; // Initial value while(length--) { crc ^= *data++; // crc ^= *data; data++; for (i = 0; i < 8; ++i) { if (crc & 1) (8-5) else 1); } } return crc; } /****************************************************************************** * Name: CRC-5/USB x5+x2+1 * Poly: 0x05 * Init: 0x1F * Refin: True * Refout: True * Xorout: 0x1F * Note: *****************************************************************************/ uint8_t crc5_usb(uint8_t *data, uint_len length) { uint8_t i; uint8_t crc = 0x1F; // Initial value while(length--) { crc ^= *data++; // crc ^= *data; data++; for (i = 0; i < 8; ++i) { if (crc & 1) (8-5) else 1); } } return crc ^ 0x1F; } /****************************************************************************** * Name: CRC-6/ITU x6+x+1 * Poly: 0x03 * Init: 0x00 * Refin: True * Refout: True * Xorout: 0x00 * Note: *****************************************************************************/ uint8_t crc6_itu(uint8_t *data, uint_len length) { uint8_t i; uint8_t crc = 0; // Initial value while(length--) { crc ^= *data++; // crc ^= *data; data++; for (i = 0; i < 8; ++i) { if (crc & 1) (8-6) else 1); } } return crc; } /****************************************************************************** * Name: CRC-7/MMC x7+x3+1 * Poly: 0x09 * Init: 0x00 * Refin: False * Refout: False * Xorout: 0x00 * Use: MultiMediaCard,SD,ect. *****************************************************************************/ uint8_t crc7_mmc(uint8_t *data, uint_len length) { uint8_t i; uint8_t crc = 0; // Initial value while(length--) { crc ^= *data++; // crc ^= *data; data++; for ( i = 0; i < 8; i++ ) { if ( crc & 0x80 ) crc = (crc << 1) ^ 0x12; // 0x12 = 0x09<<(8-7) else crc <<= 1; } } 1; } /****************************************************************************** * Name: CRC-8 x8+x2+x+1 * Poly: 0x07 * Init: 0x00 * Refin: False * Refout: False * Xorout: 0x00 * Note: *****************************************************************************/ uint8_t crc8(uint8_t *data, uint_len length) { uint8_t i; uint8_t crc = 0; // Initial value while(length--) { crc ^= *data++; // crc ^= *data; data++; for ( i = 0; i < 8; i++ ) { if ( crc & 0x80 ) crc = (crc << 1) ^ 0x07; else crc <<= 1; } } return crc; } /****************************************************************************** * Name: CRC-8/ITU x8+x2+x+1 * Poly: 0x07 * Init: 0x00 * Refin: False * Refout: False * Xorout: 0x55 * Alias: CRC-8/ATM *****************************************************************************/ uint8_t crc8_itu(uint8_t *data, uint_len length) { uint8_t i; uint8_t crc = 0; // Initial value while(length--) { crc ^= *data++; // crc ^= *data; data++; for ( i = 0; i < 8; i++ ) { if ( crc & 0x80 ) crc = (crc << 1) ^ 0x07; else crc <<= 1; } } return crc ^ 0x55; } /****************************************************************************** * Name: CRC-8/ROHC x8+x2+x+1 * Poly: 0x07 * Init: 0xFF * Refin: True * Refout: True * Xorout: 0x00 * Note: *****************************************************************************/ uint8_t crc8_rohc(uint8_t *data, uint_len length) { uint8_t i; uint8_t crc = 0xFF; // Initial value while(length--) { crc ^= *data++; // crc ^= *data; data++; for (i = 0; i < 8; ++i) { if (crc & 1) 1) ^ 0xE0; // 0xE0 = reverse 0x07 else 1); } } return crc; } /****************************************************************************** * Name: CRC-8/MAXIM x8+x5+x4+1 * Poly: 0x31 * Init: 0x00 * Refin: True * Refout: True * Xorout: 0x00 * Alias: DOW-CRC,CRC-8/IBUTTON * Use: Maxim(Dallas)'s some devices,e.g. DS18B20 *****************************************************************************/ uint8_t crc8_maxim(uint8_t *data, uint_len length) { uint8_t i; uint8_t crc = 0; // Initial value while(length--) { crc ^= *data++; // crc ^= *data; data++; for (i = 0; i < 8; i++) { if (crc & 1) 1) ^ 0x8C; // 0x8C = reverse 0x31 else = 1; } } return crc; } /****************************************************************************** * Name: CRC-16/IBM x16+x15+x2+1 * Poly: 0x8005 * Init: 0x0000 * Refin: True * Refout: True * Xorout: 0x0000 * Alias: CRC-16,CRC-16/ARC,CRC-16/LHA *****************************************************************************/ uint16_t crc16_ibm(uint8_t *data, uint_len length) { uint8_t i; uint16_t crc = 0; // Initial value while(length--) { crc ^= *data++; // crc ^= *data; data++; for (i = 0; i < 8; ++i) { if (crc & 1) 1) ^ 0xA001; // 0xA001 = reverse 0x8005 else 1); } } return crc; } /****************************************************************************** * Name: CRC-16/MAXIM x16+x15+x2+1 * Poly: 0x8005 * Init: 0x0000 * Refin: True * Refout: True * Xorout: 0xFFFF * Note: *****************************************************************************/ uint16_t crc16_maxim(uint8_t *data, uint_len length) { uint8_t i; uint16_t crc = 0; // Initial value while(length--) { crc ^= *data++; // crc ^= *data; data++; for (i = 0; i < 8; ++i) { if (crc & 1) 1) ^ 0xA001; // 0xA001 = reverse 0x8005 else 1); } } return ~crc; // crc^0xffff } /****************************************************************************** * Name: CRC-16/USB x16+x15+x2+1 * Poly: 0x8005 * Init: 0xFFFF * Refin: True * Refout: True * Xorout: 0xFFFF * Note: *****************************************************************************/ uint16_t crc16_usb(uint8_t *data, uint_len length) { uint8_t i; uint16_t crc = 0xffff; // Initial value while(length--) { crc ^= *data++; // crc ^= *data; data++; for (i = 0; i < 8; ++i) { if (crc & 1) 1) ^ 0xA001; // 0xA001 = reverse 0x8005 else 1); } } return ~crc; // crc^0xffff } /****************************************************************************** * Name: CRC-16/MODBUS x16+x15+x2+1 * Poly: 0x8005 * Init: 0xFFFF * Refin: True * Refout: True * Xorout: 0x0000 * Note: *****************************************************************************/ uint16_t crc16_modbus(uint8_t *data, uint_len length) { uint8_t i; uint16_t crc = 0xffff; // Initial value while(length--) { crc ^= *data++; // crc ^= *data; data++; for (i = 0; i < 8; ++i) { if (crc & 1) 1) ^ 0xA001; // 0xA001 = reverse 0x8005 else 1); } } return crc; } /****************************************************************************** * Name: CRC-16/CCITT x16+x12+x5+1 * Poly: 0x1021 * Init: 0x0000 * Refin: True * Refout: True * Xorout: 0x0000 * Alias: CRC-CCITT,CRC-16/CCITT-TRUE,CRC-16/KERMIT *****************************************************************************/ uint16_t crc16_ccitt(uint8_t *data, uint_len length) { uint8_t i; uint16_t crc = 0; // Initial value while(length--) { crc ^= *data++; // crc ^= *data; data++; for (i = 0; i < 8; ++i) { if (crc & 1) 1) ^ 0x8408; // 0x8408 = reverse 0x1021 else 1); } } return crc; } /****************************************************************************** * Name: CRC-16/CCITT-FALSE x16+x12+x5+1 * Poly: 0x1021 * Init: 0xFFFF * Refin: False * Refout: False * Xorout: 0x0000 * Note: *****************************************************************************/ uint16_t crc16_ccitt_false(uint8_t *data, uint_len length) { uint8_t i; uint16_t crc = 0xffff; //Initial value while(length--) { crc ^= (uint16_t)(*data++) << 8; // crc ^= (uint6_t)(*data)<<8; data++; for (i = 0; i < 8; ++i) { if ( crc & 0x8000 ) crc = (crc << 1) ^ 0x1021; else crc <<= 1; } } return crc; } /****************************************************************************** * Name: CRC-16/X25 x16+x12+x5+1 * Poly: 0x1021 * Init: 0xFFFF * Refin: True * Refout: True * Xorout: 0XFFFF * Note: *****************************************************************************/ uint16_t crc16_x25(uint8_t *data, uint_len length) { uint8_t i; uint16_t crc = 0xffff; // Initial value while(length--) { crc ^= *data++; // crc ^= *data; data++; for (i = 0; i < 8; ++i) { if (crc & 1) 1) ^ 0x8408; // 0x8408 = reverse 0x1021 else 1); } } return ~crc; // crc^Xorout } /****************************************************************************** * Name: CRC-16/XMODEM x16+x12+x5+1 * Poly: 0x1021 * Init: 0x0000 * Refin: False * Refout: False * Xorout: 0x0000 * Alias: CRC-16/ZMODEM,CRC-16/ACORN *****************************************************************************/ uint16_t crc16_xmodem(uint8_t *data, uint_len length) { uint8_t i; uint16_t crc = 0; // Initial value while(length--) { crc ^= (uint16_t)(*data++) << 8; // crc ^= (uint16_t)(*data)<<8; data++; for (i = 0; i < 8; ++i) { if ( crc & 0x8000 ) crc = (crc << 1) ^ 0x1021; else crc <<= 1; } } return crc; } /****************************************************************************** * Name: CRC-16/DNP x16+x13+x12+x11+x10+x8+x6+x5+x2+1 * Poly: 0x3D65 * Init: 0x0000 * Refin: True * Refout: True * Xorout: 0xFFFF * Use: M-Bus,ect. *****************************************************************************/ uint16_t crc16_dnp(uint8_t *data, uint_len length) { uint8_t i; uint16_t crc = 0; // Initial value while(length--) { crc ^= *data++; // crc ^= *data; data++; for (i = 0; i < 8; ++i) { if (crc & 1) 1) ^ 0xA6BC; // 0xA6BC = reverse 0x3D65 else 1); } } return ~crc; // crc^Xorout } /****************************************************************************** * Name: CRC-32 x32+x26+x23+x22+x16+x12+x11+x10+x8+x7+x5+x4+x2+x+1 * Poly: 0x4C11DB7 * Init: 0xFFFFFFF * Refin: True * Refout: True * Xorout: 0xFFFFFFF * Alias: CRC_32/ADCCP * Use: WinRAR,ect. *****************************************************************************/ uint32_t crc32(uint8_t *data, uint_len length) { uint8_t i; uint32_t crc = 0xffffffff; // Initial value while(length--) { crc ^= *data++; // crc ^= *data; data++; for (i = 0; i < 8; ++i) { if (crc & 1) 1) ^ 0xEDB88320;// 0xEDB88320= reverse 0x04C11DB7 else 1); } } return ~crc; } /****************************************************************************** * Name: CRC-32/MPEG-2 x32+x26+x23+x22+x16+x12+x11+x10+x8+x7+x5+x4+x2+x+1 * Poly: 0x4C11DB7 * Init: 0xFFFFFFF * Refin: False * Refout: False * Xorout: 0x0000000 * Note: *****************************************************************************/ uint32_t crc32_mpeg_2(uint8_t *data, uint_len length) { uint8_t i; uint32_t crc = 0xffffffff; // Initial value while(length--) { crc ^= (uint32_t)(*data++) << 24;// crc ^=(uint32_t)(*data)<<24; data++; for (i = 0; i < 8; ++i) { if ( crc & 0x80000000 ) crc = (crc << 1) ^ 0x04C11DB7; else crc <<= 1; } } return crc; } 最后附上看着原理写的不错的链接 :https://segmentfault.com/a/1190000018094567 ﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌﹌ 免责声明:本文部分内容来源网络 ,版权归原作者所有,如涉及作品版权问题,请及时与我们联系,谢谢!
  • 热度 19
    2014-9-17 13:32
    1247 次阅读|
    4 个评论
    1.功能介绍 自动支持多种分隔码 空格(默认) 逗号 C语言数组常用 支持多种校验码计算方式 CRC16(modbus)(默认) 校验码补齐到原数据末尾,自动添加分隔符 多进制选择 10进制 16进制(默认) 当数据中含有H或0x字样时,自动选择16进制 当数据中含有“A B C D E F”字码时,自动选择16进制 自动识别非法字符 复制,粘帖功能
  • 热度 22
    2013-12-15 17:02
    1044 次阅读|
    0 个评论
    总体来说PIC24F内部的CRC模块真是用起来很不方便!最主要的是不同的数据手册与文档给出的例程代码思路竟不相同,并且计算的关键部分数据手册竟没有说明 ,搞的我调了好久才成功! 在16位多项式和8位数据宽度情况下计算CRC请参考MicroChip应用笔记AN1148,其它的文档与例程移植起来都有一定的问题!
  • 热度 23
    2013-4-7 10:37
    2028 次阅读|
    4 个评论
    国家兴亡匹夫有责,从神九用到 CAN 总线讲起( 6 )方法很关键   我们很多应用选用 CAN 总线是因为它特别可靠,按 CiA 的宣传资料是一千年才会发生一次错帧残留,按 Bosch CAN2.0 规范是帧出错率 *4.7*10 -11 。其中 4.7*10 -11 是错帧漏检率 Pun ,而帧出错率 *Pun 是错帧残留率 Pres 。一千年一次在我们有生之年是碰不到的,自然非常好,不过它这个值错了, 错误的数据会导致盲目乐观的态度 。   它的计算过程是:假定误码率为每 0.7 秒有 1 位错,当位时间为 2us 时,有 ber= 1/ ( 0.7*10 6 /2 ) =2.8*10 -6 并以此来计算公式中的 error rate 。这是简化的情况,与 Bosch 分析时采用的方法不同,在那里 error rate 相当于 bad 状态概率,例如分析时采用的为 10 -3 ,在帧长为 100bit 时,它的计算偏小了约 3 倍。   假定总线工作于 500kbps ,总线负载率为 40% ,平均帧长为 100 bit ,那么每小时送 7.2×10 6 个帧。按我的计算结果(见以后博文),错帧漏检率 Pun=1.15*10 -7 , 在 bad 状态概率为 1*10 -3 时错帧残留率是 1.15*10 -10 ,每小时的失效率是 8.82×10 -4 /h 。也就是每 1200 小时 =50 天要失效一次。如果像上面 CiA 介绍总线负载率为 100% 时,就会是每 20 天失效一次。   有人会说,我的系统从来没有失效过。说到数值问题,第一是你的系统可能干扰较少,在单帧长度为统计误码率时遇到的最坏情况远小于 1*10 -3 ,但是你不能否定别人的最坏情况可能达到 1*10 -3 ;第二,许多应用属于闭环控制,由于对象的响应比较慢,即使有错帧漏检,其引起的扰动刚开始就被新来的正确数据纠正了,你就没有感觉,但是你不能否定存在无法及时更新的可能性;第三,也许你在应用上还有别的纠错措施使错帧的影响减弱了,例如各种滤波算法,所以你感觉不到,但是你已经付出了相应的代价,例如降低了系统的动态指标。   现在说可信赖性分析方法。对整个国家而言,平均概率是重要的。但是最坏情况发生时,人身和财产损失对当事人是百分之百地已经发生。所以要按最坏概率作出发点。例如一,人的价值是无价的,所以欧美各国已进入到目标为交通零伤亡的时代,如果你的车不以此为目标,你就会在竞争中失败;例如二,有的项目全国都只有有限的数量,一次失效都是难以承受的,例如火箭卫星**之类。所以无论民用或军工都该以最坏情况作出发点。   关于错帧漏检的分析方法,据我所知大致有几种方法:第一是用软件仿真的方法,可以有控制地注入位错,然后按协议的规定检查,错帧是否溜过去,不过一般采取随机注入位错的方法,即一般随机测试的 Monte Carlo 方法;第二种是用分析方法,构造出会溜过去的帧,然后统计这种帧的个数,我就是用这种方法;也许还有第三种,用形式逻辑的方法来分析,不过我还不懂,不知道是否走得通。   Bosch 采用的是第一种方法。( J. Unruh, H.J. Mathony, K.H. Kaiser: "Error Detection Analysis of Automotive Communication Protocols". SAE Int. Congress, No. 900699, ?xml:namespace prefix = st1 /Detroit, USA, 1990. ) Bosch 对造成错帧漏检的二种原因均有论述,第一种原因是 CAN 位填充规则时出错发生部分数据流相位移动,第二次是出错又使相位又对上了,在有相移的部分造成收发数据比较时有大量差,超出了 CRC 检出错的能力;第二种是在定义帧长度的位中出了错,收发二边对帧长度有了不同理解,碰巧后边又发生位错,使变形后的帧通过了 CRC 检验和格式检验。关于这二种情况我后面都要用到,到时候详细介绍。   采用软件仿真的办法要求概率的分布是均匀的,而且样本的量较大,正是在这二点细节上这种办法是有缺点的,从而导致结果的准确度低。 首先出现漏检事件的出错位分布不是均匀的,发生在标识位等处的错会因数据移相,造成帧长变化而较易检测出来,不易漏检;而发生在数据域内的错则除了 CRC 检验没有其他检验可发现,易漏检;发生在帧尾部的错立马就被视作格式错,不漏检。 其次是样本的大小, Bosch 文章中针对的是 80~90 位的帧, CRC 检验的覆盖面为 58~66 位,这样帧本身就有 2 58 =2.88×10 17 种,注入的位置有 58×57/2 组,全部实例有 4.76×10 20 个。每一个帧在注入错前后要算二次 CRC ,还要做其他格式检查。例如有没有发生填充位错,有没有发生帧长变化导致格式错等。现仅就 CRC 检验来说:每个学过 CRC 计算的人都知道它要分很多步骤, 1989 年左右还是 16 位机的时代(例如 VAX11 系列),假定累加器由 A 构成,生成多项式为立即数 G ,步骤有 1. 如 A15=0 跳到第 3 步,否则进到 2 , 2.A 与 G 异或, 3. 进位位设新数据, 4.A 与进位位左移一位, 5. 判 CRC 覆盖区是否结束,如否则回到 1 ,如是就结束。 一位要循环 5 步,就算用机器代码,那时的计算机还只在 10M 左右,即 0.5us 。完成 58 位循环要 29us ,验算一条帧需 58us 。于是可以算出不停机运行一年可检验 365*24*3600*10 6 /58=5.43*10 11 条帧。全部实例有 4.76×10 20 个,可见测试的样本还不到实例的 10 -8 。即使当时的计算机速度估计不准,仍然是样本太小了。   样本小要作结论是无法置信的,例如 100 万辆车你遇到 1 辆性能很好就说车好,或者你遇到 1 辆车坏了就说车一塌胡涂都是偏颇的。   虽然 CiA 一方面推荐 Bosch 的残差值:出错率 *4.7*10 -11 ,实际上 CiA 还给出了另一个更大的残差值: CiA, CiA Draft Standard 304 V1.0.1 “CANopen framework for safety-relevant communication” ,第 26 页: The worst case residual error probability of the CAN protocol is P Re st = 7 * 10 -9 ,它来自一篇 Joachim Charzinski 的论文,在那里有: Pres7.2*10 -9 * q bad 。 所以他们自己已否定了 Bosch 的残差值。只是 CANopen 中的值还是比我的数据 1.15*10 -7 小了很多。
  • 热度 26
    2012-1-6 10:47
    2564 次阅读|
    1 个评论
    在网上搜索了很久,18B20的CRC校验只有C51的,没有发现A51汇编子程序,只好自己动手。入口:8字节数据在40H——47H,出口:CRC校验结果在B中。子程序如下:(有更精简的朋友请留言) calibration:   MOV  B,#0   MOV  R0,#40H   calib_0:   MOV  R6,#8   MOV  A,@R0   calib_1:   RRC  A   PUSH ACC   MOV  A,B   RR  A   MOV  B.7,C   XRL  B,A   MOV  C,B.7   MOV  ACC.7,C   MOV  B.3,C   MOV  B.2,C   XRL  B,A   MOV  C,B.3   MOV  ACC.3,C   MOV  C,B.2   MOV  ACC.2,C   MOV  B,A     POP  ACC   DJNZ R6,calib_1   INC  R0   CJNE R0,#48H,calib_0   RET  
相关资源