Проблемы с АЦП Atmega168

Вопросы настройки, программирования, прошивки микроконтроллеров и микросхем программируемой логики
Закрыто
woosterstring
Нашел транзистор. Понюхал.
Сообщения: 192
Зарегистрирован: Чт сен 16, 2010 19:47:01
Откуда: Украина

Проблемы с АЦП Atmega168

Сообщение woosterstring »

Привет всем.
В устройстве используется Atmega168 (TQFP32), в котором задействованы 5 каналов АЦП (ADC0 - ADC4). Частота выборки небольшая. Источник опорного - внешний, прецизионный. Питание АЦП - через фильтр. Программа написана на С, отлажена. Но это ремарка.
После прошивки МК считывает по всем каналам номинал опорного напряжения. При этом с платами всё в порядке, сигналы на входах на превышают опорное.
Инициализация АЦП следующая:

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

void ADC_init(char ch_name, char div_factor)
{
	//cli();
	// Первичный выбор канала
	ADC_channel_select(ch_name);
	// Коэффициент деления
	ADC_prescaller(div_factor);
	//ADIE запрещаем прерывание
	ADMUX = (0<<REFS1)|(0<<REFS0)|(0<<ADLAR);
	ADCSRA = (1<<ADEN)|(0<<ADATE)|(0<<ADIF)|(0<<ADIE);
	DIDR0 = (1<<ADC4D)|(1<<ADC3D)|(1<<ADC2D)|(1<<ADC1D)|(1<<ADC0D);
	// Слепое преобразование 
	ADC_start_conversion();
	while(ADCSRA & (1<<ADSC));	
	//sei();
}
Раньше таких проблем с этими МК не было (правда использовал корпуса DIP28). Такое впечатление, что задействована внутрення подтяжка к + питания, хотя цифровые функции каналов отключены.
В чём подвох?
Реклама
Аватара пользователя
YS
Друг Кота
Сообщения: 7518
Зарегистрирован: Вс мар 29, 2009 22:09:05
Контактная информация:

Re: Проблемы с АЦП Atmega168

Сообщение YS »

Чему равно ch_name? Мультиплексор в AVR позволяет подключить АЦП напрямую к опорному. Для этого есть специальные значения.
Разница между теорией и практикой на практике гораздо больше, чем в теории.
Реклама
woosterstring
Нашел транзистор. Понюхал.
Сообщения: 192
Зарегистрирован: Чт сен 16, 2010 19:47:01
Откуда: Украина

Re: Проблемы с АЦП Atmega168

Сообщение woosterstring »

Там такая конструкция:

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

	switch(ch_name) 
	{
		case(0): ADMUX = (0<<MUX2)|(0<<MUX1)|(0<<MUX0); break;
		case(1): ADMUX = (0<<MUX2)|(0<<MUX1)|(1<<MUX0); break;
		case(2): ADMUX = (0<<MUX2)|(1<<MUX1)|(0<<MUX0); break;
		case(3): ADMUX = (0<<MUX2)|(1<<MUX1)|(1<<MUX0); break;
		case(4): ADMUX = (1<<MUX2)|(0<<MUX1)|(0<<MUX0); break;
		default:  ADMUX =  (0<<MUX2)|(0<<MUX1)|(0<<MUX0); break;
	}
(А про ADMUX на стр. 255 datasheet 2545L–AVR–08/07).
Аватара пользователя
YS
Друг Кота
Сообщения: 7518
Зарегистрирован: Вс мар 29, 2009 22:09:05
Контактная информация:

Re: Проблемы с АЦП Atmega168

Сообщение YS »

Разберем код:

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

void ADC_init(char ch_name, char div_factor)
{
   //cli();
   // Первичный выбор канала
   ADC_channel_select(ch_name);  

//БЕСПОЛЕЗНЫЙ КОД. ПОСЛЕДУЮЩЕЕ ПРИСВОЕНИЕ ADMUX НЕЙТРАЛИЗУЕТ ЕГО ДЕЙСТВИЕ.

   // Коэффициент деления
   ADC_prescaller(div_factor);
   //ADIE запрещаем прерывание
   ADMUX = (0<<REFS1)|(0<<REFS0)|(0<<ADLAR);  

//БЕСПОЛЕЗНЫЙ КОД. НАЧАЛЬНОЕ СОСТОЯНИЕ ADMUX - ВСЕ НУЛИ. УСТАНАВЛИВАТЬ ИМЕЕТ СМЫСЛ ТОЛЬКО ЕДИНИЦЫ. КСТАТИ, ЭТА СТРОЧКА НИВЕЛИРУЕТ ДЕЙСТВИЕ ADC_channel_select(), ИБО ПИШЕТСЯ СРАЗУ ВЕСЬ РЕГИСТР, Т.Е., В MUX ОКАЗЫВАЮТСЯ ВСЕ НУЛИ.

   ADCSRA = (1<<ADEN)|(0<<ADATE)|(0<<ADIF)|(0<<ADIE); 

// ОПЯТЬ ЖЕ, ВО-ПЕРВЫХ, НУЛИ ЗАПИСЫВАТЬ БЕССМЫСЛЕННО, ЭТО НАЧАЛЬНОЕ СОСТОЯНИЕ, А ВО-ВТОРЫХ, НУЛИ ЗАПИСЫВАЮТСЯ НЕ ТАК. А В-ТРЕТЬИХ, ЭТОТ КОД НЕЙТРАЛИЗУЕТ ДЕЙСТВИЕ ADC_prescaller(). МЫ ГЛУШИМ ВСЕ, ЧТО ЗАПИСАЛА ЭТА ФУНКЦИЯ, ИБО ПИШЕМ СРАЗУ В ВЕСЬ РЕГИСТР.

   DIDR0 = (1<<ADC4D)|(1<<ADC3D)|(1<<ADC2D)|(1<<ADC1D)|(1<<ADC0D);

//ВРОДЕ НОРМАЛЬНО...

   // Слепое преобразование 
   ADC_start_conversion(); 

//СМЫСЛ ВЫДЕЛЯТЬ В ОТДЕЛЬНУЮ ФУНКЦИЮ? ПОТЕРЯ ВРЕМЕНИ... ХОТЯ ФАКТИЧЕСКИ ОШИБКИ НЕТ. ДЕЛО ХОЗЯЙСКОЕ...

   while(ADCSRA & (1<<ADSC));   
   //sei();
Разница между теорией и практикой на практике гораздо больше, чем в теории.
Реклама
Эиком - электронные компоненты и радиодетали
Аватара пользователя
YS
Друг Кота
Сообщения: 7518
Зарегистрирован: Вс мар 29, 2009 22:09:05
Контактная информация:

Re: Проблемы с АЦП Atmega168

Сообщение YS »

"=" записывает весь регистр. Ясное дело, что те биты, которые мы явно не установили в единицу, по умолчанию принимаются нулями и глушат все, что было записано в них до того.

Если нужно установить какие-то биты в регистре, не трогая остальные, делают так:

REG|=(1<<BIT1) | (1<<BIT2) | ... | (BITn);

Если же нужно очистить какие-то биты, не трогая остальные, то так:

REG&=~((1<<BIT1) | (1<<BIT2) | ... | (BITn));
Разница между теорией и практикой на практике гораздо больше, чем в теории.
Реклама
woosterstring
Нашел транзистор. Понюхал.
Сообщения: 192
Зарегистрирован: Чт сен 16, 2010 19:47:01
Откуда: Украина

Re: Проблемы с АЦП Atmega168

Сообщение woosterstring »

Спасибо, YS.
С поразрядным ИЛИ наглупил.
По воводу нулей - пишу так, чтобы помнить.
Реклама
Аватара пользователя
YS
Друг Кота
Сообщения: 7518
Зарегистрирован: Вс мар 29, 2009 22:09:05
Контактная информация:

Re: Проблемы с АЦП Atmega168

Сообщение YS »

По воводу нулей - пишу так, чтобы помнить.
Лучше пишите комментарии. Не стоит тратить процессорное время на напоминалки. :idea: Хотя дело хозяйское...
Разница между теорией и практикой на практике гораздо больше, чем в теории.
Закрыто

Вернуться в «Микроконтроллеры и ПЛИС»