一个非常特殊的编译器问题

时间:2011-12-14 11:25:08

标签: c compiler-construction embedded microcontroller

我在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];
}

allCertPagesbyte[]

微观必须验证校验和确实是从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 ?? !!)

PIC16F Debug

1 个答案:

答案 0 :(得分:8)

如果您的代码与您说的一样,那么主要问题是您的测试本身:

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 ...无法帮助你...我的观点只是你在零分支。您可以尝试一个干净的构建,看看它是否仍然这样说。 (程序的调试符号可能已过时或其他什么?)