Обсуждаем контроллеры компании Atmel.
Ответить

Re: Несколько каналов АЦП Atmega 88

Чт авг 10, 2017 10:45:14

И мне можно прерывание выбросить.

можно, конечно, прерывание выбросить. Но оно для того и реализовано в контроллере, чтобы не чесать правой рукой левое ухо.
У вас было все изначально правильно, за исключением неправильного инкремента ADMUX. так что городить городушки с заменой прерывания ADC прерыванием таймера, это даже не чесать левое ухо правой рукой, это сродни удалению гланд через анальный проход. :)

Код:
ISR(ADC_vect)
{
   adc_result[ADMUX & 0b00001111] = ADCH;
   if ((ADMUX & 0b00001111) < 8)   ADMUX++;
   else   ADMUX = ADMUX & 0b11110000;
   ADCSRA |= ( 1 << ADSC );
}


сделайте вот так. Должно все заработать. Потом продумаем, как усреднить :)

Re: Несколько каналов АЦП Atmega 88

Чт авг 10, 2017 10:47:38

Я одно не пойму. Как щелкать каналами и работать с прерыванием по окончанию измерения канала ясно. А вот как это делать через определенные интервалы времени...

Re: Несколько каналов АЦП Atmega 88

Чт авг 10, 2017 10:52:46

Я одно не пойму. Как щелкать каналами и работать с прерыванием по окончанию измерения канала ясно. А вот как это делать через определенные интервалы времени...

а вот я не пойму, зачем это делать? В контроллере есть специальное прерывание, которое вызывается по окончанию преобразования. зачем же лепить горбатого к стенке? :)

Re: Несколько каналов АЦП Atmega 88

Чт авг 10, 2017 10:53:55

Нужен опрос каждого канала по 200 микросекунд.

Re: Несколько каналов АЦП Atmega 88

Чт авг 10, 2017 11:08:54

Нужен опрос каждого канала по 200 микросекунд.

тогда сделайте прерывание по таймеру и перенесите строку:

Код:
ADCSRA |= ( 1 << ADSC );


из прерывания по окончанию преобразования в прерывание по таймеру. Но тут есть нюансы. Если преобразование длится более, чем 200 мкс, то, разумеется, у вас будут проблемы. Посему, сначала разрешаете только одно прерывание по окончанию преобразования, добавляете туда две строчки и осциллографом замеряете, сколько длится преобразование.

Код:
ISR(ADC_vect)
{
   PORTB &= ~(1 << PORTB1);
   adc_result[ADMUX & 0b00001111] = ADCH;
   if ((ADMUX & 0b00001111) < 8)   ADMUX++;
   else   ADMUX = ADMUX & 0b11110000;
   ADCSRA |= ( 1 << ADSC );
       PORTB |= (1 << PORTB1);
}


PORTB1 я выбрал произвольно. Вы можете использовать любой свободный.

Ну, или расчитайте теоретически с учетом выбранной частоты преобразования.

Re: Несколько каналов АЦП Atmega 88

Чт авг 10, 2017 11:17:55

Чет так в протеусе не работает
Код:
ISR( TIMER0_OVF_vect )
{
   // 100 us oveflow
   // Reinitialize Timer 0 value
   TCNT0=0x9C;
   ADCSRA|=(1<<ADSC); //ADCSRA|=0x40
}


ISR (ADC_vect)
{
   //static byte input_index=0;
   // Read the AD conversion result
   adc_data[input_index]=ADCW;
   // Select next ADC input
   if (++input_index > (LAST_ADC_INPUT-FIRST_ADC_INPUT))
   input_index=0;
   ADMUX=(FIRST_ADC_INPUT % 3)| (ADC_VREF_TYPE+input_index);
   // Delay needed for the stabilization of the ADC input voltage
   _delay_us(10);
   //ADCSRA|=(1<<ADSC);
}

Re: Несколько каналов АЦП Atmega 88

Чт авг 10, 2017 11:22:36

Чет так в протеусе не работает
Код:
ISR( TIMER0_OVF_vect )
{
   // 100 us oveflow
   // Reinitialize Timer 0 value
   TCNT0=0x9C;
   ADCSRA|=(1<<ADSC); //ADCSRA|=0x40
}


ISR (ADC_vect)
{
   //static byte input_index=0;
   // Read the AD conversion result
   adc_data[input_index]=ADCW;
   // Select next ADC input
   if (++input_index > (LAST_ADC_INPUT-FIRST_ADC_INPUT))
   input_index=0;
   ADMUX=(FIRST_ADC_INPUT % 3)| (ADC_VREF_TYPE+input_index);
   // Delay needed for the stabilization of the ADC input voltage
   _delay_us(10);
   //ADCSRA|=(1<<ADSC);
}


ADCW, это что за зверь?
а вообще, код какой-то непонятный. Я даже и не понял, что он делает :)

Re: Несколько каналов АЦП Atmega 88

Чт авг 10, 2017 11:32:49

Судя по ДШ в ADCW пишутся оба регистра ADCL и ADCH. А код CV AVR генерирует

Re: Несколько каналов АЦП Atmega 88

Чт авг 10, 2017 11:40:23

Судя по ДШ в ADCW пишутся оба регистра ADCL и ADCH. А код CV AVR генерирует

судя по даташиту регистр называется ADC. Но в CV чего только не может быть :)

А код CV AVR генерирует

тогда понятно. Этот уж нагенерирует за пять минут столько, что тысячу мудрецов за год не смогут разобрать :)

Re: Несколько каналов АЦП Atmega 88

Чт авг 10, 2017 12:31:23

тогда сделайте прерывание по таймеру и перенесите строку:

Чего не взлетает. Переношу разрешение на преобразование а прерывание по таймеру, но не работает...

Добавлено after 12 minutes 51 second:
Вот так правильно будет?
Код:
ISR( TIMER0_OVF_vect )
{
   
   // Reinitialize Timer 0 value
   TCNT0=0xBE;
   ADCSRA &= ~(1<<ADSC); //ADCSRA|=0x40
}

Re: Несколько каналов АЦП Atmega 88

Чт авг 10, 2017 12:45:53

тогда сделайте прерывание по таймеру и перенесите строку:

Чего не взлетает. Переношу разрешение на преобразование а прерывание по таймеру, но не работает...

Добавлено after 12 minutes 51 second:
Вот так правильно будет?
Код:
ISR( TIMER0_OVF_vect )
{
   
   // Reinitialize Timer 0 value
   TCNT0=0xBE;
   ADCSRA &= ~(1<<ADSC); //ADCSRA|=0x40
}


нет, неправильно. Правильно было первый раз. Вы разрешили прерывание таймера по переполнению?

Re: Несколько каналов АЦП Atmega 88

Чт авг 10, 2017 12:48:40

Ой блин... Забыл. Все - теперь работает!!! Спасибо!
Код:
TIMSK0=(0<<OCIE0B) | (0<<OCIE0A) | (1<<TOIE0);

Re: Несколько каналов АЦП Atmega 88

Чт авг 10, 2017 13:04:47

не за что :)

Re: Несколько каналов АЦП Atmega 88

Чт авг 10, 2017 13:21:00

Ivanoff-iv писал(а):некоторое снижение случайной ошибки, вот например возьмём 10бит шим (младший разряд шумящий) сложим 2 замера и получим 11бит сигнал, младший шумящий - отсекаем его (/2) и получаем обратно 10бит сигнал, но уже стабильней.

об этом и говорю...)) три выборки АЦП - просто стабильней... но это не убирает шум полностью. Нужно или делать МНОГО выборок (оцифровать входной сигнал), или использовать другой алгоритм, например я часто исмпользую гистерезис, который полностью убирает шум АЦП...

чёто вы замудрили.. куча прерываний... Можно просто делать выборки АЦП через 200 мкс в цикле... Например типа так:

mesto_1: // начало
ADMUX=0b01100001; // где 1 - номер канала..
ADCSRA|=0b01000000; // где 1 - старт преобразования...
delay_us(200); // ждём 200 мкс...
a=ADCW; // записали данные из АЦП в переменную "a" (тип int).
goto mesto_1; // конец. Перейти вначало.

... и т.д. Короче крутимся в цикле без прерываний)) :)))
Последний раз редактировалось roman.com Чт авг 10, 2017 13:22:39, всего редактировалось 1 раз.

Re: Несколько каналов АЦП Atmega 88

Чт авг 10, 2017 13:22:05

... и т.д. Короче крутимся в цикле без прерываний))

Так не интересно. Такой вариант заработал сразу же. Тем более его генерирует Code Vision =)

Re: Несколько каналов АЦП Atmega 88

Чт авг 10, 2017 13:35:10

)) не интересно им... Это хорошо если МК кроме оцифровки входного сигнала ничего бельше не делает... А если МК выполняет сложные операции с высокой точностью... В этом случае МК вообще не может отвлекаться на прерывания...
я не люблю прерывания.. с ними постоянно головняк..

Re: Несколько каналов АЦП Atmega 88

Чт авг 10, 2017 13:39:31

три выборки АЦП - просто стабильней... но это не убирает шум полностью. Нужно или делать МНОГО выборок (оцифровать входной сигнал),

много выборок ему нельзя делать, он ограничен 200 микросекундами

или использовать другой алгоритм, например я часто исмпользую гистерезис, который полностью убирает шум АЦП...

что за гистерезис?

Добавлено after 4 minutes 4 seconds:
)) не интересно им... Это хорошо если МК кроме оцифровки входного сигнала ничего бельше не делает... А если МК выполняет сложные операции с высокой точностью... В этом случае МК вообще не может отвлекаться на прерывания...

ну да, конечно, на прерывания отвлекаться нельзя, а вот задержки на 200 мкс делать можно. Вам самим-то не смешно? :)
Если ваш контроллер выполняет много разных задач, то при помощи прерывания обрабатываются самые важные. Для того прерывания и придуманы :)
я не люблю прерывания.. с ними постоянно головняк..

то, что не любите, это чувствуется, а головняк не от прерываний, а от неумения их правильно использовать :)

Re: Несколько каналов АЦП Atmega 88

Чт авг 10, 2017 13:56:32

гистерезис обычный... например вот так:

a=ADCW/2;
if (a>ub+1) {u=a/2; ub=a;};
if (a<ub-1) {u=a/2; ub=a;};

Тут, на выходе 10 разрядного АЦП получаем 8 разрядов данных (или 9 разрядов). Понятно, что разрешающая способность АЦП меньше, но зато последний разряд не шумит)) т.к. урень шума на входе АЦП меньше шага квантования АЦП...
ozonn писал(а):при помощи прерывания обрабатываются самые важные. Для того прерывания и придуманы

я об этом и говрю..)) у меня самые важные - это аварийное отключение систем ))
ozonn писал(а):на прерывания отвлекаться нельзя, а вот задержки на 200 мкс делать можно.

:))) задержка - это просто пример, если МК больше ничем не занят, то множно и делей delay_us(200);...

но чаще у меня по другому:

mesto_1: // начало
ADMUX=0b01100001; // где 1 - номер канала..
ADCSRA|=0b01000000; // где 1 - старт преобразования...

delay_us(200); // ждём 200 мкс... Пока идет преобразование АЦП, МК выполняет полезную работу, без отрыва на прерывание. ))

a=ADCW; // по окончании выполнения полезной работы, записали данные из АЦП в переменную "a" (тип int).
goto mesto_1; // конец. Перейти вначало.

Re: Несколько каналов АЦП Atmega 88

Чт авг 10, 2017 14:14:39

гистерезис обычный... например вот так:

a=ADCW/2;
if (a>ub+1) {u=a/2; ub=a;};
if (a<ub-1) {u=a/2; ub=a;};

честно говоря не понял. сначала делим результат измерения на 2, потом, независимо от того, больше ли это частное чем предыдущее частное плюс один или оно меньше, чем предыдущее частное минус один, выполняем одно и то же действие, а именно, еще раз делим результат на два. Т.е. получаем результат в четыре раза меньше измеренного. В чем тут фокус?

Добавлено after 2 minutes 35 seconds:
Пока идет преобразование АЦП, МК выполняет полезную работу, без отрыва на прерывание. ))

да, именно так и организавна программа с использованием прерывания. Пока идет преобразование, контроллер выполняет другую задачу, а как только преобразование завершилось, приступает к его обработке. И чем вам это не нравится? :shock:

Re: Несколько каналов АЦП Atmega 88

Чт авг 10, 2017 15:03:43

roman.com писал(а):Тут, на выходе 10 разрядного АЦП получаем 8 разрядов данных (или 9 разрядов). Понятно, что разрешающая способность АЦП меньше, но зато последний разряд не шумит))
чтобы получать 8 разрядов с нешумящими (хотя это самообман) разрядами, специально придуман режим "выравнивания влево" (бит ADLAR) - включите его и пользуйтесь ADCH в качестве результата - к чему какие-то загадочные вычисления, гистерезисы и т.п.?

но повторяю еще раз: это самообман. кто вам мешает в 10-битном результате всегда тупо давить младший бит в 0? и не будет он шуметь...
Ответить