Опрос 6 каналов АЦП ATmega8

Обсуждаем контроллеры компании Atmel.
Ответить
Родился
Сообщения: 14
Зарегистрирован: Пн фев 29, 2016 13:19:10

Сообщение Tol19 »

Здравствуйте!Есть проблема. Есть программа двух канального вольтметра с индикацией на WH1602, которая работает и моделируется в протеусе:

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

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include "lcd_lib.h"//библиотека для работы с дисплеем
#include <stdio.h>

unsigned int voltage[4], voltage_1,   adc_counter;
volatile unsigned long voltage_value[4], voltage_value_1;

uint8_t res;
 //Функция вывода переменной
void lcd_num_to_str(unsigned int value, unsigned char nDigit)
{
switch(nDigit)
{
case 4: lcd_dat((value/1000)+'0');
case 3: lcd_dat(((value/100)%10)+'0');
case 2: lcd_dat(((value/10)%10)+'0');
case 1: lcd_dat((value%10)+'0');
}
}

// Обработчик прерывания от АЦП
ISR(ADC_vect)
{
ADCSRA = 0; // Выключаем АЦП 


if ((ADMUX & 0x0F)==1)
	{
		voltage_value = voltage_value + ADC; // Суммируем измеренные значения тока и помещаем в буфер
		ADMUX = (ADMUX & 0xF0) | 0; // Выбираем канал ADC0
		 // Увеличиваем счетчик выборок АЦП на 1
	}	
	else{
		voltage_value_1 = voltage_value_1 + ADC; // Суммируем измеренные значения тока и помещаем в буфер
		ADMUX = (ADMUX & 0xF0) | 1;
		adc_counter++;
	}


// Включаем АЦП
ADCSRA |= (1 << ADEN)|(1 << ADSC)|(1 << ADPS2)|(1 << ADPS1)|(1 << ADPS0)|(1 << ADIE)|(0<<REFS1)|(0<<REFS0);
}

int main(void) 
{
ADMUX |= (0 << REFS1)|(0 << REFS0); // Внутренний ИОН 2,56V
ADMUX |= (1 << MUX0); // Подключаем канал ADC1

ADCSRA |= (1 << ADEN) // разрешение АЦП
	|(1 << ADSC)     |(1 << ADPS2)|(1 << ADPS1)|(1 << ADPS0) // предделитель на 128
	|(1 << ADIE); // разрешение прерывания от АЦП

sei(); // Глобально разрешаем прерывания

lcd_init(); // Инициализация LCD
_delay_ms(25);

while(1) 
{
// вычисляем среднее значение АЦП
if (adc_counter > 40)
{
ADCSRA = 0; // Выключаем АЦП 
// преобразуем данные в реальное значение напряжения
voltage[0] = (voltage_value[0]/adc_counter)* 1.075;
voltage[1] = (voltage_value[1]/adc_counter)* 1.075;
voltage[2] = (voltage_value[2]/adc_counter)* 1.075;
voltage[3] = (voltage_value[3]/adc_counter)* 1.075;

adc_counter = 0; // Обнуляем счетчик выборок АЦП
voltage_value[0] = 0; // Обнуляем буфер значений напряжения
voltage_value[1] = 0; // Обнуляем буфер значений напряжения
voltage_value[2] = 0; // Обнуляем буфер значений напряжения
voltage_value[3] = 0; // Обнуляем буфер значений напряжения

lcd_gotoxy(0,1);
lcd_num_to_str(voltage[0]/100, 2);
lcd_string(".",1);
lcd_num_to_str(voltage[0], 2);

// Включаем АЦП
ADCSRA |= (1 << ADEN)|(1 << ADSC)|(1 << ADPS2)|(1 << ADPS1)|(1 << ADPS0)|(1 << ADIE)|(0<<REFS1)|(0<<REFS0) ;
}   
_delay_ms(1);
}
}
Однако, когда я пытаюсь опросить таким способом хотя бы 4 канала, возникают проблемы и протеус показывает пустой экран. Пробовал так:

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

switch (ADMUX & 0x0F)
 {
 case 0:voltage_value0+=ADC;break;
 case 1:voltage_value1+=ADC;break;
 case 2:voltage_value2+=ADC;break;
 case 3:voltage_value3+=ADC;break;
 }
ADMUX=(ADMUX & 0xF0)+((ADMUX & 0x0F)++ % 4);

И так:

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

voltage_value[ADMUX & 0x0F]+=ADC;
ADMUX=(ADMUX & 0xF0)+(((ADMUX & 0x0F)+1) % 4);
Бесполезно. В чем может быть проблема?
Реклама
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18783
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

Вообще-то для опроса канала АЦП разумно сделать отдельную функцию:

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

#define ADC_REF  _BV(REFS1) | _BV(REFS0)

int get_adc(uint8_t channel){
   ADMUX = ADC_REF | (channel & 0x07);
   ADCSRA |= _BV(ADSC); 
   while(ADCSRA & _BV(ADSC));
   // тут можно провести какие-то преобразования результата, если надо
   return ADC; 
}
и потом работать с результатом этой функции, передавая ей номер канала АЦП - усреднять результаты, выводить на экран и т.п.

и никаких прерываний не надо (пока). до первого вызова функции следует настроить АЦП правильными битами ADCSRA.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
Реклама
Вымогатель припоя
Сообщения: 522
Зарегистрирован: Чт янв 21, 2016 15:59:10

Сообщение ozonn »

для начала попробуйте напрямую записывать записывать в ADMUX, без извращений, типа ADMUX = 0b11110000, ADMUX = 0b11110001 и т.д.
Это проще, с какой стороны не глянь. Я в своем вольтамперметре опрашиваю таким образом три входа и работает безо всякиз проблем :)
Родился
Сообщения: 14
Зарегистрирован: Пн фев 29, 2016 13:19:10

Сообщение Tol19 »

Даже так не выходит. Почему?

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

if ((ADMUX & 0x0F)==0)
    {
        voltage_value[0] = voltage_value[0] + ADC; // Суммируем измеренные значения тока и помещаем в буфер
        ADMUX = (ADMUX & 0xF0) | 1; // Выбираем канал ADC0
         // Увеличиваем счетчик выборок АЦП на 1
    ADCSRA |= (1 << ADEN)|(1 << ADSC)|(1 << ADPS2)|(1 << ADPS1)|(1 << ADPS0)|(1 << ADIE)|(0<<REFS1)|(0<<REFS0);
    }   
    if ((ADMUX & 0x0F)==1)
    {
        voltage_value[1] = voltage_value[1] + ADC; // Суммируем измеренные значения тока и помещаем в буфер
        ADMUX = (ADMUX & 0xF0) | 2; // Выбираем канал ADC0
        // Увеличиваем счетчик выборок АЦП на 1
        
        ADCSRA |= (1 << ADEN)|(1 << ADSC)|(1 << ADPS2)|(1 << ADPS1)|(1 << ADPS0)|(1 << ADIE)|(0<<REFS1)|(0<<REFS0);
    }
    if ((ADMUX & 0x0F)==2)
    {
        voltage_value[2] = voltage_value[2] + ADC; // Суммируем измеренные значения тока и помещаем в буфер
        ADMUX = (ADMUX & 0xF0) | 0; // Выбираем канал ADC0
        adc_counter++;// Увеличиваем счетчик выборок АЦП на 1
        ADCSRA |= (1 << ADEN)|(1 << ADSC)|(1 << ADPS2)|(1 << ADPS1)|(1 << ADPS0)|(1 << ADIE)|(0<<REFS1)|(0<<REFS0);
    }
Реклама
Эиком - электронные компоненты и радиодетали
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18783
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

Tol19 писал(а):не выходит. Почему?
потому что делаете через анус. делайте хотя бы приблизительно правильно, и результат не заставит себя ждать.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
Реклама
Родился
Сообщения: 14
Зарегистрирован: Пн фев 29, 2016 13:19:10

Сообщение Tol19 »

Если бы я знал, как правильно, я бы не стал задавать вопросы, не так ли? :idea:
Реклама
Говорящий с текстолитом
Аватара пользователя
Сообщения: 1525
Зарегистрирован: Чт июн 10, 2010 20:11:19

Сообщение COKPOWEHEU »

в коде Tol19 отрабатывают все условия подряд, а не какое-то одно, но это неважно потому что неверен сам подход. Более правильный указал ARV - сначала заставить работать функцию и уже потом разбираться с прерываниями.
Ответить

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