Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Микропроцессорные системы пособие.doc
Скачиваний:
0
Добавлен:
12.02.2026
Размер:
2.53 Mб
Скачать

7. Использование аналого-цифрового преобразователя

Все микроконтроллеры семейства AtMega и некоторые из семейства Tiny (как наш микроконтроллер AtTiny104) имеют встроенный блок аналого-цифрового преобразования (далее в тексте – АЦП). Он может использоваться для замены простого, но значительно менее функционального компаратора. АЦП этот десятиразрядный и многоканальный (количество каналов может варьироваться от 4 до 16 в зависимости от модели микроконтроллера). Но не стоит ждать особых изысков, модуль АЦП у нас всего один, просто на его входе стоит аналоговый мультиплексор, подключающий этот вход к различным выводам МК, что позволяет проводить разделенные во времени измерения сразу нескольких независимых аналоговых величин. Входы мультиплексора могут работать как по отдельности (в несимметричном режиме, измеряя напряжение относительно земли), так и объединяться в пары (только для некоторых моделей микроконтроллеров), измеряя дифференциальное напряжение. Также опционально возможно усиление входного сигнала с фиксированным коэффициентом 10 или 100.

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

Для выполнения первого преобразования (при первоначальной настройке АЦП) требуется 25 тактов. Тактовая частота преобразования формируется с помощью делителя от опорной частоты микроконтроллера при помощи соответствующего управляющего регистра, рекомендованная частота преобразования – от 50 до 200кГц, в этом диапазоне наиболее вероятно получение наиболее достоверного результата измерения. Как упоминалось ранее, модуль АЦП имеет разрешение в 10 бит, и, по заявлениям разработчиков, абсолютная погрешность не превышает двух младших значащих разрядов (погрешность не более 0,25% шкалы измерения). Для достижения подобных результатов необходимо применение как аппаратных, так и программных способов повышения точности измерений, с которыми можно дополнительно ознакомиться в фирменной документации.

Также возможно два режима преобразования: непрерывный (free-running mode), когда по завершении одного цикла преобразования сразу же следует другой, и одиночный (single), когда последовательность циклов регулируется вручную. Первый способ не отличается высокой точностью измерений и целесообразен только при необходимости максимальной скорости преобразований.

Настройка АЦП

Ознакомимся с регистрами, задающими режим работы аналого-цифрового преобразователя.

ADMUX (ADC Multiplexer Selection Register) – регистр, определяющий текущий канал АЦП, источник опорного напряжения и режим хранения данных. В этом регистре нас больше всего интересуют биты, описанные далее.

REFS1:0 (Reference Selection Bits) – определяют источник опорного напряжения, относительно которого будет происходить преобразование. Опорное напряжение должно быть как можно более стабильным, без помех и колебаний по напряжению – от этого во многом зависит точность работы АЦП. Все возможные варианты приведены в таблице 7.1.

Таблица 7.1. Выбор источника опорного напряжения АЦП

REFS[1:0]

Выбор источника опорного напряжения

00

Напряжение питания

01

Внутренний ИОН на 1.1В

10

Внутренний ИОН на 2.2В

11

Внутренний ИОН на 4.3В

Внутренний источник опорного напряжения не очень точный и подходит только для нетребовательных приложений.

MUX4:0 (Analog Channel and Gain Selection Bits) – данные биты определяют текущий вход, с которого мы будем считывать аналоговый сигнал. Также с помощью этих битов выставляется коэффициент усиления при измерении в дифференциальном режиме. Возможные конфигурации для выбора текущего источника входного сигнала представлены в таблице 7.2.

Таблица 7.2. Выбор текущего канала АЦП

MUX4..0

Номер канала

00000

ADC0

00001

ADC1

00010

ADC2

00011

ADC3

00100

ADC4

00101

ADC5

00110

ADC6

00111

ADC7

Данные с АЦП записываются в регистровую пару ADCH:ADCL, откуда их можно считать для дальнейшей обработки. Причем здесь есть один важный момент. Регистровая пара 16-ти разрядная, а АЦП имеет разрядность 10 бит. В итоге, лишь один регистр занят полностью, а второй занимают лишь оставшиеся два бита. Исходя из этого факта, выравнивание может производиться как по правому краю – старшие два бита в ADCH, а младшие в ADCL, так и по по левому – старшие биты в ADCH, а два младших бита в ADCL.

  • [9][8][7][6][5][4][3][2]:[1][0][x][x][x][x][x][x]

  • [x][x][x][x][x][x][9][8]:[7][6][5][4][3][2][1][0]

Для чего же хранение данных АЦП преобразования организовано именно таким образом? Так как в двух младших битах чаще всего достаточно сложно получить значимые данные (скорее всего, мы получим там всякий мусор и помехи), мы можем использовать выравнивание по правому краю и считывать данные преобразования только из одного регистра ADCH, экономя время и программный код. За выравнивание отвечает бит ADLAR. Записывая в него логический ноль, получаем выравнивание по правой границе, записываем единицу – по левой.

ADCSRA (ADC Control and Status Register A)

ADEN (ADC Enable) – записывая единицу в этот бит, разрешаем использование АЦП.

ADIE (ADC Interrupt Enable) – разрешение прерывания по завершению цикла преобразования.

ADPS2:0 (ADC Prescaler Select Bits) – позволяет выбрать коэффициент делителя тактовых импульсов для установки частоты преобразований (в непрерывном режиме). Значение коэффициента делителя определяется в соответствии с таблицей 7.3.

Таблица 7.3. Выбор коэффициента деления.

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

ADFR (ADC Free Running Select) – записывая единицу в этот бит, выбираем непрерывный режим преобразования.

ADSC (ADC Start Conversion) – записывая единицу в этот бит, мы начинаем очередной цикл преобразования в одиночном режиме работы (или первый цикл при непрерывном), который занимает 13 тактов (первый цикл – 25 тактов, здесь осуществляется первоначальная инициализация АЦП), при условии, что с помощью бита ADEN разрешено использование АЦП.

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

  • Настраиваем таймер на формирование прерывания по переполнению (берем 1000 выборок в секунду, т.е. таймер отсчитывает промежутки по 1мс)

  • Настраиваем АЦП (не забываем о необходимости разрешить прерывание по окончанию цикла преобразования, режим одиночных преобразований) и UART(скорость передачи 115200);

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

  • В прерывании от АЦП считываем данные с нулевого канала (к которому подключаем потенциометр), полученное в результате преобразования значение передаем по интерфейсу UART на компьютер.

  • Все операции проводятся в обработчиках прерываний, основной цикл должен оставаться пустым.

Далее представлен код программы на языке Си, выполняющий указанный выше алгоритм. Программу на языке Ассемблер необходимо разработать самостоятельно.

/*****************************************************************/

#define USART_BAUDRATE 9600 // Задаём скорость передачи данных

#define BAUD_PRESCALE ((F_CPU / (USART_BAUDRATE * 16UL)) - 1)

int main(void)

{

// Меняем тактовую частоту на 8 МГц (Clock Division = 1)

CCP = 0xD8;

CLKPSR = 0x00;

// Задаём настройки UART’а

UCSRC = (1 << UCSZ0) | (1 << UCSZ1); // 8 бит данных

UBRRH = (BAUD_PRESCALE >> 8); // Скорость передачи данных

UBRRL = BAUD_PRESCALE; // Записываем в оба регистра

UCSRB = (1 << TXEN); // Разрешаем передачу данных

// Настраиваем работу АЦП

// Разрешаем работу АЦП и прерывания, устанавливаем переделитесь на 16

ADCSRA |= (1 << ADEN) | (1 << ADPS2)| (1 << ADIE);

ADMUX |= (1 << MUX1) | (1 << MUX0); // Используем канал ADC3

DIDR0 |= (1 << ADC3D); // Режим энергосбережения

// Настраиваем таймер

TCCR0B |= (0<<CS00)|(1<<CS01); // Задаем предделитель таймера

// Разрешаем прерывание по переполнению таймера

TIMSK0 |= (1<<TOIE0);

// Разрешаем прерывания на глобальном уровне

sei();

while (1) // Бесконечный цикл

{

// Оставляем его пустым, вся работа идёт в прерываниях

}

}

// Обработчик прерывания по переполнению таймера

ISR(TIM0_OVF_vect)

{

// Начинаем одиночное преобразование, ждем окончания преобразования

ADCSRA |= (1 << ADSC);

}

// Обработчик прерывания по завершению АЦП преобразования

ISR(ADC_vect)

{

// Сохраняем результат в переменной analogReading

uint16_t analogReading = ADCL | (ADCH << 8);

UDR = (analogReading << 2); / // Посылаем данные по UART

while (!(UCSRA & (1 << UDRE))) {}; // Ждем окончания передачи

}