Программирование микроконтроллеров. Часть 3-1
И снова здравствуйте! Иногда возникает необходимость измерить аналоговый сигнал, например, температуру или напряжение на аккумуляторе, обработать его и вывести на индикатор в удобной для нас форме. Для этого применяется АЦП - Аналого-цифровой преобразователь. АЦП – это устройство, преобразующее входной аналоговый сигнал в дискретный код (цифровой сигнал).
Подробнее про АЦП, на какие типы делятся АЦП и прочие характеристики можно прочитать в википедии: 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:
Если есть вопросы и предложения по этому уроку, пишите комментарии буду рад ответить на ваши вопросы.
Мой блог в ЖЖ: http://evgenij-byvshev.livejournal.com