ATmega8: использование АЦП на примере датчика освещенности собраного на фоторезисторе

разделы: AVR , дата: 24 октября 2015г.


схема подключения

Попробуем сделать датчик освещености. В комбинации с модулем RTC такой датчик может управлять освещением и подсветкой в системах типа: "умный дом". Датчик будет на фоторезисторе, сопротивление которого обратно пропорционально уровню освещености. Фоторезистор будет подключаться по схеме делителя напряжения, где в верхнее плечо будет установлен постоянный резистор 10K, а в нижнее сам фоторезистор. Нулевая точка будет поключена к пину ADC0 микроконтроллера. По такой же схеме можно подключать терморезистор или клавиатурную сборку на тактовых кнопках, где к каждой кнопке будет подключен резистор с каким-то своим индивидуальным значенем. Тогда, замеряя разность потенциалов, можно будет узнать какая имено кнопка была нажата.

Но вернемся к фоторезистору. Модель котрая мне попалась под руку - VT93N2. Даташит на него представлен ниже:

Чтобы иметь предстваление как это все должно работать, я сначала проверил это на Arduino с помощью такого скетча:

Результат работы был таким:

Здесь низкие значения соответствуют слабой освещености, а высокие - относительно яркой.

    Теперь, некоторые моменты реализации АПЦ в AVR микроконтроллерах:
  1. АЦП там один. НО можно задавать несколько пинов, с которых АЦП будет последовательно снимать показания в порядке очереди. Это называется каналами.
  2. АЦП там 10-битный, но младшие два бита относятся к зоне погрешности, чтобы снимать с них достоверную информацию, нужно чтобы частота оцифровки не превышала определенного значения, и нужно использовать специальный спящий режим ADC Noise Reduction, когда программа и перефирия отключаются ради бесшумной работы АЦП. Другими словами, приходится использовать 8-битный АЦП или проще использовать внешний АЦП.
  3. Значения АЦП выводятся в долях между землей и опорным напряжением. И то и то должно подаваться от эталонных источников, иначе качество выходной "цифры" будет неважнецкое.
  4. Приминительно к ATmega8, там существует два управляющих регистра АЦП: ADCSRA и ADMUX.
  5. Т.к. АЦП формально 10-битный, есть два регистра приемника: ADCH и ADCL. Существует специальный порядок чтения этих регистров, чтобы пока питается один, другой не менял своего значения при очередном преобразовании.
  6. Установкой бита ADLAR в регистре ADMUX, возможен 8-режим, т.е. когда старшие 8 битов пишутся в ADCH, а значением ADCL, как правило, пренебрегают.
  7. Имеется два режима работы АЦП: разовое и беспрерывная работа с определенной частотой. Частота дискретизации(оцифовки) задается тремя младшими битами ADPS2:ADPS0 в регистре ADCSRA.
  8. Имется прерывание по вектору ADC, кторое вызывается при окончании дискретизации. Т.е. это момент, когда можно забрать свежие данные. Вместо прерывания можно пользоваться ADIF флагом в регистре ADCSRA.
    В оффициальном руководстве к ATmega8 о АЦП рассказано, на мой взгляд, довольно сухо.
    Дополнительно о АЦП в AVR можно почитать онлайн:
  1. Аналого-цифровой преобразователь МК ATmega8
  2. AVR. Учебный курс. Использование АЦП
  3. Так же полезно будет почитать книгу: "Практическое программирование микроконтроллеров AVR" Юрия Ревича, глава десятая.

Пора снова вернуться к фоторезистору. Код который у меня получился в итоге:

#include <util/delay.h>
#include <uart.h>
#include <avr/io.h>
#include <avr/interrupt.h>

static FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE);

volatile uint8_t dataADC;
ISR(ADC_vect)
{
	dataADC=ADCH;
};

int main(void)
{
	//---- init
	init_uart();
        DDRB |= (1<<PB5); // led indicator

	ADCSRA |=(1<<ADEN)|(1<<ADFR)|(1<<ADIE)|(1<<ADSC)|(3<<ADPS0); // set 0xFF
	ADMUX  |=(1<<REFS0)|(1<<ADLAR);

	//---- ready indication
        blink13(3); //ready indication
	stdout = &mystdout;
	printf("Ok, I'm ready!\n");

	dataADC=0;
	sei();
	//---- main body
	for (;;)
	{
		printf("Voltage: %d\n",dataADC);
		_delay_ms(2000);
	};

        return 0;
}

Здесь используется 8-битный режим АЦП и непрерывную дискретизацию и AVcc в качестве опорного напряжения. Используется также ADC0 канал. Результат работы выглядит так:

Здесь в начале и в конце высокие значения, это темнота, а в середине виден след от фонарика. Для определения освещености, на мой взгляд, получилось не плохо. Если искусственое освещение имеет управление через ШИМ, то можно использовать для "умной" регулировки уровня освещенности.

Архив с полными исходниками и сборочными файлами можно скачать здесь: архив