АЦП. Разбор полётов

Обсуждаем контроллеры компании Atmel.
Аватара пользователя
КРАМ
Друг Кота
Сообщения: 25121
Зарегистрирован: Чт янв 10, 2008 22:01:02
Откуда: Московская область, Фрязино

Re: АЦП. Разбор полётов

Сообщение КРАМ »

глобальные переменныe - объявляем до main()
char i
int Buffer[8]
Начальная инициализация указателя на массив в начале main():
i=0
В обработчике прерываний от АЦП:
int ADCres
ADCres = младший регистр АЦП + старший регистр АЦП*256
Buffer[(i++)&0x07] = ADCres
Среднее массива можно вычислять либо тут же, либо в main() - это зависит от временных ограничений программы.
Только не вздумайте применять i для вычисления среднего, объявите для этого ЛОКАЛЬНУЮ переменную той же размерности char.

Комментарии.
Сначала объявляем массив как глобальный int, а указатель на него как глобальный char
Потом указатель инициализируем начальным значением и запускаем цепочку таймер-АЦП. Тут я немного не в курсе какой таймер может запускать АЦП по своему переполнению в AVR. Но это несущественно - можно взглянуть в даташите или кто подскажет на лету.
В прерывании по АЦП сначала формируем 16-разрядное значение из двух отдельных байт результата преобразования.
Затем вписываем этот результат в массив по текущему значению указателя (адреса массива). После этого инкрементируем указатель и накладываем на него маску 0х07, тем самым ограничивая размер указателя от 0 до 7.
В приведенном примере использован массив из 8 элементов.
Все! Массив готов для вычисления среднего.
Таким образом мы записываем значения преобразования в массив по КРУГУ. В массиве всегда имеется последние 8 измерений. Правда они неупорядочены, поскольку граница начала новых данных все время скользит по кругу, но для прямоугольного окна это и не требуется, поскольку мы просто суммируем все значения для нахождения среднего.


ЗЫ. Решил не рисовать. Проще будет метапрограмма
Аватара пользователя
просто КОТ
Друг Кота
Сообщения: 12364
Зарегистрирован: Пт дек 17, 2010 15:07:50
Откуда: Крымский Федеральный Округ
Контактная информация:

Re: АЦП. Разбор полётов

Сообщение просто КОТ »

Так, получается, что в буфере сумма из 8 измерений. Тогда мне надо или мои требования умножить на 8, или буфер делить. Пожалуй заранее умножу пункты на 8. . .


Кстати, а можно запустит АЦП не таймером?! А просто прописав в основной программе. От него прерывания, а потом продолжается основная программа, в которой идёт обработка прерываний!


Типа так:
Спойлер

Код: Выделить всё

#define F_CPU 4800000 // Инициализация
#include <io.h>
#include <delay.h>

char i
int Buffer[8]
int sum = 0;

interrupt[10] void ADCInt1(void) // Прерывания от АЦП

int ADCres
ADCres = ADCH*256 + ADCL;
sum = sum - Buffer[i] + ADCres;
Buffer[(i++)&0x07] = ADCres

void main (void)
{
i=0
DDRB=0b011011;
PORTB=0b10010;
ADMUX=00000001;
#asm("sei");
{
ADCSRA=11000000; //Запускаем Аналого-Цифровой преобразователь
if (ADCres>5600)   // Если насчитал больше 700, зажечь Синий светик
{
PORTB=000001;
delay_ms(5000);
PORTB=000000;
}
else if (ADCres>5200)   // Если более 650, то Зелёный
{
PORTB=000010;
delay_ms(2000);
PORTB=000000;
}
else if (ADCres>4800)  // Если хоть более 600, то Жёлтый
{
PORTB=010000;
delay_ms(2000);
PORTB=000000;
}
else if (ADCres<4400)  // А если менее 550, то Красный!
{
PORTB=001000;
delay_ms(2000);
PORTB=000000;
}
}
}
Последний раз редактировалось просто КОТ Чт авг 16, 2012 19:52:11, всего редактировалось 4 раза.
Изображение
И ты врёшь!!! © Vladisman
Изображение
Аватара пользователя
Ser60
Друг Кота
Сообщения: 3780
Зарегистрирован: Ср дек 24, 2008 09:58:58

Re: АЦП. Разбор полётов

Сообщение Ser60 »

Поддерживаю способ усреднения показаний АЦП с помощью скользящего среднего, как писал Kramer. Сам такими часто пользуюсь, эффект от них колосальный. В плане реализации, для подсчета суммы элементов в буфере при занесении в него нового числа можно добавить к старой сумме это новое число (текущее значение АЦП) и вычесть из результата самое старое число в буфере. Это самое статое число имеет индекс i до занесения в буфер нового числа.

Конкретно, в мета-программе Krama-а вместо операци
Buffer[(i++)&0x07] = ADCres
можно сделать так:
sum = sum - Buffer[i] + ADCres;
Buffer[(++i)&0x007] = ADCres;

Переменную sum можно об'явить как глобальную там-же где об'явлен сам буфер и инициализировать нулем:
int sum = 0;
Аватара пользователя
просто КОТ
Друг Кота
Сообщения: 12364
Зарегистрирован: Пт дек 17, 2010 15:07:50
Откуда: Крымский Федеральный Округ
Контактная информация:

Re: АЦП. Разбор полётов

Сообщение просто КОТ »

А как мой код?!
Работать будет?!
Изображение
И ты врёшь!!! © Vladisman
Изображение
Аватара пользователя
siamds
Встал на лапы
Сообщения: 99
Зарегистрирован: Вт мар 20, 2012 20:50:22
Откуда: Краснодар

Re: АЦП. Разбор полётов

Сообщение siamds »

КРАМ писал(а):Конденсатор на входе сам по себе никаким внятным фильтром не будет.
Опять же ЗАЧЕМ городить даже единственный конденсатор, когда программная реализация ВООБЩЕ НЕ ТРЕБУЕТ никаких схемотехнических затрат?
Уважаемый КРАМ! Честно говоря, ваше утверждение вызывает у меня большие сомнения. И чтобы не считать Ваше утверждение голословным выложите на форум hex. файл чтобы желающие могли протестировать Вашу программу. Когда я выложил на форум программу “Чтение АЦП”, у нашего коллеги Совесть закрались сомнения в ее работоспособности (и это его законное право) и я убедил его выложив результат работы программы. Так и мне хотелось бы, чтобы Вы убедили меня и наших коллег в правомерности Ваших утверждений реальным примером.
На каждого Моцарта есть свой Сальери.
Аватара пользователя
КРАМ
Друг Кота
Сообщения: 25121
Зарегистрирован: Чт янв 10, 2008 22:01:02
Откуда: Московская область, Фрязино

Re: АЦП. Разбор полётов

Сообщение КРАМ »

просто КОТ писал(а):Так, получается, что в буфере сумма из 8 измерений. Тогда мне надо или мои требования умножить на 8, или буфер делить.

В буфере не сумма, а 8 элементов массива. После суммирования результат нужно поделить на 8 путем сдвига вправо на 3. Причем по хорошему перед последним сдвигом нужно проверить младший разряд промежуточного результата и если он =1, то после 3-его сдвига нужно к результату прибавить 1. Это будет корректным округлением.
Аватара пользователя
просто КОТ
Друг Кота
Сообщения: 12364
Зарегистрирован: Пт дек 17, 2010 15:07:50
Откуда: Крымский Федеральный Округ
Контактная информация:

Re: АЦП. Разбор полётов

Сообщение просто КОТ »

Извиняюсь -- не так сказал. Не буфер, а регистр ADCres!
Изображение
И ты врёшь!!! © Vladisman
Изображение
Аватара пользователя
КРАМ
Друг Кота
Сообщения: 25121
Зарегистрирован: Чт янв 10, 2008 22:01:02
Откуда: Московская область, Фрязино

Re: АЦП. Разбор полётов

Сообщение КРАМ »

siamds писал(а):Уважаемый КРАМ! Честно говоря, ваше утверждение вызывает у меня большие сомнения. И чтобы не считать Ваше утверждение голословным выложите на форум hex. файл чтобы желающие могли протестировать Вашу программу. Когда я выложил на форум программу “Чтение АЦП”, у нашего коллеги Совесть закрались сомнения в ее работоспособности (и это его законное право) и я убедил его выложив результат работы программы. Так и мне хотелось бы, чтобы Вы убедили меня и наших коллег в правомерности Ваших утверждений реальным примером.

:))) :))) :)))
Я даже не знаю как это комментировать...
Для того, чтобы что либо проверить, нужно собрать устройство целиком...
Опять же требуется некая программа для сравнения...
И зачем Вам HEX? :shock: Для сравнения нужен ИСХОДНЫЙ код либо на Си, либо на АСМе. Причем все это пишут под КОНКРЕТНЫЙ контроллер...
:wink:
Вообще то ваши сомнения легко разрешимы гораздо более продуктивным путем.
Путем изучения теории цифровой фильтрации.
ЗЫ. Кстати, я как то давно на Паяльнике статейку накропал про термометр на 18В20 и, если мне не изменяет память, там я скользящее среднее как раз и считаю, чтобы показания были "резиновыми" и не дрожали. А тут давал ссылку.
Но проще Вам самим сходить на Паяльник и посмотреть и сам проект и исходный код к нему.
А вообще то вопросы фильтрации - это моя профессия. :)
Последний раз редактировалось КРАМ Чт авг 16, 2012 19:41:21, всего редактировалось 1 раз.
Аватара пользователя
просто КОТ
Друг Кота
Сообщения: 12364
Зарегистрирован: Пт дек 17, 2010 15:07:50
Откуда: Крымский Федеральный Округ
Контактная информация:

Re: АЦП. Разбор полётов

Сообщение просто КОТ »

Ну так скажите мне -- правильно я "буфер" вписал в код?!
Изображение
И ты врёшь!!! © Vladisman
Изображение
Аватара пользователя
КРАМ
Друг Кота
Сообщения: 25121
Зарегистрирован: Чт янв 10, 2008 22:01:02
Откуда: Московская область, Фрязино

Re: АЦП. Разбор полётов

Сообщение КРАМ »

В буфер правильно, а результат суммирования далее почему то проигнорировали и вместо сдвига и округления суммы (саму сумму при этом трогать нельзя, поскольку она у Вас текущая) зачем то используете последний результат преобразования...
:(
Ну и нет кода для запуска таймера-АЦП.
Как будет вообще стартовать преобразование?
Аватара пользователя
просто КОТ
Друг Кота
Сообщения: 12364
Зарегистрирован: Пт дек 17, 2010 15:07:50
Откуда: Крымский Федеральный Округ
Контактная информация:

Re: АЦП. Разбор полётов

Сообщение просто КОТ »

Код: Выделить всё

ADCSRA=11000000; //Запускаем Аналогово-Цифровой преобразователь

Вот то должно АЦП запускать. Я попытался его без таймера сделать. Судя по всему не правильно. . .
Изображение
И ты врёшь!!! © Vladisman
Изображение
Аватара пользователя
КРАМ
Друг Кота
Сообщения: 25121
Зарегистрирован: Чт янв 10, 2008 22:01:02
Откуда: Московская область, Фрязино

Re: АЦП. Разбор полётов

Сообщение КРАМ »

Так тоже можно, только в main() должен быть БЕСКОНЕЧНЫЙ ЦИКЛ, где в КАЖДОМ цикле будет происходить запуск АЦП и обработка результата с выводом на светодиоды. Тогда и накопление будет в прерывании и программа будет работать непрерывно. А так она у Вас уходит в никуда...
Нет так называемого суперлупа - т.е. главного цикла.
Аватара пользователя
Аlex
Модератор
Сообщения: 4614
Зарегистрирован: Чт мар 18, 2010 23:09:57
Откуда: Планета Земля
Контактная информация:

Re: АЦП. Разбор полётов

Сообщение Аlex »

просто КОТ, как то примерно так:

Код: Выделить всё


volatile unsigned int ADC_Buf[8];
volatile unsigned int ADC_result;

/*****************************************************/
ОП_Прерывания_От_ADC(){
static unsigned char cnt_buf=0;

ADC_Buf[cnt_buf] = (unsigned int)ADCH<<8 | ADCL;
if(++cnt_buf>=8) cnt_buf=0;

перезапускаем_преобразование();
}
/*****************************************************/

/*****************************************************/
void main(void){
long adc_summ;
unsigned char i;

for(i=0;i<8;i++) ADC_Buf[i]=0;
..................
..................

adc_summ=0;
for(i=0;i<8;i++) adc_summ+=ADC_Buf[i];
adc_summ >>=8;
ADC_result = (unsigned int)adc_summ;

.....................
.....................

}
/*****************************************************/
Аватара пользователя
Ser60
Друг Кота
Сообщения: 3780
Зарегистрирован: Ср дек 24, 2008 09:58:58

Re: АЦП. Разбор полётов

Сообщение Ser60 »

Опять полностью согласен с Kramerom по поводу округления. :beer:
ПростоКОТ - у Вас отсутствуют скобки {} вокруг тела прерывания.
А сравнивать с пунктами надо не ADCres а sum.
Аватара пользователя
КРАМ
Друг Кота
Сообщения: 25121
Зарегистрирован: Чт янв 10, 2008 22:01:02
Откуда: Московская область, Фрязино

Re: АЦП. Разбор полётов

Сообщение КРАМ »

Ну вооот, пришел Алекс и все на Си грамотно написал, а то я все больше на АСМе... :)
Только я не понял про 8 сдвигов после суммирования...
Аватара пользователя
просто КОТ
Друг Кота
Сообщения: 12364
Зарегистрирован: Пт дек 17, 2010 15:07:50
Откуда: Крымский Федеральный Округ
Контактная информация:

Re: АЦП. Разбор полётов

Сообщение просто КОТ »

А я тем более не понял!
Изображение
И ты врёшь!!! © Vladisman
Изображение
Аватара пользователя
Аlex
Модератор
Сообщения: 4614
Зарегистрирован: Чт мар 18, 2010 23:09:57
Откуда: Планета Земля
Контактная информация:

Re: АЦП. Разбор полётов

Сообщение Аlex »

КРАМ писал(а):Только я не понял про 8 сдвигов после суммирования...
Тьфу, блин, лохонулся... :)))

Код: Выделить всё

adc_summ >>=3;
за место

Код: Выделить всё

adc_summ >>=8;
:)
Аватара пользователя
Аlex
Модератор
Сообщения: 4614
Зарегистрирован: Чт мар 18, 2010 23:09:57
Откуда: Планета Земля
Контактная информация:

Re: АЦП. Разбор полётов

Сообщение Аlex »

За место cnt_buf можно держать указатель (unsigned int*) и, инкрементируя его, сравнивать с адресом последней ячейки массива и сбрасывать на адрес нулевой ячейки. И работать напрямую через указатель. Будет, скорее всего, оптимальнее.
И ещё, во время обработки массива в майне, необходимо запретить прерывания (можно только для ADC) для атомарного доступа к массиву.
Аватара пользователя
КРАМ
Друг Кота
Сообщения: 25121
Зарегистрирован: Чт янв 10, 2008 22:01:02
Откуда: Московская область, Фрязино

Re: АЦП. Разбор полётов

Сообщение КРАМ »

Алекс, ты его так совсем запутаешь... :)
Ему бы с обычным индексом управиться... :)
Аватара пользователя
Аlex
Модератор
Сообщения: 4614
Зарегистрирован: Чт мар 18, 2010 23:09:57
Откуда: Планета Земля
Контактная информация:

Re: АЦП. Разбор полётов

Сообщение Аlex »

Ну я и привёл простенький пример для простоты понимания :)
Ответить

Вернуться в «AVR»