Датчик направления ветра CYC-FX1-KV-A1 (производства китайской компании WUHAN CHENYUN Technology Co., Ltd) представляет собой свободно поворачивающийся флюгер с аналоговым токовым выходом.

Питается датчик от постоянного напряжения DC 9V .. 30V, и подключается тремя проводами:
Красный DC 9V .. 30V Желтый Выходной сигнал Черный Общий провод, GND
Ток на выходе датчика пропорционален углу поворота флюгера: 4 .. 20 мА в зависимости от угла поворота 0 .. 359 градусов. От угла поворота также зависит потребляемый ток: например, при напряжении питания 12V максимальный потребляемый ток составит около 26 мА.
Чтобы подключить выход датчика к АЦП микроконтроллера, его выход нужно нагрузить на постоянный резистор. В случае АЦП микроконтроллера ESP32-C3 номинал этого резистора должен быть 120 Ом, тогда максимальное напряжение на входе АЦП получится 2.4V, что при ослаблении на входе 11 db как раз будет попадать в диапазон 0 .. 2.5V (см. [1]).
Схема подключения датчика к каналу A0 (GPIO0) микроконтроллера ESP32-C3:

Код опроса датчика CYC-FX1-KV-A1:
#include "esp_log.h" #include "esp_err.h" #include "esp_adc/adc_oneshot.h" #include "adcapp.h" #include "pins.h" #include "task_priorities.h" #include "nvsapp.h"
static const char *TAG = "adcapp"; static adc_oneshot_unit_handle_t adc1_handle; // Дескриптор АЦП bool adc_test_enabled = false;
// Функция считывания сырого значения ADC из входа GPIO0
esp_err_t get_adc_gpio0_raw(int *raw)
{ esp_err_t ret; do { adc_oneshot_unit_init_cfg_t init_config1 = { .unit_id = ADC_UNIT_1, // Используем модуль ADC1 .ulp_mode = ADC_ULP_MODE_DISABLE, // Отключаем режим ULP (для // простых задач не нужен) }; // Конфигурация канала АЦП adc_oneshot_chan_cfg_t config = { .atten = ADC_ATTEN_DB_12, // Ослабление 12 дБ (диапазон 0 мВ - 2500 мВ) .bitwidth = ADC_BITWIDTH_DEFAULT, // Используем разрядность по умолчанию (12 бит) }; // Инициализируем блок АЦП ret = adc_oneshot_new_unit(&init_config1, &adc1_handle); if (ret != ESP_OK) { ESP_LOGE(TAG, "Ошибка инициализации модуля АЦП: %s", esp_err_to_name(ret)); break; }
// Настраиваем конкретный канал (ADC_CHANNEL_0 на ADC1) ret = adc_oneshot_config_channel(adc1_handle, ADC_CHANNEL_0, &config); if (ret != ESP_OK) { ESP_LOGE(TAG, "Ошибка настройки канала: %s", esp_err_to_name(ret)); break; }
ESP_LOGI(TAG, "АЦП инициализирован. Начинаем чтение с ADC1_CHANNEL_0..."); // Производим одиночное измерение ret = adc_oneshot_read(adc1_handle, ADC_CHANNEL_0, raw); if (ret != ESP_OK) { ESP_LOGE(TAG, "Ошибка чтения АЦП: %s", esp_err_to_name(ret)); } adc_oneshot_del_unit(adc1_handle); }while(false);
return ret;
}
static void adcTask(void *pvParameters)
{ int imin, imax; imin = 65535; imax = 0; printf("ADC test started\n"); while(adc_test_enabled) { int raw; esp_err_t ret = get_adc_gpio0_raw(&raw); if (ret == ESP_OK) { ESP_LOGI(TAG, "ADC1_CHANNEL_0: %d", raw); if (raw < imin) imin = raw; if (raw > imax) imax = raw; uint16_t deg = map_to_degree_float(raw, a0min, a0max); //uint16_t deg = map_to_degree_optimized(raw, a0min, a0max); printf("\r%4d a0min=%4d a0max=%4d град=%3u", raw, imin, imax, deg); } vTaskDelay(pdMS_TO_TICKS(100)); } vTaskDelete(NULL);
}
void adc_test_start(void)
{ adc_test_enabled = true; esp_log_level_set("gpio", ESP_LOG_ERROR); // Только ошибки esp_log_level_set("adcapp", ESP_LOG_ERROR); // Только ошибки xTaskCreate(&adcTask, "adcTask", 4096, NULL, PRIORITY_ADC_TEST, NULL);
}
void adc_test_stop(void)
{ adc_test_enabled = false;
}
В этом примере применен драйвер режима однократного чтения АЦП (one shot mode). Сырое значение, считываемое с АЦП, масштабируется в значения 0° .. 360° с помощью функции map_to_degree_float. Значения a0min и a0max соответствуют значениям, считанным с канала A0 АЦП при токе 4 мА и 20 мА соответственно.
uint16_t map_to_degree_float(uint16_t value, uint16_t a0min, uint16_t a0max) {
if (value <= a0min) return 0;
if (value >= a0max) return 359;
float result = (float)(value - a0min) * 359.0f / (float)(a0max - a0min);
return (uint16_t)(result + 0.5f); // Округление до ближайшего
}
[Ссылки]
1. ESP32-C3: работа со встроенным АЦП. |