Page 1 of 2

Алгоритм обработки АЦП ДАД

Posted: Wed Dec 14, 2011 8:34 pm
by nikll
Делаем 120 выборок из ацп за оборот кв (в прерываниях ДПКВ), результат каждой выборки складываем в таблицу (кольцевой буфер).
Полученный усредненный результат будет на ~6% меньше фактического т.к. мы делим на 128 вместо 120
На вскидку код получается вот такой:

map.h

Code: Select all

typedef struct {
	uint16_t buffer[120];
	uint16_t *cursor;
}map_t;

map_t map;
#define MAP_START	&map.buffer[0]
#define MAP_END		&map.buffer[119]
for (map.cursor = MAP_START; map.cursor <= MAP_END; map.cursor++) *map.cursor = 0xFFF;	// забиваем в таблицу по дефолту атмосферное давление

map.c

Code: Select all

#include <map.h>

void add_map(uint16_t adc) {
	if (map.cursor == MAP_END)
		map.cursor = MAP_START;
	else	map.cursor++;

	*map.cursor = adc;
}

// Целочислительный алгоритм усреднения без деления:
// в цилке, начиная от текущщей ячейки буфера, выбираем и складываем их вместе, делаем сдвиг >> 16 для деления и отброса дробной части, примерный код:
uint16_t get_avg_map() {
	uint16_t *tmp_cursor;
	uint32_t result;

	// начинаем от текущщей ячейки включительно и до конца таблицы
	for (tmp_cursor = map.cursor; tmp_cursor <= MAP_END; tmp_cursor++) result += *tmp_cursor;

	// продолжаем от начала таблицы и до текущщей ячейки
	for (tmp_cursor = MAP_START; tmp_cursor < map_buffer_cursor; tmp_cursor++) result += *tmp_cursor;

	return ((uint16_t)(result >> 7)); // делим на 128 и приводим тип
}

Re: Алгоритм обработки АЦП ДАД

Posted: Wed Dec 14, 2011 9:53 pm
by STC
Используй нормальное деление (дели на 120). Процессор ARM Cortex M3 выполняет 32-х битное деление за 1 такт. Можно делить как угодно и на что угодно.

Re: Алгоритм обработки АЦП ДАД

Posted: Wed Dec 14, 2011 10:43 pm
by nikll
хм, немогу найти подтверждение этой информации, нашел только что умножение 32х32 за один такт, деление 2-7 тактов...

Re: Алгоритм обработки АЦП ДАД

Posted: Wed Dec 14, 2011 11:37 pm
by STC
На титульной странице даташита написано что "hardware division", дальше я не смотрел. Даже если 2-7 тактов, то заморачиваться не стоит.
Кроме этого, если нужно разделить на константу, то деление можно заменить умножением на так тазываемое обратное число. Данная техника будет применимой в случае, если система команд процессора позволяет умножить два 32-х разрядных числа и получить 64-х разрядное. ARM вроде умеет такое. Подробнее про "магические" числа можно почитать в книге Генри Уоррена "Алгоритмические трюки для программистов", изд. Вильямс. Это русский перевод. На английском название данной книжки звучит круче - "Hacker's Delight". Можно посетить сайт http://www.hackersdelight.org/
http://www.hackersdelight.org/magic.htm

Так выглядит: http://www.rsdn.ru/res/book/prog/worren.xml

Re: Алгоритм обработки АЦП ДАД

Posted: Thu Dec 15, 2011 12:27 am
by nikll
просто вся суть в том что отклонение линейное и не зависит от частоты и амплитуды, достаточно полученное значение умножить на (128/120) и мы получим истенное усредненное значение АЦП, вот только зачем нам оно? всеравно значение АЦП надо приводить к давлению через смещщение и наклон характеристики ДАД, прощще в прошивку заносить параметры дад разделенные на (128/120) чем в каждом цикле терять семь тактов... Я понимаю что stm32 кажется сверхмощным безграничным МК :) но как показывает практика минимальная оптимизация без ухудшения параметров системы никога не бывает избыточной, зато ресурсов железа никогда не бывает много бывает только иногда достаточно :)))

Re: Алгоритм обработки АЦП ДАД

Posted: Thu Dec 15, 2011 12:48 am
by STC
Игра не стоит свеч. Применим, скажем другой шкив и нужно будет усреднять, скажем 60 раз за оборот и константа 128/120 все равно не подойдет.
Не усложняй жизнь такими вещами. Усреднение ДАД будет происходить в основном цикле (в прерываниях такие вещи лучше не делать), а для него лишние 7 тактов погоды не сделают.

Тем более вспомни как говорят: "Излишняя оптимизация на раннем этапе не есть хорошо".

Re: Алгоритм обработки АЦП ДАД

Posted: Thu Dec 15, 2011 1:08 am
by nikll
Надо именно в прерывании запускать АЦП, ждать результат не надо, можно через прерывание АЦП данные в таблицу сохранять, думаю еще DMA покурить, есть подозрения что можно пошагово отрабатывать данные из АЦП в таблицу по средствам DMA.
В основном цикле дергать АЦП синхронно с положением коленвала? Как??? через условные флаг который взводить в прерывании и обрабатывать основном цикле? получится неконролируемый разброс по времени, и тем он больше будет чем реже этот флаг будет проверятся в основном цикле, вплоть до пропусков при больших обротах.

Можно конечно скрестить АЦП с DMA через таймер и рулить таймером согласно времени ДПКВ но там еще сложней все получается да и по ресурсам затратней.
Вот именно что излишняя :), тут ее нету, вот если развернуть циклы убрать функции и впихать все стопкой кода прямо в обработчик прерывания вот тогда да получится пресловутое "преждевременная оптимизация".

60-2 является стандартом, практически де-факто, для изменения диска ДПКВ достаточно поменять две константы в прошивке (размер таблицы и делитель) и одну в менеждере (та самая 128/120)
К примеру требуется обрабатывать диск ДПКВ 12-2: соответсвенно получается за оброт кв 28 прерываний, оптимальным делителем будет 32 (сдвиг на 5), в менеджер соответсвенно впишем 32/28, все банально.

Re: Алгоритм обработки АЦП ДАД

Posted: Thu Dec 15, 2011 2:07 am
by STC
В прерывании только заполнять кольцевой буфер, а усреднять в основном цикле.

Re: Алгоритм обработки АЦП ДАД

Posted: Thu Dec 15, 2011 2:15 am
by nikll
Да естественно :).
Расчет наполнения будет происходить в основном цикле, перед расчетом наполнения брать темпиратуру воздуха и усреднять дад, ДТОЖ врятли стоит брать в каждом цикле, вполне достаточно в одном из таймеров к примеру раз в секунду или когда удобней.

Re: Алгоритм обработки АЦП ДАД

Posted: Thu Dec 15, 2011 5:09 am
by nikll
в общем разобрался, полная схема следующщая:
1. инициализируем АЦП (настройки, автокалибровка и прочая при запуске МК), вешаем прерывание по окончанию преобразования.
2. в прерывании ДПКВ запускаем преобразование АЦП
3. в прерывании АЦП вызываем add_map(uint16_t adc) для записи данных в таблицу.

Прерывания в stm32 работают с минимальными накладными расходами, однако АЦП при нормальном качестве распознования работает 239,5 циклов + 12,5 циклов это не мало, на частоте АЦП (12мгц) это 21мкс что при частоте ядра равняется ~1512 тактам. Накладные расходы на прерывание несколько тактов, поэтому такой подход актуален.