АЦП на Atmega32

Управлять через COM порт скважностью PWM на выводах МК  Atmega32 для проекта bluetooth-вертолета я уже научился. Теперь настало время разобраться с гироскопом. Он нужен для удержания заданного курса вертолета, который все время грозит измениться, особенно, когда нам это не нужно, благодаря вращающим моментам от основных двигателей. Штатный гироскоп китайской трехканалки представляет собой аналоговый датчик угловой скорости. В числе его выводов — опорное напряжение Vref и выходной сигнал Vout. Направление вращения можно определить по знаку разности Vout-Vref, а величина этой разности соответствует величине скорости. Поэтому нужно научится определять уровень Vout и Vref гироскопа и, сравнивая их, вырабатывать корректирующие команды, которые будут увеличивать или уменьшать обороты соответствующих двигатель для компенсации случайного вращения.

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

За основу я взял код программы из поста о PWM на ATmega32. И добавил туда инициализацию и использование АЦП. Инициализация:

//Программа инициализации АЦП
void init_ADC (void)
{
    ADCSRA=(1<<ADEN)|(1<<ADPS1)|(1<<ADPS0);
    /*Включаем АЦП, тактовая частота преобразователя =/8
от тактовой чистоты микроконтроллера*/
    ADMUX=(1<<REFS0);
    //Внутренний источник опорного напряжения Vref=2,56
}
//Программа инициализации АЦП
void init_ADC (void)
{
	ADCSRA=(1<<ADEN)|(1<<ADPS1)|(1<<ADPS0);
	/*Включаем АЦП, тактовая частота преобразователя =/8
от тактовой чистоты микроконтроллера*/
	ADMUX=(1<<REFS0);
	//Внутренний источник опорного напряжения Vref=2,56
}

Включение и выбор режимов запуска АЦП осуществляется выставлением соответствующих битов в регистре ADCSRA. Подробнее о них в даташите. В моем же случае преобразование осуществляется когда я его вызываю в основном цикле, а тактовая частота настраивается битами ADPSx. Конфигурацию источника опорного напряжения выбирается в регистре ADMUX с помощью битов REFSx. В программе инициализации я еще не назначаю вывод (выводы ADC0..7 порта А контроллера) уровень напряжения на котором будет использоваться для АЦП. Его, а точнее их, я определю в процедуре реализации преобразования:

//Функция считывания результатов АЦП
unsigned int getADC(void)
{   unsigned int v;
    ADMUX=0<<MUX0;// устанавливаем входом ADC0
    ADCSRA|=(1<<ADSC);  //Начать преобразование
    while ((ADCSRA&_BV(ADIF))==0x00) //Дождаться окончания преобразования
        ;
    v=(ADCL|ADCH<<8); // записываем значение
 
    ADMUX=1<<MUX0; //Устанавливаем входом ADC1
    ADCSRA|=(1<<ADSC);  //Начать преобразование
    while ((ADCSRA&_BV(ADIF))==0x00) //Дождатся окончания преобразования
        ;
    v=(ADCL|ADCH<<8)-v; //вычитаем из первого значения второе
 
    return v; // возвращаем результат
}
//Функция считывания результатов АЦП
unsigned int getADC(void)
{ 	unsigned int v;
 	ADMUX=0<<MUX0;// устанавливаем входом ADC0
 	ADCSRA|=(1<<ADSC);	//Начать преобразование
 	while ((ADCSRA&_BV(ADIF))==0x00) //Дождаться окончания преобразования
		;
 	v=(ADCL|ADCH<<8); // записываем значение

 	ADMUX=1<<MUX0; //Устанавливаем входом ADC1
 	ADCSRA|=(1<<ADSC);	//Начать преобразование
 	while ((ADCSRA&_BV(ADIF))==0x00) //Дождатся окончания преобразования
		;
 	v=(ADCL|ADCH<<8)-v; //вычитаем из первого значения второе

 	return v; // возвращаем результат
}

В подпрограмме считывания результатов АЦП последовательно «опрашиваются» входы 0 и 1 порта А, на которых заводится опорное напряжение гироскопа и выходное,  находится их разность и определяется направление вращения по знаку разности. Входы, с которых берет значения АЦП назначаются установкой битов MUX4..0.

В главную функцию программы добавляется процедура инициализации АЦП: init_ADC (); А в основной бесконечный цикл я добавил вызов функции сравнения:

While(1) {
         _delay_ms(10);// небольшая задержка
     OCR0=128-getADC()/4;//изменение PWM в зависимости от результатов АЦП
     put(OCR0);//печать результата АЦП в UART
    }
While(1) {
         _delay_ms(10);// небольшая задержка
	 OCR0=128-getADC()/4;//изменение PWM в зависимости от результатов АЦП
	 put(OCR0);//печать результата АЦП в UART
	}

В цикле будет меняется скважность ШИМ вывода PB3 МК ATmega32 в зависимости от разности напряжения на входах PA0 и PA1, то есть от показания гироскопа в моем случае. Для проверки кода добавим в схему Proteus’а из поста про PWM два переменных резистора (находятся по названию POT-HG):


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

Запись опубликована в рубрике AVR. Добавьте в закладки постоянную ссылку.

         
Подписаться на новые статьи блога:

Один комментарий: АЦП на Atmega32

  1. Joann говорит:

    This is cool!

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Лимит времени истёк. Пожалуйста, перезагрузите CAPTCHA.