Программирование микроконтроллеров. Часть 3-1

05.01.2018

Иногда возникает необходимость измерить аналоговый сигнал, например, температуру или напряжение на аккумуляторе, обработать его и вывести на индикатор в удобной для нас форме. Для этого применяется АЦП - Аналого-цифровой преобразователь. АЦП – это устройство, преобразующее входной аналоговый сигнал в дискретный код (цифровой сигнал).

Подробнее про АЦП, на какие типы делятся АЦП и прочие характеристики можно прочитать в википедии: https://ru.wikipedia.org/wiki/Аналого-цифровой_преобразователь

Сегодня я покажу Вам как можно включить встроенный в микроконтроллерАЦП. И в зависимости от угла поворота переменного резистора зажигать или гасить линейку светодиодов.

В микроконтроллере atmega328p имеется 10 разрядный 6-канальный АЦП в корпусе PDIP, который висит на порту С. Выходное напряжение конвертируется в 10 разрядное двоичное значение. Минимальное значение соответствует 0, а максимальное опорному напряжению. В данном микроконтроллере имеется 4 вида опорных напряжений, которые переключаются определённым битом при настройке АЦП. Полученный результат преобразования записывается в 2 регистра ADCH и ADCL.

Для этого нам понадобиться собрать следующую схему:

В этом уроке я буду использовать напряжение источника питания в качестве опорного напряжения. Выводы AREF и AVCC соединены с плюсом питания схемы. Переменный резистор на 10к крайними выводами подключен к источнику питания и к общему проводу схемы, а средним выводом подключен к входу АЦП микроконтроллера. Также к микроконтроллеру подключены 8 светодиодов которые будут отображать результат преобразования напряжения питания в виде светодиодной шкалы.

Код выглядит следующим образом:

#define F_CPU 8000000UL //Рабочая частота МК (8МГц)
#include <avr/io.h>
#include <util/delay.h> //для _delay_ms()

//Инициализируем порты
void port_ini(void)
{
DDRD=0xff;
PORTD=0x00;
}

//Инициализируем АЦП
void ADC_Init(){
ADCSRA |= (1<<ADEN) // Разрешение использования АЦП
|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);//Делитель 128
ADMUX |= (0<<REFS1)|(0<<REFS0); //Подключен внешний опорный ион, внутренний ион выключен
ADMUX |= (0 << MUX0)|(0 << MUX1)|(0 << MUX2)|(0 << MUX3); // вход PC0
}

//Получаем данные с АЦП
unsigned int ADC_convert (void)
{
ADCSRA |= (1<<ADSC); //Начинаем преобразование
while((ADCSRA & (1<<ADSC))); //проверим закончилось ли аналого-цифровое преобразование
return (unsigned int) ADC;
}

//Главная функция
int main(void)
{
port_ini(); //Инициализируем порты
ADC_Init(); //Инициализируем АЦП
unsigned int u;
while (1)
{

u = ADC_convert(); //Вызывем преобразование

//Проверяем считанное значение и отображаем на шкале светодиодов
if (u > 128)
PORTD = 0b00000001;
else
PORTD = 0b00000000;
if (u > 256)
PORTD = 0b00000011;
if (u > 384)
PORTD = 0b00000111;
if (u > 512)
PORTD = 0b00001111;
if (u > 640)
PORTD = 0b00011111;
if (u > 768)
PORTD = 0b00111111;
if (u > 896)
PORTD = 0b01111111;
if (u > 1020)
PORTD = 0b11111111;
_delay_ms(30);
}
}



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

Результат моделирования схемы в Proteus: