Работа АЦП микроконтроллера AVR Atmega8

Любой микроконтроллер общается с периферийными устройствами при помощи портов ввода/вывода. При этом он способен “воспринимать” только цифровые сигналы – логический ноль или единицу. Например, у МК ATmega8 при напряжении питания 5 В логический ноль – это напряжение лежащие в интервале от 0 до 1,3 В, а единица – от 1,8 до 5 В. Довольно часто в радиолюбительской практике возникает необходимость измерять напряжения, которое может принимать любое значение в диапазоне от нуля до уровня напряжения питания. Для этих задач в составе всех микроконтроллеров AVR имеется аналого-цифровой преобразователь.
Радиоконструкторы на любой вкус

Работа микроконтроллера AVR с АЦП

Не вникая в подробности устройства АЦП, представим его типовым черного ящика. На вход АЦП идет аналоговый сигнал, а на выходе его имеем последовательность цифровых значений. АЦП имеет огромное число различных характеристик, из них можно выделить такие как: разрешающая способность, абсолютную точность, предельная частота дискретизации и диапазон входных напряжений.

Разрешающая способность или разрешение – эта характеристика АЦП помогает различать два значения входного сигнала. Определяется как величина обратная наибольшему числу кодовых комбинаций АЦП на выходе. У нашего МК АЦП десяти разрядный, поэтому максимальное число возможных кодовых комбинаций будет равно 210 = 1024, а его разрешающая способность равна 1/1024 от полной шкалы допустимых входных напряжений.

Для правильной работы АЦП требуется источник опорного напряжения (ИОН). По отношению к которому, АЦП измеряет сигналы поступающие на его вход. МК AVR позволяют в роли ИОН применять напряжение питания, их внутренний опорный источник на 2,56 В, а напряжение на выходе AREF (внешний ИОН).

Так как наша схема запитана от 5 В, тогда 1/1024 от всей шкалы получится 0,0048 В или около 5 мВ. С таким шагом АЦП будет определять уровень входного напряжения. Если два ближайших значения на входе преобразователя будут отличаться друг от друга на величину менее 5 мВ, АЦП будет считать равными. На практике разрешающая способность любого АЦП ограничена шумами.

Абсолютная точность АЦП это отклонение реального преобразования от идеального. Это составной результат нескольких погрешностей преобразователя. Математически описывается в количестве младших значащих разрядов (LSB). Максимальная абсолютная погрешность АЦП «Atmega8» равна 1.5 LSB. Для нашего случая абсолютная точность равна 2 × 5 мВ = ±10 мВ

Предельная частота дискретизации это есть быстродействие АЦП, которое измеряется в Гц или количестве выборок за секунду (SPS – samples per second). Для МК AVR она равна15 kSPS (килло семплов за секунду).

Давайте соберем схему чтоб было понятнее. Стандартная обвеска микроконтроллера непоказана, для упрощения, но она быть должна, посмотреть ее можно в этой статье "Простой проект на микроконтроллере Atmega 8 - мигающий светодиод".

Схема работы микроконтроллера AVR с АЦП

На порт В - МК AVR подключен типовой ЖК дисплей 16х2. Выводы AREF и AVCC подключены к питающему напряжению 5В. Это и есть ИОН. На порт С Atmega к нулевому разряду подключен контакт с вольтметром и переменным сопротивлением для изменения уровня входного напряжения. Наша задача в этом учебном примере следующая: Мы хотим вывести на ЖК экран величину напряжения, аналогичную измерению вольтметра.

Переходим к программированию запускаем новый проект в программе CodeVisionAVR. В настройках Chip выбираем МК Atmega8, частоту выставляем 4,00000000 MHz. (см. пример с мигающим светодиодом). Переходим во вкладку LCD выбираем PORTB. И сохраняем проект под названием ADC (аббревиатура АЦП на забугорном языке). Вначале необходимо добавить две директивы препроцессора для работы с текстом и задержкой. Для этого после директивы LCD вставим две строки.

#include <delay.h>
#include <stdio.h>

Первая строка необходима для задержек, а вторая для работы дисплея с текстом. Далее создаем массив для промежуточного хранения форматированного текста. После текста в коде, пишем.

// Declare your global variables here
char string[10];

Затем после открытия главной функции main, мы должны добавить еще две переменных. Одна из них используется для хранения значения после выборки, а другая для хранения выводимого на экран значения.

void main(void)
{
// Declare your local variables here
int data; // Переменная для хранения данных выборки. int так как регистр 10 разрядов.
float V; // Переменная для выводимого значения. float так как у нас точность до 2 знаков.

Теперь настроим сам АЦП. Для этого после настройка компаратора запишем следующее.

// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off

ACSR=0x80;
SFIOR=0x00;


ADMUX=0; // Первая строка, № порта.
ADCSR=0x85; // Вторая строка настройка АЦП. (в двоичной системе x85=10000101)

Для того чтоб начать работу с АЦП у МК имеется регистр ADCSR. Вот, что в нем находится.

0-й бит ADPS0 Настройка частоты преобразования
1-й бит ADPS1 -/-/-
2-й бит ADPS2 -/-/-
3-й бит ADIE Разрешение прерывания
4-й бит ADIF Флаг прерывания
5-й бит ADFR Выбор работы АЦП. 1-непрерывный либо 0-по запуску ADSC
6-й бит ADSC Запуск преобразование 1-старт. После преобразования сбрасывается в ноль аппаратно.
7-й бит ADEN Разрешение работы АЦП 1-да 0-нет

Для включения в АЦП записываем 1 в 7-й разряд, 0 в 6-й, 5-й, 3-й и 4-й разряды. Теперь подбираем частоту, т.к у нас кварц на 4000 кГц, то нам его надо поделить (для стабильной работы АЦП его требуется тактировать частотой в диапазоне 50 кГц - 200 кГц), чуть ниже представлена таблица коэффициентов деления.

ADPS2 ADPS1 ADPS0 Делитель
0 0 0 2
0 0 1 2
0 1 0 4
0 1 1 8
1 0 0 16
1 0 1 32
1 1 0 64
1 1 1 128

Возьмем коэффициент делителя на 32, получим частоту 125 кГц, что вполне достаточно для стабильной работы АЦП. Итак, в регистр ADCSR нам надо записать значение 10000101.

С настройками АЦП надеюсь понятно. Теперь давайте выведем в первой строке на экране наши намерения. Для этого после инициализации LCD дисплея запишем строчку. lcd_putsf("Work with ADC");

// LCD module initialization
lcd_init(16);
lcd_putsf("Work with ADC"); // Выводим запись

Теперь при старте программы В МК увидим эту надпись. Далее в бесконечном цикле пишем тело основной программы.

while (1)
{
delay_ms(20); // Задаем задержку в 20 миллисекунд
ADCSR |= 0x40; // Записываем 1 в ADSC
data = ADCW; // Вычитываем значение
V = (float) data*0.0048828; // Переводим в вольты
sprintf(string, "Data: %1.2f", V); // форматируем
lcd_gotoxy(0,1); // Выставляем курсор
lcd_puts(string); // Выводим значение

};

delay_ms(20); задержку на 20 миллисекунд.
ADCSR |= 0x40; битное ИЛИ. Число 0х40 в бинаре выглядит так 0b01000000. Если мы проведем по битное ИЛИ с 0х85 (0b10000101), то у нас в 6-й разряд запишется 1. Для того, чтобы началось преобразование в 6-й разряд нужно записать 1. А после преобразование он сбросится в 0 аппаратно.
data = ADCW; После преобразования микроконтроллер записывает полученное значение в ADCW. Вот оттуда мы его и возьмем
V = (float) data*0.0048828; Преобразуем полученное значение в вольты, т.к ИОН=5В, а значение регистра 1024, то мы 5/1024=0.0048828 получим коэффициент напряжения. Минимальная величина напряжения будет при минимальном значении регистра ADCW. То есть если в нем будет значение 1, то напряжение будет 0.0048828 В. Поэтому в строке, данные ADCW перемножаем на это значение - 0.0048828. Слово float в скобке используется для того чтобы преобразовать переменную data из целочисленной в вещественную с плавающей точкой.
sprintf(string, "Data: %1.2f", V); Заносим значение напряжения в массив string с последующим форматированием. Сначала впишем Data: . После ставим знак процента. 1.2f - говорит о том что мы хотим вывести на экран один знак до запятой и два знака после, а буква f означает, что это значение вещественным с плавающей точкой.
lcd_gotoxy(0,1); Курсор в нулевую позицию во второй строке.
lcd_puts(string); Выводим значение на дисплей.

Перед тем как собрать проект нужно сделать небольшие настройки в CodeVisionAVR. В меню нажимаем "Project->Configure" и в открывшемся окне переходим во вкладку "C Compiler", затем в левом нижнем углу меняем значение (s)printf Features: с int, width на float, width, precision.

Результат работы программы на рисунке ниже:

Результат работы МК с АЦП

Архив с проектом для CodeVisionAVR и Proteus вы можете скачать по зеленой ссылке выше. Затем распакуйте архив в корень диска С и проект можно запускать.