在 C 中定义整数解析为无符号字符,或在数学运算的情况下产生意外行为

Defining integer in C resolves to unsigned char, or produces unexpected behavior in case of math operations

我正在开发一个微控制器,我想对结果值实施一个简单的平均滤波器以滤除噪音(或者老实说,不要让值在 LCD 上跳动!)。

ADC结果通过DMA插入内存。我有一个大小为 8 的数组(只是为了便于调试)。为了让生活更轻松,我写了一些 defines 使我的代码可以轻松编辑:

#define FP_ID_POT_0             0  //identifier for POT_0
#define FP_ID_POT_1             1  //identifier for POT_1
#define FP_ANALOGS_BUFFER_SIZE  8 //buffer size for filtering ADC vals
#define FP_ANALOGS_COUNT        2  // we have now 2 analog axis
#define FP_FILTER_ELEMENT_COUNT  FP_ANALOGS_BUFFER_SIZE / FP_ANALOGS_COUNT
//means that the DMA buffer will have 4 results for each ADC

因此,缓冲区的大小为 8,类型为 uint32_t。我正在读取 2 个 ADC 通道。在缓冲区中,Channel A 有 4 个结果,Channel B 有 4 个结果(以循环方式)。该数组的简单转储如下:

INDEX    0      1      2       3     4      5      6    7
CHNL     A      B      A       B     A      B      A    B
VALUE   4017    62    4032    67    4035    64    4029  63  

这意味着 DMA 将 ChAChB 的结果始终放在固定位置。

现在要计算每个通道的平均值,我有以下函数:

uint32_t filter_pots(uint8_t which) {

  uint32_t sum = 0;
  uint8_t i = which;

  for( ; i < FP_ANALOGS_BUFFER_SIZE; i += FP_ANALOGS_COUNT) {
    sum += adc_vals[i];
  }

  return sum / (uint32_t)FP_FILTER_ELEMENT_COUNT;
}

如果我想使用 chA 的函数,我会将 0 作为参数传递给函数。如果我想要 chB 我就通过 1... 如果我碰巧有 chC 我就通过 2 等等。这样我就可以启动 for 循环以指向我需要的元素。

问题是,在最后一步,当我想要 return 结果时,我没有得到正确的值。函数 returns 1007 用于 chA16 用于 chB。我很确定 sum 计算正常(我可以在调试器中看到它)。我认为问题出在除以使用#define 定义的值。即使将其转换为 uint32_t 也无济于事。 sum 计算正常,但我看不到编译器已将 FP_FILTER_ELEMENT_COUNT 分配给什么类型或值。可能是uint32除以uint8的溢出问题?

#define FP_FILTER_ELEMENT_COUNT  FP_ANALOGS_BUFFER_SIZE / FP_ANALOGS_COUNT
//means FP_FILTER_ELEMENT_COUNT  will be 8 / 2 which results in 4

是什么导致了这种行为,如果 #define 无法在我的情况下工作,我还有哪些其他选择?

编译器是 IAR Embedded Workbench。平台为STM32F103

为了减少意外,请始终在宏定义两边加上括号

#define FP_FILTER_ELEMENT_COUNT (FP_ANALOGS_BUFFER_SIZE / FP_ANALOGS_COUNT)

这可以防止出现奇怪的运算符优先级问题和其他意外的语法和逻辑错误。在这种情况下,当您想要 return sum/4.

时,您正在 returning sum/8/2(即 sum/16

正如@Russ 所说,括号会有所帮助,但更好的解决方案是使用常量:

static const int FP_ID_POT_0 = 0;  //identifier for POT_0
static const int FP_ID_POT_1 = 1;  //identifier for POT_1
static const int FP_ANALOGS_BUFFER_SIZE = 8; //buffer size for filtering ADC vals
static const int FP_ANALOGS_COUNT = 2;  // we have now 2 analog axis
static const int FP_FILTER_ELEMENT_COUNT = FP_ANALOGS_BUFFER_SIZE / FP_ANALOGS_COUNT;

在C++中,所有这些都是编译时整型常量表达式,可以用作数组边界、case标签、模板参数等。但与宏不同的是,它们尊重命名空间,类型安全,行为像真实值,而不是文本替换。