Измерение постоянного напряжения при помощи АЦП AtMega32

Обсуждаем контроллеры компании Atmel.
Ответить
Встал на лапы
Сообщения: 99
Зарегистрирован: Чт мар 08, 2012 18:05:49
Откуда: Пермь

Сообщение x8973 »

Снова на связи я со своими глупыми вопросами...
Поставил себе задачу сделать контроль напряжения на батарее аккумуляторов с помощью микроконтроллера. Под рукой оказался только AtMega32. Сделал делитель напряжения 10:1 для батареи, повесил его на вход ADC1 (PA1). Написал следующий код:
Спойлер

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

/*
 * ADC_Voltmeter.cpp
 *
 * Created: 18.05.2014 19:34:44
 *  Author: x-8973
 */ 


#include <avr/io.h>
#include <avr/interrupt.h>
#include <math.h>
#define F_CPU 8000000UL
#include <util/delay.h>

unsigned int voltage, adc_counter;
volatile unsigned long voltage_value;

void USART_Transmit(unsigned char data) //Функция отправки данных USART
{
	while (!(UCSRA&(1<<UDRE))); //Ожидание опустошения буфера приема
	UDR = data; //Начало передачи данных			        
}

void funcUSARTInit(unsigned int baudrate) //Функция инициализации USART
{
	UBRRH = (baudrate >> 8);                  
	UBRRL = (baudrate & 0xFF);
	UCSRA = 0; //Удвоение скорости отключено
	UCSRB = _BV(RXEN) | _BV(TXEN); //Разрешение на прием и на передачу через USART
	UCSRC = _BV(URSEL) | _BV(UCSZ0) | _BV(UCSZ1); //Формат кадра: 8 бит данных, 1 стоп-бит.
}

ISR(ADC_vect)
{
	ADCSRA = 0; // Выключаем АЦП
	voltage_value = voltage_value + ADC; // Суммируем измеренные значения напряжения и помещаем в буфер
	adc_counter++; // Увеличиваем счетчик выборок АЦП на 1
	ADCSRA |= _BV(ADEN)|_BV(ADSC)|_BV(ADPS2)|_BV(ADPS1)|_BV(ADPS0)|_BV(ADIE); // Включаем АЦП
}

int main(void)
{
	ADMUX |=  _BV(REFS1) | (1 << REFS0); // Внутренний ИОН на 2,56В
	ADMUX |= (1 << MUX0); // Подключаем канал ADC1
 
	ADCSRA |= (1 << ADEN) // разрешение АЦП
				|(1 << ADSC) // запуск преобразования
                |(1 << ADPS2)|(1 << ADPS1)|(1 << ADPS0) // предделитель на 128
				|(1 << ADIE); // разрешение прерывания от АЦП
 
	sei(); // Глобально разрешаем прерывания
	funcUSARTInit(51);
    while(1)
    {
		if (adc_counter > 400)
		{
			ADCSRA = 0; // Выключаем АЦП
			// преобразуем данные в реальное значение напряжения
			voltage = (voltage_value/adc_counter);
			USART_Transmit(voltage);
			adc_counter = 0; // Обнуляем счетчик выборок АЦП
			voltage_value = 0; // Обнуляем буфер значений напряжения
			ADCSRA |= (1 << ADEN)|(1 << ADSC)|(1 << ADPS2)|(1 << ADPS1)|(1 << ADPS0)|(1 << ADIE);  // Включаем АЦП
		}
		_delay_ms(1000);
        //TODO:: Please write your application code 
    }
}
По ЮАРТу получаю медленно уменьшающееся число в районе E0, то есть 224. С пересчетом в вольты получается 0,56, что даже с умножением на 10 не дает 11,5 вольт на выходе батареи. Пересчитываю по формуле из даташита, Vin = (ADC*Vref)/1024.
На основе этого у меня два вопроса: что я не учел при написании прошивки, и почему, собственно, число в регистре ADC постепенно уменьшается, хотя напряжение на входе остается неизменным (проверено китайским тестером).
Реклама
Вымогатель припоя
Аватара пользователя
Сообщения: 577
Зарегистрирован: Ср июн 19, 2013 08:10:48
Откуда: Москва, СПб, Липецк, Рязань

Сообщение ИС-пытатель »

Было бы неплохо, если бы Вы приложили схему своего устройства.
Т.к. АЦП построено на основе конденсатора, возможно, у Вас в делителе использован слишком большой номинал резисторов и напряжение на этом конденсаторе слишком долго устанавливается. http://leoniv.livejournal.com/194681.html
Еще не учли, что adc_counter тоже должен быть volatile.
Еще, как вариант, данные в регистре АЦП повреждаются при его выключении. Правильнее было бы запретить прерывания от АЦП и прочитать данные с него, чем выключить его.
Вывод AREF при таком выборе ИОН отключен от питания?
Без схемы - на кофейной гуще гадать
Реклама
Встал на лапы
Сообщения: 99
Зарегистрирован: Чт мар 08, 2012 18:05:49
Откуда: Пермь

Сообщение x8973 »

ИС-пытатель, вот схема. AREF подключен к Vcc постоянно. Код, честно скажу, скоммуниздил из Интернета, убрав из него измерение тока на ADC0.
Вложения
sh.JPG
(63.92 КБ) 412 скачиваний
Вымогатель припоя
Аватара пользователя
Сообщения: 577
Зарегистрирован: Ср июн 19, 2013 08:10:48
Откуда: Москва, СПб, Липецк, Рязань

Сообщение ИС-пытатель »

А Вы Даташит читали? При подключении внутреннего ИОН нельзя подавать на вывод AREF какое-либо напряжение (естественно, отличное от значения самого источника, но поскольку угадать точное значение ИОН сложно, то просто нельзя). Оставьте вывод AREF свободным.
Как у Вас еще контроллер не сгорел.. :evil:
Последний раз редактировалось ИС-пытатель Ср май 21, 2014 20:58:46, всего редактировалось 4 раза.
Реклама
Эиком - электронные компоненты и радиодетали
Встал на лапы
Сообщения: 99
Зарегистрирован: Чт мар 08, 2012 18:05:49
Откуда: Пермь

Сообщение x8973 »

Да, в AREF и проблема. Только сейчас догадался повнимательнее посмотреть на схему из исходной статьи, там AREF посажен на землю через конденсатор.
Честно - даташит смотрел только на предмет содержимого регистров)
Реклама
Держит паяльник хвостом
Сообщения: 933
Зарегистрирован: Ср апр 13, 2011 11:09:20
Откуда: Екатеринбург

Сообщение Alkul »

x8973 писал(а):ИС-пытатель, вот схема.
Плохая схема. При задействовании внутреннего АЦП вывод AVCC нужно подключать через LC-фильтр, как показано в даташите, найдите даташит и посмотрите в разделе Analog-to-Digital Converter.
Далее - подключать AREF напрямую к питанию МК - моветон, так как при работе МК питание "пульсирует" и эти пульсации скажутся на зашумленности результатов измерений. Если используется встроенный ИОН, то AREF вообще нельзя подключать к питанию, только на землю через конденсатор 0,1мкФ.
Далее - где блокировочные конденсаторы? Хотя бы один по питанию?
Далее - на вход АЦП сигнал желательно подавать через RC-фильтр (интегрирующую RC-цепь). Резистор порядка 200 Ом, конденсатор - керамический 0,1 мкФ.
Далее - вывод RESET через резистор 10 кОм подключить к питанию.

Это только самые грубые "ляпы"...
Каждый раз удивляюсь - неужели перед тем, как начать разработку схемы на МК, нельзя почитать даташит?
Реклама
Встал на лапы
Сообщения: 99
Зарегистрирован: Чт мар 08, 2012 18:05:49
Откуда: Пермь

Сообщение x8973 »

Alkul, резистор на Резете и конденсаторы по питанию имеются, я их просто в схеме не отобразил. Про RC-фильтр согласен - не знал, поленился посмотреть. Думал, в статье все необходимое есть. Учту на будущее.
Вымогатель припоя
Аватара пользователя
Сообщения: 577
Зарегистрирован: Ср июн 19, 2013 08:10:48
Откуда: Москва, СПб, Липецк, Рязань

Сообщение ИС-пытатель »

Alkul не только ответил на вопрос, но и "пропатчил" чувака по полной, чтобы вопросов вообще больше не возникало... :))) 5 баллов! ;)
Про фильтр скажу так. Если у Вас к питанию МК идет хорошо стабилизированное напряжение с достаточной мощностью (а ее для МК в 99 % случаев хватает за глаза), то лепить фильтры не обязательно. Да, это скажется на точности измерения (2-3 младших значащих разряда), но в большинстве случаев - не существенно. На вход АЦП фильтр - тоже вопрос спорный. Смотря чего достичь желаете. И какая скорость преобразования.
Последний раз редактировалось ИС-пытатель Ср май 21, 2014 21:14:06, всего редактировалось 1 раз.
Встал на лапы
Сообщения: 99
Зарегистрирован: Чт мар 08, 2012 18:05:49
Откуда: Пермь

Сообщение x8973 »

ИС-пытатель, питание идет с программатора, по USB.
Вымогатель припоя
Аватара пользователя
Сообщения: 577
Зарегистрирован: Ср июн 19, 2013 08:10:48
Откуда: Москва, СПб, Липецк, Рязань

Сообщение ИС-пытатель »

Ну, блоки питания в ПК довольно неплохо стабилизированы (Если, конечно у Вас ПК не за 5 000 р), поэтому с питанием можно не парится. А что, так и будет от программатора работать? )))
Встал на лапы
Сообщения: 99
Зарегистрирован: Чт мар 08, 2012 18:05:49
Откуда: Пермь

Сообщение x8973 »

ИС-пытатель, нет, конечно) Собрано пока на некоем подобии макетной платы. Потом будет питаться от преобразователя на 34063, контролировать в том числе будет и свое питание.
Держит паяльник хвостом
Сообщения: 933
Зарегистрирован: Ср апр 13, 2011 11:09:20
Откуда: Екатеринбург

Сообщение Alkul »

x8973 писал(а):Alkul, резистор на Резете и конденсаторы по питанию имеются, я их просто в схеме не отобразил.
Ну, знаете... Вы уж в следующий раз приводите схему полностью, ибо "дьявол кроется в мелочах", а в электронике мелочей не бывает. Для того, чтобы помочь Вам, мы должны видеть полную картину.
ИС-пытатель писал(а):5 баллов! ;)
:))
ИС-пытатель писал(а):Про фильтр скажу так. Если у Вас к питанию МК идет хорошо стабилизированное напряжение с достаточной мощностью (а ее для МК в 99 % случаев хватает за глаза), то лепить фильтры не обязательно.
Блокировочные конденсаторы никогда лишними не будут.
ИС-пытатель писал(а):Да, это скажется на точности измерения (2-3 младших значащих разряда), но в большинстве случаев - не существенно.
Ну, если вспомнить, что часто АЦП используют в 8-ми разрядном режиме, то потеря двух-трех младших разрядов - это существенное снижение динамического диапазона
Тем более, что все эти фильтры не такие уж сложные и элементов требуют по минимуму. Смысл экономить на спичках?
Вымогатель припоя
Аватара пользователя
Сообщения: 577
Зарегистрирован: Ср июн 19, 2013 08:10:48
Откуда: Москва, СПб, Липецк, Рязань

Сообщение ИС-пытатель »

В 8-разрядном режиме берутся старшие 8 бит. )
Встал на лапы
Сообщения: 99
Зарегистрирован: Чт мар 08, 2012 18:05:49
Откуда: Пермь

Сообщение x8973 »

Не знаю, в чем тут магия, но если отключать только прерывание, то данные перестают идти вообще. Прерывание срабатывает один раз, при перезагрузке контроллера, и все.
Выключаю прерывания:

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

ADCSRA &= ~_BV(ADIE);
Включаю прерывания:

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

ADCSRA |= _BV(ADIE);
AREF от питания отключил, повесил через конденсатор на землю.
Низкие напряжения (4,8 вольт питающих, 3,6 вольт от одного аккумулятора) воспринимает нормально, а вот с необходимыми 11,5 - накладочка. Может, переполнение переменной voltage проходит? Хотя она вроде как 16 бит должна быть, с ЮАРТа должно было приходить по 2 байта. Приходит же по одному. Или в 8-битных АВРах int занимает 1 байт?
Вложения
Снимок.PNG
Так выглядит попытка измерения высокого напряжения.
(3.69 КБ) 583 скачивания
Вымогатель припоя
Аватара пользователя
Сообщения: 577
Зарегистрирован: Ср июн 19, 2013 08:10:48
Откуда: Москва, СПб, Липецк, Рязань

Сообщение ИС-пытатель »

int занимает 2 байта. только когда вы пихаете int в 8-битный UART (или куда-то еще, где всего 8 бит), то берется младшая часть, а старшая "сделай папе ручкой". Чтобы отправить старшую часть вдогонку младшей необходимо пользовать операции сдвига.

UDR = voltage;
UDR = voltage>>8;

P.S. Здесь без ожидания завершения отправки
Встал на лапы
Сообщения: 99
Зарегистрирован: Чт мар 08, 2012 18:05:49
Откуда: Пермь

Сообщение x8973 »

ИС-пытатель, ура! Данные пошли, меряет правильно. Осталось разобраться с постепенным уменьшением значения измеренного напряжения. Напряжение на входе постоянное - проверено тестером.
Вымогатель припоя
Аватара пользователя
Сообщения: 577
Зарегистрирован: Ср июн 19, 2013 08:10:48
Откуда: Москва, СПб, Липецк, Рязань

Сообщение ИС-пытатель »

Измеренное напряжение опускается меньше того, что замерено тестером? Или оно сначала больше него, а потом опускается до его уровня? И в каких пределах меняется напряжение?
Думаю, скорее всего "плывет" напряжение ИОН. Если хотите более-менее точных результатов - подключайте внешнюю стабилизированную опору, желательно развязанную с питанием контроллера.
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18723
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

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

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

uint16_t get_adc(uint8_t adc_chanel){
   ADMUX = ADC_REFS | (adc_chanel & 0x07);
   ADCSRA |= _BV(ADSC);
   while(ADCSRA & _BV(ADSC));
   return ADC;
}
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
Ответить

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