Да знаю я, знаю, что долго сидеть в прерывании нехорошо, не ругайтесь так...
Но тут какая проблема была - если вычисления делать просто в цикле for(;;), то за время, пока эти вычисления делаются, уже успевает прийти несколько прерываний, и данные обновляются прямо по ходу вычислений.
Есть два способа решения этой проблемы. Либо на время вычислений в основном цикле запрещать прерывания от АЦП (либо останавливать его) - все равно АЦП не работает, когда вы считаете в прерывании. Либо использовать два циклических буфера. В то время пока вы обсчитываете результаты одного буфера, в другой буфер (по прерываниям АЦП) идет запись новых результатов изменений. В основном цикле вы только устанавливаете номер буфера и флаг сигнализирующий обработчику прерывания АЦП о смене номера буфера. В прерывании АЦП сначала анализируется состояние флага и при необходимости изменяется указатель на буфер, а запись новых значений происходит уже в другой буфер.
И происходит такая вещь - если плавно поворачивать плату, то оцифрованый уровень меняется далеко не плавно, жутко скачет во время поворота и долго "успокаивается", если вращать быстро, то будет долгий переходной процесс - т.е. улетает сначала намного выше реального уровня, затем медленно возвращается. Вот, по-женски так объясняю, самой смешно
я думаю, это происходит оттого, что допустим координата Х уже просчиталась, а У еще нет, пришло прерывание, данные обновились, У считается, и уже характеризует новое положение, а Х - еще старое, поэтому при вращении возникают большие ошибки.
Значит у вас где-то ошибка в алгоритме. нужно синхронизировать обновления значений переменных координат так, чтобы не было разбега, как он у вас описан.
Кстати, на ваш вопрос - да, усредняю скользящим, среднее арифметическое - это глупо даже для меня
Каждый раз дожидаться, пока наберется 30 отсчетов... Я жду, пока они наберутся только в самом начале работы, а потом каждое новое число записывается 30-м элементом массива, и массив усредняется и сдвигается.
Ну да, зато теперь тратится куча времени...
А вам приниципально усреднять уже готовые значения координат или можно усреднять непосредственно отсчеты АЦП? Ведь просуммировать целые числа получается гораздо быстрее, чем получить сумму "плавучих" чисел? К тому же при целочисленных вычислениях не накапливается ошибка округления. Поэтому алгоритм скользящего вычисления среднего можно значительно ускорить. Для этого нужно лишь хранить отдельно текущее значение суммы элементов буфера. При поступлении нового значения в буфер достаточно вычесть из этой суммы значение самого древнего элемента буфера, прибавить значение нового элемента буфера и вуаля! - вы получаете готовую сумму. Итого одно сложение и одно вычитание, вместо суммирования всего буфера. Для "плавучки" такой способ не годиться, т.к. довольно быстро набегает ошибка вычисления суммы. К тому же зачем вы каждый раз при записи нового значения в буфер сдвигаете все элементы в буфере? Это же лишнее время и совершенно ненужное действие. Сдвигайте не сам буфер, а лишь индекс-указатель на текущий элемент буфера. Получается то же самый неоднократно упомянутый циклический буфер.
Ну да, зато теперь тратится куча времени...

Код
#define MAXNUMFLTRBUF 30
unsigned int funcSMA(unsigned int val)
{ static unsigned int fltrBuf[MAXNUMFLTRBUF];
static unsigned int idx;
static unsigned long sumBuf;
sumBuf-=fltrBuf[idx]; //вычитаем из суммы значение самого старого элемента
sumBuf+=val; //прибавляем к сумме значение нового элемента
fltrBuf[idx]=val; //записываем в буфер значение нового элемента
if (idx<(MAXNUMFLTRBUF-1))//сдвигаем индекс
idx++;
else
idx=0;
return(sumBuf/MAXNUMFLTRBUF);//высисляем среднее значение
}
unsigned int funcSMA(unsigned int val)
{ static unsigned int fltrBuf[MAXNUMFLTRBUF];
static unsigned int idx;
static unsigned long sumBuf;
sumBuf-=fltrBuf[idx]; //вычитаем из суммы значение самого старого элемента
sumBuf+=val; //прибавляем к сумме значение нового элемента
fltrBuf[idx]=val; //записываем в буфер значение нового элемента
if (idx<(MAXNUMFLTRBUF-1))//сдвигаем индекс
idx++;
else
idx=0;
return(sumBuf/MAXNUMFLTRBUF);//высисляем среднее значение
}
При желании можно добавить команды управления фильтром. Например, команду очистки буфера или инициализация его определенным значением. Для того, чтобы увеличить начальную крутизну его переходной характеристики.
Код
#define MAXNUMFLTRBUF 30
unsigned int funcSMA(unsigned int cmd, unsigned int val)
{ static unsigned int fltrBuf[MAXNUMFLTRBUF];
static unsigned int idx;
static unsigned long sumBuf;
if (cmd==0) //это случано не команда инициализации фильтра?
{ sumBuf-=fltrBuf[idx]; //нет, вычитаем старое значение
sumBuf+=val; //прибавляем к сумме значение нового элемента
fltrBuf[idx]=val; //записываем в буфер значение нового элемента
if (idx<(MAXNUMFLTRBUF-1))//сдвигаем индекс
idx++;
else
idx=0;
return(sumBuf/MAXNUMFLTRBUF);//вычисляем среднее значение
}
else //да, инициализируем буфер фильтра новым значением
{ sumBuf=val*MAXNUMFLTRBUF;
idx=MAXNUMFLTRBUF-1;
while (idx!=0)
fltrBuf[idx--]=val;
return(val);
}
}
unsigned int funcSMA(unsigned int cmd, unsigned int val)
{ static unsigned int fltrBuf[MAXNUMFLTRBUF];
static unsigned int idx;
static unsigned long sumBuf;
if (cmd==0) //это случано не команда инициализации фильтра?
{ sumBuf-=fltrBuf[idx]; //нет, вычитаем старое значение
sumBuf+=val; //прибавляем к сумме значение нового элемента
fltrBuf[idx]=val; //записываем в буфер значение нового элемента
if (idx<(MAXNUMFLTRBUF-1))//сдвигаем индекс
idx++;
else
idx=0;
return(sumBuf/MAXNUMFLTRBUF);//вычисляем среднее значение
}
else //да, инициализируем буфер фильтра новым значением
{ sumBuf=val*MAXNUMFLTRBUF;
idx=MAXNUMFLTRBUF-1;
while (idx!=0)
fltrBuf[idx--]=val;
return(val);
}
}
Учитывая, что входные значения 12-и разрядные и сумма заведомо не превышает разрядности типа long, то при целочисленном вычислении среднего можно повысить точность, если перед делением сдвигать сумму до заполнения разрядности типа, а потом сдвигать обратно.
Код
return(((sumBuf<<8UL)/MAXNUMFLTRBUF)>>8UL);