Arduino по-взрослому: Си и иже с ним. Лекция 5. ADC/АЦП

ВИШ RosCanSat Junior. Лекция 5.

Продолжаем лекцией про аналоговые измерения.

Теория

Как обычно, вся теория рассказана в видео.

Практика

Теперь напишем этот же пример на языке Си. Начнём с настойки мультиплексора — регистр ADMUX. Я люблю при первичной инициализации указывать все биты регистра. Биты MUXx используются для выбора входа. Помимо аналоговых входов вход АЦП может быть подключён к питанию МК, к «земле» или к встроенному аналоговому термометру. Я не рекомендую использовать этот термометр ввиду низкой точности показаний. Биты REFS1 и REFS0 устанавливают источник опорного напряжения — эталон для измерения. Можно выбрать как внутренний источник напряжения 2,56 В, так и внешний (вход AREF) или использовать в качестве эталона напряжение питания. Бит ADLAR определяет выравнивание: 1 — слева, 0 — справа.

ADLAR = 0
[-] [-] [-] [-] [-] [-] [9] [8]   [7] [6] [5] [4] [3] [2] [1] [0]

ADLAR = 1
[9] [8] [7] [6] [5] [4] [3] [2]   [1] [0] [-] [-] [-] [-] [-] [-]

Далее следует регистр ADCSRA — регистр управления и состояния. Биты ADPS2, ADPS1, ADPS0 отвечают за настройку тактовой частоты АЦП. Производитель рекомендует выбирать тактовую частоту в диапазоне 50..200 кГц. Биты ADIE и ADIF отвечают за прерывание по окончании измерения: разрешение и флаг прерывания соответственно. Следующий бит — ADATE устанавливает режим работы: 0 — преобразование запускается по команде, 1 — режим определяется битами ADTS2, ADTS1, ADTS0 регистра ADCSR1B. Бит ADSC — команда запуска преобразования. И последний бит — ADEN попросту включает или выключает АЦП.

В конечном итоге инициализация выглядит так:

//Инициализация ADC (АЦП)
/* 1. Регистр ADMUX - настройка аналогового мультиплексора
Биты REFS1 (7) и REFS0 (6) устанавливают какой источник опорного напряжения будет выбран:
0 0 - опорное напряжение на входе AREF (21 ножка)
0 1 - Vпитания (вход AREF должен быть отключен. или к нему можно подключить фильтрующий конденсатор)
1 0 - резерв
1 1 - внутренний ИОН (источник опорного напряжения) 1.1 В (к входу AREF можно подключить фильтрующий конденсатор)
Бит ADLAR (5) регистра ADMUX позволяет выравнивать результат преобразования по левому краю при записи в него 1.
Биты MUX3 - MUX0 (3 - 0) - управляют мультиплексором:
0 0 0 0 - вход ADC0 (23 ножка)
0 0 0 1 - вход ADC1 (24 ножка)
0 0 1 0 - вход ADC2 (25 ножка)
0 0 1 1 - вход ADC3 (26 ножка)
0 1 0 0 - вход ADC4 (27 ножка)
0 1 0 1 - вход ADC5 (28 ножка)
0 1 1 0 - резерв
0 1 1 1 - резерв
1 0 0 0 - датчик температуры
1 0 0 1 - резерв
1 0 1 0 - резерв
1 0 1 1 - резерв
1 1 0 0 - резерв
1 1 0 1 - резерв
1 1 1 0 - 1.1 В
1 1 1 1 - 0 В (земля) */
ADMUX = (1<<REFS1)|(1<<REFS0)|(0<<ADLAR)|(0<<MUX3)|(0<<MUX2)|(0<<MUX1)|(0<<MUX0);

/* 2. Регистр ADCSR1A - регистр управления и состояния АЦП
Бит ADEN (7) регистра ADCSRA включает или выключает АЦП (1-включен).
Бит ADSC (6) регистра ADCSRA запускает преобразование если в него записать 1 (для многоразового режима запуск первого преобразования).
Бит ADATE (5) регистра ADCSRA позволяет запускать преобразование по прерыванию от периферийных устройств микроконтроллера если установить в 1.
Бит ADIF (4) регистра ADCSRA - флаг прерывания от АЦП.
Бит ADIE (3) регистра ADCSRA - разрешает прерывания от АЦП если установлен в 1.
Биты ADPS2 - ADPS0 (2 - 0) регистра ADCSRA выбирают режим работы предделителя тактовой частоты:
0 0 0 - CLK/2
0 0 1 - CLK/2
0 1 0 - CLK/4
0 1 1 - CLK/8
1 0 0 - CLK/16
1 0 1 - CLK/32
1 1 0 - CLK/64
1 1 1 - CLK/128 */
ADCSRA = (1<<ADEN)|(0<<ADSC)|(0<<ADATE)|(1<<ADIF)|(0<<ADIE)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);

/* 3. Регистр ADCSR1B - регистр управления и состояния АЦП
Бит ACME (6) регистра ADCSRB позволяет использовать мультиплексор АЦП в качестве входов аналогового компаратора при установке 1 ( при этом АЦП должен быть выключен).
Биты ADTS2 - ADTS0 (2 - 0) регистра ADCSRB выбирают источник сигнала по которому будет начинаться преобразование АЦП:
0 0 0 - непрерывное преобразование
0 0 1 - прерывание от аналогового компаратора
0 1 0 - внешнее прерывание INT0
0 1 1 - прерывание по совпадению таймера/счетчика T0 с A
1 0 0 - прерывание по переполнению таймера/счетчика T0
1 0 1 - прерывание по совпадению таймера/счетчика T1 с B
1 1 0 - прерывание по переполнению таймера/счетчика T1
1 1 1 - прерывание по захвату таймера/счетчика T1 */
ADCSRB = (0<<ACME)|(0<<ADTS2)|(0<<ADTS1)|(0<<ADTS0);

Этот код нужно добавить в проект, который был создан в предыдущих статьях.

Теперь переходим к измерению. Алгоритм следующий — записываем бит ADSC, ожидаем поднятия флага ADFR, считываем результат и отправляем в порт.

while(1)
{
PORTB |= (1<<5); //Включаем светодиод
ADCSRA |= (1<<ADSC); //Запускаем преобразование
while(!(ADCSRA & (1<<ADIF))) {} //Ожидаем поднятия флага
UART_send_int(ADCL + (ADCH << 8)); //Отправляем полученный результат
UART_send_BK(); //Отправляем перенос строки
PORTB &=~ (1<<5); //Выключаем светодиод
_delay_ms(50); //Ждём 50 мс
}

Скриншот программы Монитор Порта Про

Конструкция while была рассмотрена во втором уроке цикла. Символ ! (восклицательный знак) обозначает отрицание. То есть, конструкция while(!(ADCSRA & (1<<ADIF))) {} означает пока (НЕ (в регистре ADCSRA на месте бита ADIF единица)) выполнять ничего.

Вместо скучной консоли можно использовать автоматический графопостроитель — SerialPort Plotter. Для этого перед числом нужно отправить символ «$» (0x24 по таблице ASCII), а после — символ «;» (0x3B по таблице ASCII).

Таблица ASCII

while(1)
{
PORTB |= (1<<5); //Включаем светодиод
ADCSRA |= (1<<ADSC); //Запускаем преобразование
while(!(ADCSRA & (1<<ADIF))) {} //Ожидаем поднятия флага
UART_send(0x24); //Отправляем "$"
UART_send_int(ADCL + (ADCH << 8)); //Отправляем полученный результат
UART_send(0x3B); //Отправляем ";"
UART_send_BK(); //Отправляем перенос строки
PORTB &=~ (1<<5); //Выключаем светодиод
_delay_ms(50); //Ждём 50 мс
}

Скриншот программы SerialPort Plotter
Но на этом аналоговые возможности цифрового микроконтроллера не заканчиваются. В следующей лекции речь пойдет о аналоговом компараторе и возможностях его применения в микроспутнике CanSat.

 

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

*

code