【发布时间】:2011-12-14 11:25:08
【问题描述】:
我已经用 C 语言编写了 PIC16F1947 的代码。我正在使用以下代码:
- MPLAB IDE 8.73
- HI-TECH C 编译器 9.81
部分代码处理来自 PC 的数据。我从 PC 发送的特定数据包是 325 字节。该数据包如下所示:
data: 0, 64, 1, 0, 255, 255, 255, ... (all 255) ..., 255, 1
index: 0 1 2 3 4 5 6 323 324
数据包的内容显示为 8 位十进制值(8 位无符号整数)。 micro将其存储在unsigned char的数组中:
unsigned char _command_mgr_buff[330];
unsigned char 是 PIC16F 的 8 位无符号整数。
包的最后一个字节,即索引324,是包的校验和。它是索引 1 到 323 的总和,包括 1 和 323。计算此校验和的 PC 代码(C# 中)如下:
allCertPages[324] = 0;
for (int i = 1; i <= 323; i++)
{
allCertPages[324] += allCertPages[i];
}
allCertPages 是 byte[]。
微机必须验证校验和确实是从 PC 传递的值。这是我为PIC16F编写的验证码,包括一些调试信息:
param0 = _command_mgr_buff[324]; // param0 is unsigned int, 16 bit
param1 = _command_mgr_buff[324]; // param1 is unsigned int, 16 bit
// Checksum verification
for (var = 1; var <= 323; var++) // var is unsigned int, 16 bit
{
_command_mgr_buff[324] -= _command_mgr_buff[var];
param1 -= _command_mgr_buff[var];
}
if (!_command_mgr_buff[324])
{
send_status(CS_BAD_PARAM);
}
这个想法是从校验和中减去 [1, 323] 范围内的所有值。如果最终值为 0,则校验和是正确的。否则,如果_command_mgr_buff[324]在减法后发现非零,则校验和不正确。
在调试模式(以及发布模式)下执行代码后,我在_command_mgr_buff[324] 中得到非零值(所以send_status(CS_BAD_PARAM); 被执行,PC 认为有问题),但在param1的低字节!
这怎么可能?!
如果您有兴趣,这里是为非零检查生成的程序集:
8780 ;mgr_command.c: 1230: if (!_command_mgr_buff[324])
8781 0E89 30EA movlw low(8870+0144h)
8782 0E8A 00D3 movwf (??_command_mgr_run+0)^080h+0
8783 0E8B 3023 movlw high(8870+0144h)
8784 0E8C 00D4 movwf (??_command_mgr_run+0)^080h+0+1
8785 0E8D 0853 movf 0+(??_command_mgr_run+0)^080h+0,w
8786 0E8E 0086 movwf fsr1l
8787 0E8F 0854 movf 1+(??_command_mgr_run+0)^080h+0,w
8788 0E90 0087 movwf fsr1h
8789
8790 0E91 0881 movf indf1,f
8791 0E92 1D03 skipz
8792 0E93 2E95 goto u10101
8793 0E94 2E96 goto u10100
8794 0E95 u10101:
8795 0E95 2E9B goto l55070
8796 0E96 u10100:
8797 line 1232
8798
8799 0E96 l55068:
8800 ;mgr_command.c: 1231: {
8801 ;mgr_command.c: 1232: send_status(0x11);
8802 0E96 3011 movlw (011h)
8803 0E97 31B6 2693 3188 fcall _send_status
8804 line 1233
8805 ;mgr_command.c: 1233: }
8806 0E9A 2FE3 goto l45048
8807 line 1234
这是调试过程中截取的屏幕截图。请检查右侧的 Watch 窗口和第 324 个元素的工具提示。
-
param0应该是 1 -
param1 & 0xFF应该是 0 _command_mgr_buff[324]应为 0(工具提示显示 0x0F??!!)
【问题讨论】:
-
您的固件还在做什么?如果要检查是否是导致问题的校验和计算(不太可能),则应将代码减少为仅使用静态 const 数组中的数据值进行校验和计算。否则,如果它是一个完整的系统,它可能是任何东西:PC 发送另一个字符串,部分覆盖第一个字符串,其他缓冲区溢出,未保留所有必需寄存器的 ASM ISR,等等。
-
324 是 _command_mgr_buff[324] 的错误索引。顺便说一句 sizeof 可以帮助您避免所有这些文字数字。恕我直言,一个程序应该只包含三个数字:0、1 和 sizeof。
-
@wildplasser:PC和micro之间的通信协议是严格定义的,不会改变。如果需要对协议进行任何更改,则将创建一个新命令。此外,数组 _command_mgr_buff 的大小为 330。sizeof 在这里不起作用。
-
我的立场是正确的。顺便说一句,你为什么要和
allCertPages[324]相加;你应该很容易地求和一个无符号的临时变量并将最终值分配给allCertPages[324]。 (无符号类型之间的“向下转换”保证是模截断)。WRT sizeof:我的代码片段中仍然有太多的幻数。 (也许你这样做是为了让解释更容易?) -
@wildplasser:关于汇总到 allCertPages[324],我看不出你的方法和我的做法有什么区别。关于幻数,也许我可以将 WRITE_CERT_CHECKSUM 定义为 324 并使用它。
标签: c compiler-construction embedded microcontroller