一个极其特殊的编译器问题

发布于 2024-12-21 07:16:25 字数 3467 浏览 2 评论 0原文

我已经用 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 应为 1
  • param1 & 0xFF 应为 0
  • _command_mgr_buff[324] 应为 0(工具提示显示 0x0F??!!)

PIC16F 调试

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 1
  • param1 & 0xFF should be 0
  • _command_mgr_buff[324] should be 0 (tooltip shows 0x0F??!!)

PIC16F Debug

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

杀手六號 2024-12-28 07:16:25

如果你的代码如你所说,这里的主要问题是你的测试本身:

if (!_command_mgr_buff[324])
{
    send_status(CS_BAD_PARAM);
}

如果结果是你想要的(即零),你就发送信号......

这是我不喜欢布尔值的原因之一测试非布尔值。布尔变量的名称通常会提示您正确读取它们捕获的条件,例如 if (isLoaded)if (!anyErrors)...但这并不成立对于数字。因此,更容易确保您已经获得了想要写出来的语义:

if (_command_mgr_buff[324] != 0) 
{
    send_status(CS_BAD_PARAM);
}

至于为什么您的调试器给您 0x0F...无法帮助您...我的观点是您是在零分支中。您可以尝试一个干净的构建,看看它是否仍然这样说。 (程序的调试符号可能已过时或其他原因?)

If your code is as you say, the main problem here is your test itself:

if (!_command_mgr_buff[324])
{
    send_status(CS_BAD_PARAM);
}

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) or if (!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:

if (_command_mgr_buff[324] != 0) 
{
    send_status(CS_BAD_PARAM);
}

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?)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文