Определение целого числа в C преобразуется в unsigned char или приводит к непредвиденному поведению в случае математических операций

Я работаю над микроконтроллером и хочу внедрить простой усредненный фильтр по полученным значениям, чтобы отфильтровать шум (или, если честно, не дать значениям танцевать на ЖК-дисплее!).

Результат АЦП вставляется в память DMA. У меня есть (просто для простоты отладки) массив размером 8. Чтобы сделать жизнь еще проще, я написал несколько определяет сделать мой код редактируемым с минимальными усилиями:

#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 канала АЦП. в буфере у меня будет 4 результата для Канал А и 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 ставит результаты для ЧА а также ChB всегда в фиксированном месте.

Теперь для вычисления среднего значения для каждого канала у меня есть функция ниже:

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, чтобы указать на элемент, который мне нужен.

Проблема в том, что на последнем шаге, когда я хочу вернуть результат, я не получаю правильное значение. Функция возвращает 1007 когда используется для Cha а также 16 когда используется для БКИ. Я уверен, что 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

3

Решение

Чтобы меньше сюрпризов, всегда ставьте круглые скобки вокруг определений макросов

#define FP_FILTER_ELEMENT_COUNT (FP_ANALOGS_BUFFER_SIZE / FP_ANALOGS_COUNT)

Это предотвращает возникновение проблем с приоритетом нечетных операторов и других непредвиденных синтаксических и логических ошибок. В этом случае вы возвращаетесь sum/8/2 (Т.е. sum/16) когда хочешь вернуться sum/4,

9

Другие решения

Как говорит @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, аргументов шаблона и т. Д. Но в отличие от макросов они уважают пространства имен, безопасны для типов и действуют как реальные значения, а не подстановка текста.

5

По вопросам рекламы [email protected]