一个极其特殊的编译器问题
我已经用 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 位无符号整数)。微控制器将其存储在 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
这是调试期间截取的屏幕截图。请检查右侧的“监视”窗口和第 324 个元素的工具提示。
param0
应为 1param1 & 0xFF
应为 0_command_mgr_buff[324]
应为 0(工具提示显示 0x0F??!!)
I've written code for PIC16F1947 in C. I am using the following:
- MPLAB IDE 8.73
- HI-TECH C Compiler 9.81
A part of the code deals with data coming from PC. The specific packet I'm sending from PC is 325 bytes. This packet looks as follows:
data: 0, 64, 1, 0, 255, 255, 255, ... (all 255) ..., 255, 1
index: 0 1 2 3 4 5 6 323 324
The contents of the packet are shown as 8 bit decimal value (8 bit unsigned integer). The micro stores it in an array of unsigned char
:
unsigned char _command_mgr_buff[330];
unsigned char
is the 8 bit unsigned integer for PIC16F.
The last byte of the packet, ie index 324, is the checksum of the packet. It is the summation of index 1 through 323, including 1 and 323. The PC code (in C#) that calculates this checksum is as follows:
allCertPages[324] = 0;
for (int i = 1; i <= 323; i++)
{
allCertPages[324] += allCertPages[i];
}
allCertPages
is a byte[]
.
The micro must verify that the checksum is indeed the value passed from PC. Here is the verification code that I've written for PIC16F, including some debug information:
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);
}
The idea is to subtract all values within the range [1, 323] from the checksum. If the final value is 0, then checksum is correct. Otherwise, if _command_mgr_buff[324]
is found non-zero after subtraction, then the checksum is incorrect.
After executing the code in debug mode (and also in release mode), I'm getting non-zero value in _command_mgr_buff[324]
(so send_status(CS_BAD_PARAM);
gets executed and the PC thinks something is wrong), but zero in the lower byte of param1
!
How is that possible?!
In case you're interested, here is the assembly generated for the non-zero checking:
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
Here is a screenshot taken during debugging. Please check the Watch window in the right and the tooltip for 324-th element.
param0
should be 1param1 & 0xFF
should be 0_command_mgr_buff[324]
should be 0 (tooltip shows 0x0F??!!)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
如果你的代码如你所说,这里的主要问题是你的测试本身:
如果结果是你想要的(即零),你就发送信号......
这是我不喜欢布尔值的原因之一测试非布尔值。布尔变量的名称通常会提示您正确读取它们捕获的条件,例如
if (isLoaded)
或if (!anyErrors)
...但这并不成立对于数字。因此,更容易确保您已经获得了想要写出来的语义:至于为什么您的调试器给您 0x0F...无法帮助您...我的观点是您是在零分支中。您可以尝试一个干净的构建,看看它是否仍然这样说。 (程序的调试符号可能已过时或其他原因?)
If your code is as you say, the main problem here is your test itself:
You're sending the signal if the result is what you want (namely zero)...
This is one of the reasons why I don't like boolean testing of non-boolean values. Boolean variables often have names that cue you into reading the condition they capture correctly, like
if (isLoaded)
orif (!anyErrors)
...and that doesn't hold for numerics. So it's easier to make sure you've got the semantics you want to just write it out:As for why your debugger is giving you the 0x0F...can't help you there...my point just being that you're in the zero branch. You might try a clean build and see if it still says that. (The program's debug symbols could be out of date or something?)