Лабораторная работа №15. Настройка GPIO для ввода аналогового
15.1 Цель и задачи
Цель работы: изучить правила настройки портов ввода-вывода микроконтроллера ESP32-C3 на реализацию альтернативных функций. Задачи:
- Освоить прием аналогового сигнала и его оцифровку с использованием встроенного аналого-цифрового преобразователя.
- Получить навыки подключения встроенного температурного сенсора
Презентация к блоку "Микроконтроллеры RISC-V"
15.2 Краткие теоретические сведения
ESP32-C3 включает в себя 2 АЦП последовательного приближения, поддерживающие в общей сложности 6 каналов измерения, которые обеспечиваются следующим образом:
- АЦП1 допускает подключение 5 каналов: GPIO0 - GPIO4
- АЦП2 допускает подключение 1 канала: GPIO5.
АЦП ESP32 оцифровывают напряжения в диапазоне от 0 В до Vref. Vref - это опорное напряжение, у разных микросхем Vref различается, среднее значение составляет 1,1 В. Чтобы преобразовать напряжения, превышающие Vref, входные напряжения можно ослабить перед подачей на АЦП. Доступны 4 варианта затухания: чем выше затухание, тем выше может быть измеряемое входное напряжение.
Контроллер поддерживает частоту дискретизации до 12 бит, однократное считывание (single read mode), запускаемое с помощью ПО и непрерывное сканирование (continuous read mode), запускаемое по таймеру. Режим однократного чтения подходит для низкочастотных измерений. Режим непрерывного чтения подходит для постоянно повторяющихся с высокой частотой измерений.
Для настройки однократного считывания с помощью ПО, необходимо:
- Выбрать АЦП1 или АЦП2:
- если установлен APB_SARADC1_ONETIME_SAMPLE, выбран АЦП1;
- если установлен APB_SARADC2_ONETIME_SAMPLE, выбран АЦП2;
- Настроить APB_SARADC_ONETIME_CHANNEL, чтобы выбрать один канал.
- Настроить APB_SARADC_ONETIME_ATTEN, чтобы установить затухание.
- Установить APB_SARADC_ONETIME_START, чтобы начать считывание.
- По окончанию считывания, генерируется прерывание APB_SARADC_ADCX_DONE_INT_RAW, которое может использоваться для считывания данных из APB_SARADC_ADCX_DATA. X может принимать значение 1:(АЦП1), или 2:(АЦП2).
Для настройки непрерывного сканирования, нужно выполнить следующие действия:
- Установить APB_SARADC_TIMER_TARGET для выбора DIG АЦП в качестве цели для запуска таймера.
- Установить APB_SARADC_TIMER_EN для запуска таймера.
- Когда время таймера истекает, он заставляет DIG ADC FSM начать измерения в соответствии с таблицей шаблонов.
- Значения автоматически помещаются в память с помощью DMA (прямой доступ в память). Прерывание генерируется после завершения считывания.
В контроллер ESP32-C3 встроен датчик температуры, позволяющий отслеживать изменения температуры внутри чипа. К нему можно обратиться программно для получения текущих значений. В зависимости от температуры окружающей среды настраивается диапазон измерений и смещение, которое позволяет повысить точность датчика.
Получить данные с датчика температуры можно следующим образом:
- Установить APB_SARADC_TSENS_PU, чтобы запустить XPD_SAR, а затем включить датчик температуры.
- Установить SYSTEM_TSENS_CLK_EN, чтобы запустить тактовый сигнал датчика.
- Ждать тактов APB_SARADC_TSENS_XPD_WAIT, пока не будет выполнен сброс датчика температуры. После этого начнется измерение температуры;
- Через некоторое время данные можно будет считать из APB_SARADC_TSENS_OUT. Для получения значений в градусах Цельсия, нужно использовать формулу T(°C) = 0.4386 ? VALUE-27.88 ? offset-20.52, где значение offset определяется по таблице 15.1.
Диапазон измерений, °C | Смещение, °C |
---|---|
50 ~ 125 | -2 |
20 ~ 100 | -1 |
10 ~ 80 | 0 |
-30 ~ 50 | 1 |
-40 ~ 20 | 2 |
Настройка регистров осуществляется с использованием функций API.
Для подключения контакта к АЦП1 последовательно вызываются две функции:
- adc1_config_width (adc_bits_width_t width_bit) - настройка разрешения канала, width_bit - число бит. Для ESP32-C3 доступно 12-ти битное разрешение.
- adc1_config_channel_atten (adc1_channel_t channel, adc_atten_t atten) - выбор канала (channel) и уровня ослабления (atten). Благодаря этому можно изменять верхнюю границу измеряемого диапазона для увеличения точности значений.
Доступные значения adc_atten_t:
- ADC_ATTEN_DB_0 (или значение 0) 0 mV ~ 750 mV
- ADC_ATTEN_DB_2_5 (1) 0 mV ~ 1050 mV
- ADC_ATTEN_DB_6 (2) 0 mV ~ 1300 mV
- ADC_ATTEN_DB_11 (3) 0 mV ~ 2500 mV
Для одиночного считывания данных вызывается следующая функция adc1_get_raw(adc1_channel_t channel), в которой указывается номер канала, выбранный в предыдущей функции. На выходе получаем целое значение val в диапазоне от 0 до (2**width_bit-1)
При необходимости получить значение напряжения можно использовать формулу mVolts = val*(Vref/4095), Vref - верхнее значение выбранного диапазона adc_atten.
Для получения данных со встроенного датчика температуры выполняются следующие действия:
- После создания пустого объекта типа temperature_sensor_handle_t необходимо определить, в каких условиях датчик будет работать, и задать их верхнюю и нижнюю температурные границы.
- Структуру temperature_sensor_config_t можно задать функцией TEMPERATURE_SENSOR_CONFIG_DEFAULT (min, max), где min и max - границы температуры. Ссылка на эту структуру вместе с указателем на объект передается в функцию temperature_sensor_install(). Далее для начала работы с датчиком вызывается temperature_sensor_enable(), в которую также нужно передать указатель на созданный temperature_sensor_handle_t.
- Для получения значений температуры используется функция temperature_sensor_get_celsius(temperature_sensor_handle_t tsens, float *out_celsius) , в out_celsius будет храниться значение в градусах Цельсия.
15.3 Задания к лабораторной работе
Подготовить программу, обеспечивающую прием аналогового сигнала, его оцифровку и использование полученного цифрового кода для управления внешним элементом. С использованием беспаечной макетной платы собрать схему, подключив к аналоговому входу переменный резистор, а к цифровому выходу - элемент, управляемый цифровым сигналом.
- Реализовать плавное изменение яркости светодиода в зависимости от значения сопротивления переменного резистора.
- Реализовать плавное изменение частоты звучания зуммера в зависимости от значения сопротивления переменного резистора.
- Реализовать вывод на экран компьютера оцифрованных значений сигнала, получаемого от переменного резистора.
15.3.1 Описание последовательности выполнения работы
Для выполнения работы необходимо иметь беспаечную макетную плату для многократного макетирования; одножильные провода-перемычки с контактами, допускающими коммутацию с установленными на макетной плате элементами; светодиоды; зуммер.
- Изучить настройки портов GPIO для подключения аналогового сигнала.
- Для выполнения работы рекомендуется воспользоваться шаблоном проекта ADC. Подготовить текст основной программы в соответствии с заданием, используя шаблон, приведенный в п.15.2.3. Доработать программу шаблона таким образом, чтобы входной аналоговый сигнал преобразовывался в цифровой эквивалент, который, в свою очередь, использовался для управления внешним элементом (зуммером, светодиодом).
- Используя беспаечную макетную плату, подключить к аналоговому входу резистор с переменным напряжением, а к цифровому выходу элемент, управляемый от цифрового выхода.
15.3.2 Пример выполнения задания на защиту
#include <stdio.h> #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "driver/adc.h" #include "esp_adc_cal.h" #include "driver/temperature_sensor.h" void app_main(void){ //подключаемся к каналу АЦП adc1_config_width(12); adc1_config_channel_atten(ADC1_CHANNEL_2, ADC_ATTEN_DB_11); //подключаем встроенный датчик температуры temperature_sensor_handle_t temp_sensor = NULL; temperature_sensor_config_t temp_sensor_config = TEMPERATURE_SENSOR_CONFIG_DEFAULT(10, 50); ESP_ERROR_CHECK(temperature_sensor_install(&temp_sensor_config, &temp_sensor)); ESP_ERROR_CHECK(temperature_sensor_enable(temp_sensor)); float tsens_value; while(1){ //получение значений температуры с внешнего датчика int val = adc1_get_raw(ADC1_CHANNEL_2); float voltage = val*(2500.0/4096.0); float temp = (voltage-500)/10.0; //для датчика TMP36 printf("Temperature in the room is %.02f ? \n", temp); //получение значений температуры со встроенного датчика ESP_ERROR_CHECK(temperature_sensor_get_celsius(temp_sensor, &tsens_value)); printf("Temperature value inside the chip is %.02f ?\n\n", tsens_value); vTaskDelay(2000/portTICK_PERIOD_MS); } }
15.4 Вопросы для контроля
- Поясните порядок настройки аналого-цифрового преобразователя.
- Поясните режимы работы АЦП, для каких задач они могут быть использованы?
- С помощью каких настроек можно регулировать разрешающую способность АЦП?