По техническим причинам заседание клуба не состоялось, однако тема для разговора есть и она очень важна в контексте того,что мы с Вами обсуждали на прошлом заседании. Тогда мы рассмотрели программирование микроконтроллера на основе создание устройства "Бегущий огонь" и хоть оно не проявляет особой требовательности к процессору и программе, однако на её примере мы рассмотрели написание программы используя внутренние устройство микроконтроллера. Теперь, когда мы убедились что стандартные функции для работы с дискретными сигналами работают в разы медленнее, а размер программы на порядок меньше, имеет смысл рассмотреть и другие способы управления сигналами на выводах микроконтроллера, используя регистры нашего микроконтроллера. Однако надо отдавать себе отчёт, что у этого способа есть плюсы и минусы. Основных плюсов два, скорость реакции программы её размер. К основным минусам можно отнести, то что рассматривая регистры конкретного микроконтроллера, мы неизбежно столкнётся, с тем что на других МК структура регистров и их количество будет различаться, и как следствие программа становиться не переносимой. Другим значительным минусом становиться трудоемкость написания программы, что требует большей квалификации от программиста разработчика.
Тем не менее, мы знаем, что функции ввода-вывода цифровых сигналов digitalWriter() и digitalRead() можно заменить на непосредственные операции с регистрами портов D,В,C. Теперь пора перейти к рассмотрению аналоговых сигналов, которые может обрабатывать микроконтроллер.
В отличие от остальных функций, ускорение функции analogRead() достигается не модификацией её исходного кода, а настройкой режима работы АЦП. Но обо всем по порядку и начнем с описания работы АЦП микроконтроллера Atmega 328P.
Тем не менее, мы знаем, что функции ввода-вывода цифровых сигналов digitalWriter() и digitalRead() можно заменить на непосредственные операции с регистрами портов D,В,C. Теперь пора перейти к рассмотрению аналоговых сигналов, которые может обрабатывать микроконтроллер.
В отличие от остальных функций, ускорение функции analogRead() достигается не модификацией её исходного кода, а настройкой режима работы АЦП. Но обо всем по порядку и начнем с описания работы АЦП микроконтроллера Atmega 328P.
Микроконтроллер Atmega 328P, на котором построен Arduino Uno содержит встроенный 10-битный аналого-цифровой преобразователь (далее АЦП, англ. ADC — Analog to Digital Converter) последовательного приближения. Именно он, как видно из названия, отвечает за оцифровку входящего аналогового сигнала.
|
По умолчанию, у Arduino в качестве ИОН
выступает напряжение пиитания МК — 5 В. Для использования в качестве ИОН
других источников референсного внешнего напряжения у микроконтроллера
есть дополнительный вход AREF. Перед преобразованием аналогового
сигнала, при использовании внешнего ИОН необходимо вызвать функцию analogReference().
|
Сигнал, поданный на вход АЦП должен быть в границах заданного диапазона 0 (GND)...ИОН. 10-битный означает, что заданный диапазон будет разбит на значения, и входной сигнал будет оцифрован в соответствующее цифровое значение из диапазона 0...1023:
|
Запуск преобразования может осуществляться несколькими способами:
|
Для управления АЦП существует 5 основных восьмибитных регистров:
|
Регистр ADCSRA (ADC Control and Status Register A)
Назначение битов регистра ADCSRA (ADC Control and Status Register A, регистр управления и состояния):
- ADEN (ADC Enable, включение АЦП) — флаг, разрешающий использование АЦП, при сбросе флага во время преобразования процесс останавливается;
- ADATE (ADC Auto Trigger Enable) — выбор режима работы АЦП. 0 – разовое преобразование (Single Conversion Mode); 1 – включение автоматического преобразования по срабатыванию триггера (заданного сигнала). Источник автоматического запуска задается битами ADTS[2:0] регистра ADCSRB. Возможны следующие варианты:
- ADSC (ADC Start Conversion, запуск преобразования) — флаг установленный в 1 запускает процесс преобразования.
В режиме Single Conversion (ADATE=0) для запуска каждого нового преобразования этот флаг должен быть установлен в единицу. После завершения преобразования, флаг ADSC сбрасывается в 0.
В режиме Free Running Mode (ADATE=1, ADTS[2:0]=000) этот флаг должен быть установлен в единицу один раз — для запуска первого преобразования, следующие происходят автоматически.
Если установка флага ADSC происходит во время или после разрешения АЦП (ADEN), то перед запрашиваемым преобразованием происходит дополнительное (extended) преобразование, во время которого происходит инициализация АЦП. Сброс флага во время преобразования не оказывает никакого влияния на процесс. - ADIF (ADC Interrupt Flag) — флаг прерывания от компаратора
- ADIE (ADC Interrupt Enable) — разрешение прерывания от компаратора
- ADPS[2:0] (ADC Prescaler Select) — комбинацией битов задается частота преобразования АЦП по отношению к частоте МК. Выбранная частота влияет на точность — чем выше частота, тем ниже точность. АЦП тактируется через выбранный делитель от частоты ядра микроконтроллера. Значения битов:
int pinIn = A0; // Пин аналогового входа
void setup()
{
pinMode(pinIn, INPUT);
ADCSRA |= (1 << ADPS2); //Биту ADPS2 присваиваем единицу - коэффициент деления 16
ADCSRA &= ~ ((1 << ADPS1) | (1 << ADPS0)); //Битам ADPS1 и ADPS0 присваиваем нули
}
void loop()
{
Serial.println(analogRead(pinIn));
delay(1000);
}
Замеры производительности показывают время выполнения функции — 16 мкс (вместо первоначальных 112 мкс):
Вспомним какие биты содержатся в регистре ADMUX:
Замеры производительности показывают время выполнения функции — 16 мкс (вместо первоначальных 112 мкс):
Регистр ADMUX (ADC Multiplexer Selection Register)
Назначение битов регистра ADMUX:
- REFS[1:0](Reference Selection Bit) — биты определяют источник опорного напряжения. Возможные значения:
- ADLAR(ADC Left Adjust Result) — бит отвечающий за порядок записи битов результата в регистры ADCL и ADCH. В зависимости от того значения, которое присвоено биту ADLAR возможны 2 варианта:
- MUX[3:0] (Multiplexer Selection Input) — биты выбора аналогового входа. Значения:
Продолжение следует
Использованы материалы :
https://codius.ru/articles/Arduino_%D1%83%D1%81%D0%BA%D0%BE%D1%80%D1%8F%D0%B5%D0%BC_%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D1%83_%D0%BF%D0%BB%D0%B0%D1%82%D1%8B_%D0%A7%D0%B0%D1%81%D1%82%D1%8C_2_%D0%90%D0%BD%D0%B0%D0%BB%D0%BE%D0%B3%D0%BE_%D1%86%D0%B8%D1%84%D1%80%D0%BE%D0%B2%D0%BE%D0%B9_%D0%BF%D1%80%D0%B5%D0%BE%D0%B1%D1%80%D0%B0%D0%B7%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D1%8C_%D0%90%D0%A6%D0%9F_%D0%B8_analogRead