Напряжение на аналоговом входе (холостое)

Добрый день, извините возможно за глупый вопрос, есть плата UNO R3, на A0 - приходит 0-5В, на цифровом 2 висит датчик холла, написал код чтобы данные с А0 и D2 раз в секунду записывались на SD-карту. Для проверки взял ESP32 и пустил с нее имитацию холла, и постоянный выход 2В, собрал все, но возникла проблема на А0 как я понял присутствует напряжение в простое без подключеной ESP, напряжение не постоянное а меняющееся с 2 до 4.2В При подключении ЕСП напряжение устанавливается в районе 3.442 - 3.447В но иногда появляется ноль. Мультиметром на выходе с ЕСП 32 я вижу 1.96. Данные с порта прикрепляю (слева с подключенной ЕСП, справа без).


Я начинающий в теме ардуино, скажу честно этот проект начал делать не я, у нас небольшая государственная техническая секция по картингу, в рамках применения компьютерных технологий, один из участников секции предложил сделать регистратор данных на ардуино, в его задачу входит получение аналогового сигнала 0-5В с контроллера лямбда-зонда и получение оборотов с датчика ХХ, все это записывать на СД-карту, для дальнейшего построения графика в Excel. Он начал реализовывать задачу, но в дальнейшем проект застопорился, и парень ушел с секции, я как тренер решил продолжить это.

С чем может быть связано такое поведение на аналоговом пине? нужны какие то фильтры?

Очевидно нет подтяжки входа. Вход очень чувствителен к любым возмущениям.
Сопротивлением 10-100 кОм вход притянуть к земле, дараллельно ёмкость керамическую 0.01-1 мкФ.

Согласен, и тут я больше за 100 кОм, чем за 10 кОм.

Нахуа?

Данные раз в секунду, то есть статичные, постоянные, а ёмкость на всякий случай, вдруг рядом помеха пойдёт? Я бы поставил, хоть и не так это важно.
Хотя…непонятно что там источником 0-5в будет. Скорей всего вообще не надо ничего мудрить. Проблема-то при неподключеном входе.
И вообще, чем больше конденсаторов, тем ты круче в глазах неспециалистов😄

1 лайк

Емкость нужна. Причем, в гораздо большей степени, чем сопротивление.
Другое дело, пока не опубликована схема, все это не более, чем досужие размышления.

ТС, если задаешь вопрос, первое, что нужно сделать, - опубликовать скетч и схему.

1 лайк

возьми ADS1115, там 4-ре канала, получишь реальную картину, у ESP32 не важный ADC, измеряет от 0.1 вольта, для измерения больших напряжений до 2.5 вольта включается внутренний делитель

Attenuation Measurable input voltage range

ADC_ATTEN_DB_0  100 mV ~ 950 mV
ADC_ATTEN_DB_2_5 100 mV ~ 1250 mV
ADC_ATTEN_DB_6  150 mV ~ 1750 mV
ADC_ATTEN_DB_11 150 mV ~ 2450 mV
1 лайк

фнч по входу ацп всегда желателен, какую частоту среза ему задать это уже по задаче.

есть такая очевидность, не поставить заложенную в плату деталь проще, чем поставить не заложенную.


Для правильной работы ацп нужно учитывать выходное сопротивление источника - фнч - входное сопротивление ацп, т.к. резистор фнч образует с входным сопротивлением ацп делитель.
Резистор и конденсатор фнч следует устанавливать непосредственно на ноге ацп.

Спасибо, вот так?

Пардон, сейчас скетч прикреплю.

У нас есть датчик кислорода, к нему есть контроллер, который выводит показания с датчика на дисплей, но в контроллере нет функции записи лога, предусмотрен аналоговый выход 0-5В, где 0 это 10AFR (Air Fuel ratio) т.е бедная смесь, а 5 это 20AFR богатая смесь. Контроллер сделан на Open Source, к сожалению что и как в нем устроено я не могу сказать я не настолько продвинут в электронике, могу прикрепить архив с файлами для изготовления. К сожалению больше ничего сказать про него не могу.

#include <SPI.h>
#include <SD.h>

// Определяем пины для входов
const int analogPin = A0;  // Пин для аналогового сигнала
const int digitalPin = 2;  // Пин для цифрового сигнала
const int chipSelect = 10;  // Пин выбора чипа для модуля SD

// Переменные для расчета RPM
volatile unsigned long lastflash = 0;
float RPM = 0;

File dataFile;

void setup() {
  // Настраиваем скорость передачи данных для монитор порта
  Serial.begin(9600);
  
  // Устанавливаем режимы пинов
  pinMode(digitalPin, INPUT);  // Устанавливаем цифровой пин как вход
  pinMode(chipSelect, OUTPUT);  // Устанавливаем пин выбора чипа как выход
  
  // Инициализируем значение последнего времени
  lastflash = micros();
  
  // Инициализация модуля SD
  if (!SD.begin(chipSelect)) {
    Serial.println("Ошибка инициализации SD");
    return;
  }
  
  // Создание или открытие файла для записи
  dataFile = SD.open("data.txt", FILE_WRITE);
  if (dataFile) {
    dataFile.println("Analog Voltage, RPM");
    dataFile.close();
  } else {
    Serial.println("Ошибка открытия файла для записи");
  }
}

void loop() {
  // Читаем значение аналогового сигнала
  int analogValue = analogRead(analogPin);
  
  // Преобразуем значение аналогового сигнала в вольты
  float voltage = analogValue * (5.0 / 1024.0);
  
  // Читаем значение цифрового сигнала
  int digitalValue = digitalRead(digitalPin);
  
  // Если цифровой сигнал изменился, вызываем функцию sens()
  if (digitalValue == HIGH && (micros() - lastflash) > 1000) {  // Фильтр от дребезга контактов
    sens();  // Вызов функции для расчета RPM
  }
  
  // Если прошло больше секунды с последнего импульса, считаем что RPM = 0
  if ((micros() - lastflash) > 1000000) {
    RPM = 0;
  }

  // Выводим значения в монитор порта
  Serial.print("Analog Voltage: ");
  Serial.print(voltage, 3);  // Значение в вольтах с тремя знаками после запятой
  
  Serial.print(" V  RPM: ");
  Serial.println(RPM);
  
  // Открываем файл для записи данных
  dataFile = SD.open("data.txt", FILE_WRITE);
  if (dataFile) {
    dataFile.print(voltage, 3);
    dataFile.print(", ");
    dataFile.println(RPM);
    dataFile.close();  // Закрываем файл после записи
  } else {
    Serial.println("Ошибка записи в файл");
  }
  
  // Добавляем задержку, чтобы не перегружать монитор порта
  delay(1000);
}

void sens() {
  // Расчет RPM
  RPM = 60.0 / ((float)(micros() - lastflash) / 1000000.0);  // Расчет
  lastflash = micros();  // Запомнить время последнего оборота
}

Использую плату UNO + Datalogger Shield.


:+1: :stuck_out_tongue_winking_eye:

Я бы подал испытательное напряжение через потенциометр…

Смущает она что-то. Ещё и float.
60/(x/10000000)= 60000000/x.
Конечно, лучше бы на таймере измерять, ну да ладно, “Работает? Не трогай!”)
Либо не micros, а millis, либо значение micros сократить до uint16, точности должно хватить.
А то вычисления очень “тяжёлые”.
@ЕвгенийП , хороший вопрос задам, сам сталкивался с необходимостью деления. Пытался как-то сократить вычисления(жёсткое ограничение времени было), но так и не обошёл деление. Есть ли способ вообще обойти его? Ну может там какие хитроумные битовые операции?

Эту часть взяли из готового примера тахометра у Алексгайвера если что, сам датчик холла еще не подключал, попробую в ближайшие пару дней подключить, и найти магнит для испытания. На простом тахометре оно работало, мы использовали его на нано.

Он никогда не славился оптимизацией кода))) Тяп-ляп и готово)

посчитать импульсы за секунду и умножить на 60

Та нее, имею ввиду прям вот не меняя метода. Например есть период некий, а надо частоту, то есть 1/x.

В приведенном примере используется числа с плавающей точкой. В этом случае, естественно, деление на 1000000.0 элементарно заменяется умножением на 0.000001.
Для целых чисел можно умножить на 4295 и сдвинуть вправо. (либо подобрать другую пару множителя и величины сдвига в зависимости от требований к времени выполнения, точности и разрядности операндов).
Помнится, я заменял деление x/7 формулой x/8+x/64.

1 лайк

Плавающую точку можно вообще битово сдвигать? Странно, я об этом не думал и не проверял. И не помню можно ли сдвигать 4х байтное число или только 2х байтное. На досуге проверю разные варианты.

Сдвигать можно всё. Вопрос – что при этом получится в результате.

1 лайк

Какаха?))))
Да понял уже что нельзя. Мантисса, бит знака низя трогать скопом. Если только отдельно и со знанием, но зачем? Их надо всячески избегать. Видимо поэтому плохо с ними знаком- избегаю😄