Я работаю над микроконтроллером и хочу внедрить простой усредненный фильтр по полученным значениям, чтобы отфильтровать шум (или, если честно, не дать значениям танцевать на ЖК-дисплее!).
Результат АЦП вставляется в память 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
Чтобы меньше сюрпризов, всегда ставьте круглые скобки вокруг определений макросов
#define FP_FILTER_ELEMENT_COUNT (FP_ANALOGS_BUFFER_SIZE / FP_ANALOGS_COUNT)
Это предотвращает возникновение проблем с приоритетом нечетных операторов и других непредвиденных синтаксических и логических ошибок. В этом случае вы возвращаетесь sum/8/2
(Т.е. sum/16
) когда хочешь вернуться sum/4
,
Как говорит @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, аргументов шаблона и т. Д. Но в отличие от макросов они уважают пространства имен, безопасны для типов и действуют как реальные значения, а не подстановка текста.