- •Медицинские микропроцессорные системы
- •Анисимов а.А.
- •Isbn © сПбГэту «лэти», 2019 введение
- •1. Общая структура микроконтроллеров avr
- •2. Программирование микроконтроллеров на языке ассемблер
- •3. Работа с отладочной платой attiny104-xnano
- •4. Устройство портов ввода-вывода
- •5. Таймеры-счётчики
- •6. Широтно-импульсная модуляция
- •7. Использование аналого-цифрового преобразователя
- •8. Передача данных по uart
- •9. Последовательный интерфейс spi
- •Приложение 1. Основные команды языка assembler для микроконтроллера attiny104
- •Список литературы
- •Оглавление
- •Медицинские микропроцессорные системы
- •197376, С.-Петербург, ул. Проф. Попова, 5
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))) {}; // Ждем окончания передачи
}
