Взаимодействие датчика кислорода Figaro KE25 с Arduino Uno
Я пытался подключить датчик кислорода на свинцовом топливном элементе Figaro KE25 2 к Arduino Uno. Я не получаю требуемый вывод на последовательном мониторе для обычного воздуха (концентрация кислорода 19%).
Я приложил скетч, который я напечатал, выход, который я получил на последовательном мониторе, выход (мВ) в зависимости от концентрации кислорода (% ) график датчика Figaro KE25, который я получил из технического описания, химические реакции, управляющие работой датчика, схема цепи, которую я использовал, и конструкция датчика.
В этом вопросе; Сначала я объясню датчик, затем схему, затем скетч и, наконец, проблему с выходом.
В электронике анод — это положительный электрод, а катод — отрицательный электрод. В электрохимии анод — это отрицательный электрод, а катод — это положительный электрод. . Проверьте изображение конструкции датчика, которое я предоставил, полученное из таблицы данных.[![изображение конструкции датчика][1]][1] Полный технический паспорт
Катод, то есть положительный электрод, является чувствительным электродом (здесь потребляется кислород и генерируется электрический ток). Поскольку датчик (топливный элемент) генерирует ток, питание датчика не требуется. Проверьте представленное изображение химических реакций (полученное из полного технического паспорта датчика). Технический паспорт
Рассматриваемый датчик представляет собой датчик аналогового типа напряжения. Помня об этом и обо всем, что я упомянул выше, я построил следующую схему с помощью Arduino Uno. Обратите внимание на картинку, которую я выложил. Я подключил катод (чувствительный положительный электрод красного цвета) к аналоговому контакту A0 Arduino и анод (отрицательный электрод) к земле Arduino.
Скетч, который я использовал, выглядит следующим образом:
/*the analog pin of the alcohol sensor goes into analog pin A0 of the
Arduino*/
void setup()
{
Serial.begin(9600); // устанавливает скорость передачи данных
}
void loop()
{
float v1;
float oxy = 0.0;
float v2 = 0.0;
pinMode(A0,INPUT_PULLUP);
/*To make sure that reading is zero when the circuit is open*/
v1 = analogRead(A0);
/*reads the analog value from the Oxygen gas sensor and this value can
be anywhere from 0 to 1023 (10 bit ADC used in Arduino Uno)*/
if(v1>900) //Чтобы убедиться, что показания равны нулю, когда цепь разомкнута
{
v1=0;
}
v2 = (v1*3000)/992;
/*The above line calculates the output of the sensor in mV using the
fact that a HIGH reading in an input pin of an Arduino Uno board is
equivalent to a voltage of 3V or higher. When I displayed just 'v1',
the lowest of the high values I got was 992. So I equated it to 3V
(3000mV) and used the unitary method to find out what a non-HIGH v1
value would be in terms of mV.*/
oxy = v2/0.6;
/*The above line calculates the Oxygen concentration from the mV output
of the sensor using the output(mV) vs concentration(%) graph from the
sensor's datasheet. The graph is a straight line passing through (0,0)
and hence the governing equation is of the form y = m * x. Where 'y' is
'v2' and 'x' is Oxygen conc. in %.*/
Serial.print("Oxygen value: ");
Serial.print(v1);
Serial.print(" ");
Serial.print(v2);
Serial.print("mV ");
Serial.print(oxy);//выводит значение кислорода
Serial.println("%");
delay(1000);
}
График выхода (мВ) и концентрации кислорода (%), приведенный в таблице данных, показан ниже. Следует учитывать прямую линию, обозначенную как «KE25». Информация о продукте (техническое описание)
вывод, который я получил на последовательном мониторе, выглядит следующим образом:
Такое высокое напряжение от датчика невозможно. Мое выходное чтение вообще невозможно. Где я допустил ошибку и как ее исправить?
Обновление 1: я изменил строку
pinMode(A0,INPUT_PULLUP)
наpinMode(A0,INPUT)
. Теперь я получаю разумные значения на своем последовательном мониторе. Однако я также получаю много выходных значений «0» (много). Я также получаю много случайных значений (много). Мне нужно больше информации о том, как подключить кислородный датчик типа топливного элемента с помощью Arduino Uno с точки зрения того, как получить правильное значение напряжения на таком датчике. Я не нашел вопросов по электрохимическому взаимодействию с кислородным датчиком типа топливного элемента. Все заданные вопросы касаются датчиков, которым требуется источник питания. В случае датчиков кислорода на топливных элементах ток генерируется при обнаружении кислорода, и, следовательно, источник питания не требуется. Кроме того, если кто-то занимается электрохимией, как мне проверить выходное напряжение датчика кислорода на топливном элементе с помощью вольтметра? Я использую вольтметр постоянного тока или вольтметр переменного тока?Обновление 2. Я внес изменения в код на основе предложений @EdgarB. Результат, который я получаю сейчас, лучше, но все же неправильный. Я проверил, работают ли датчики, которые я использую, с помощью мультиметра (я подтвердил, что метод, который я использую, верен, и это так), и они работают. Значения кислорода, которые я получаю сейчас, все еще очень низкие: 6-8%. Я должен получить: 19-21%. Я использовал опорное напряжение 600 мВ и изменил код.
Измененный код:
void setup()
{
Serial.begin(9600);//устанавливает скорость передачи
analogReference(INTERNAL);
}
void loop()
{
const float A_REF = 0.6e3;
const float Scalc = (1/0.6);
float v1;
float oxy = 0.0;
float v2 = 0.0;
pinMode(A0, INPUT);
v1 = analogRead(A0);
v2 = (v1 * A_REF) / 1024;
oxy = v2 * Scalc;
Serial.print("Oxygen value: ");
Serial.print(v1);
Serial.print(" ");
Serial.print(v2,4);
Serial.print("mV ");
Serial.print(oxy,4);//выводит значение кислорода
Serial.println("%");
delay(1000);
}
Вывод:
@athindra pavan, 👍0
Обсуждение3 ответа
Лучший ответ:
Ваша проблема связана с тем, что внутренний подтягивающий резистор для A0 включен.
Датчик представляет собой генератор тока со встроенным нагрузочным резистором (плюс термистор) для преобразования тока в напряжение. Добавляя подтягивающий резистор, вы превращаете его в делитель напряжения на 5 В с небольшим током, подаваемым в центральный узел:
Поскольку в техническом описании не указано ни сопротивление нагрузки, ни ток источника, я составил некоторые значения для демонстрации.
Если мы возьмем только источник тока и сопротивление нагрузки RL+RT и рассчитаем падение напряжения на них, мы получим:
V=R×I = 5000 × 0.00001 = 50mV
Это разумное значение. Это много кислорода, но это потому, что это выдуманные значения.
Каково будет напряжение с добавленным подтягивающим резистором? Ну, здесь все становится немного сложнее. В такие моменты проще просто смоделировать схему в чем-то вроде симулятора фальстада, и я могу сказать вам, что это 757,1 мВ (Если вы хотите научиться выполнять такой анализ цепей вручную, вам следует изучить теория суперпозиции).
Грандиозное изменение.
Очевидно, что вы не видите настолько большого изменения, и это потому, что подтягивающий резистор больше, чем просто резистор. Есть много других факторов, влияющих на показания, в том числе выходное сопротивление сети, а также остальная часть внутренней схемы АЦП.
Достаточно сказать, что добавление подтягивающего резистора — плохая идея при использовании АЦП.
Но вы хотите оставить подтягивающий резистор, чтобы знать, подключен датчик или нет. Это не проблема. Просто включите и выключите его по желанию:
pinMode(A0, INPUT_PULLUP);
delay(1);
bool connected = analogRead(A0) < 900;
if (connected) {
pinMode(A0, INPUT);
delay(1);
v1 = analogRead(A0);
}
Рекомендуется подождать некоторое время после изменения состояния подтягивающего резистора перед чтением из АЦП, чтобы уменьшить электрический шум, улавливаемый АЦП — отсюда и вызовы delay(1)
.
Ваш расчет v2 неверен.
v2 = (v1 * 3000) / 992;
Максимальное значение v1 равно 1023, что соответствует 5v (не 3v). Итак, чтобы рассчитать напряжение v2, я думаю, вы должны сделать:
v2 = (v1 / 1023) * 5000;
Но это еще больше улучшит ваши расчеты!
Максимальное напряжение на контакте, настроенном как ВЫХОД, составляет 5 В на плате Arduino Uno 5 В. Однако на той же плате, если контакт сконфигурирован как ВХОД, то напряжение на контакте составляет 3 В или выше. Проверьте [https://www.arduino.cc/reference/en/language/variables/constants/constants/], @athindra pavan
Я просто читал, что сказал AnalogInput()., @Code Gorilla
Здесь у вас три разные проблемы:
- неправильное использование подтягивающего резистора
- неправильная интерпретация аналогового показания
- слишком слабый входной сигнал
Подтягивающий резистор
Маженко уже рассказал о первом выпуске, дав очень хорошие советы.
Интерпретация аналоговых показаний
Code Gorilla уже объяснила вторую проблему. Однако, поскольку вы делаете кажется, не понял, я добавлю сюда свое мнение.
Формула для преобразования аналоговых показаний в фактическое напряжение
напряжение = показание × Analog_reference ÷ 1024.
Да, это 1024, а не часто встречающееся (но ошибочное) 1023. См. паспорт производителя, который является единственным официальным ссылка. Все равно особой разницы нет. Основная проблема заключается в аналоговое опорное напряжение, которое в конфигурации по умолчанию является такое же, как напряжение питания Arduino, т. е. 5 В.
В комментарии вы написали:
если контакт настроен как ВХОД, то напряжение на контакте составляет 3 В или выше
Это полная ерунда. Напряжение на входном контакте любое
напряжение обеспечивается цепью, подключенной к этому контакту. Если вы
на самом деле означает пороговое напряжение для вывода HIGH
, ну,
этот порог обычно составляет 2,6 В (см.
характеристики» в даташите), но точного значения нет
гарантировано. Число, которое вы цитируете, является «наименьшим значением, где контакт
гарантированно будет прочитан как высокий». Другими словами, порог напряжения
может быть ниже 3 В, но не выше.
И все это совершенно не имеет к вам никакого отношения. Входные пороги
особенность схемы цифрового ввода, прикрепленной к контакту. Эта схема
отвечает за определение того, является ли контакт LOW
или HIGH
, когда вы
digitalRead()
это. Но вас не волнует цифровое значение: вы
использование вывода в качестве аналогового входа. Преобразователь АЦП другой.
схема, которая не имеет абсолютно никакого отношения к цифровому входу.
Вы даже можете отключить цифровой вход вывода и по-прежнему использовать АЦП.
Низкий уровень сигнала
Согласно приведенному вами графику, датчик должен выводить 12,6 мВ в обычном воздухе (21% O2). Это о 2,58 шага АЦП. Таким образом, вы ожидаете, что показания будут колебаться между цифровые значения 2 и 3. Это действительно очень мало для вашего АЦП.
Простым способом решения этой проблемы является изменение аналогового эталона.
По умолчанию используется 5 В, но вы можете переключить его на внутренний
1.1 V, что значительно увеличит
ваше решение: в setup()
вызовите
analogReference(INTERNAL);
Затем вы можете рассчитать уровень кислорода следующим образом:
const float A_REF = 1.1e3; // аналоговое задание = 1100 мВ
const float SENSOR_CAL = 1 / 0.6; // калибровка: %(O2) / мВ
void loop()
{
int reading = analogRead(A0);
float voltage = reading * (A_REF / 1024);
float oxygen = voltage * SENSOR_CAL;
// ...
}
Еще один способ уменьшить слабый сигнал — усреднить чтения. Это может сделать ваше эффективное разрешение лучше, чем необработанное Разрешение АЦП.
Смещение АЦП
Формула
напряжение = показание × Analog_reference ÷ 1024
применяется только к идеальному АЦП. На практике любой АЦП имеет некоторую погрешность смещения. и получить ошибку. Принимая их во внимание, формула принимает вид:
напряжение = (показание + ошибка смещения) × аналоговая_опорность ÷ (1024 + ошибка_усиления)
Во многих случаях эти ошибки слишком малы, чтобы обращать на них внимание. Однако, поскольку вы работаете вблизи предела разрешения вашего АЦП, ошибка смещения может быть важной заботой. Ошибка усиления здесь не проблема, так что вы можете забудьте об этом.
Если у вас есть вольтметр, вы можете легко определить погрешность смещения: измерьте низкое напряжение, например, от вашего датчика, с помощью обоих вольтметр и АЦП. В идеале вы должны усреднять многие показания АЦП, чтобы получить лучшее разрешение. Из измерения вольтметра вы вычисляете среднее значение, которое вы ожидаете от вашего АЦП, то вы получите
offset_error = ожидаемое_чтение_ADC — фактическое_чтение_ADC
Затем вы используете это измеренное смещение для корректировки показаний:
const float offset_error = ...; // измеряется вольтметром
void loop()
{
int reading = analogRead(A0);
float voltage = (reading + offset_error) * (A_REF / 1024);
// ...
}
Я имел в виду, что если вывод сконфигурирован как ВХОД и имеет ВЫСОКОЕ значение, то напряжение на этом выводе составляет 3 В или выше. Я прочитаю остальную часть вашего ответа и скоро обновлю статус., @athindra pavan
@athindrapavan: Понял, что вы имеете в виду, но: 1. Это неправильно (вывод может читаться как «HIGH» даже при 2,2 В) 2. Это не имеет отношения к аналоговому чтению., @Edgar Bonet
Прежде всего, спасибо! Это помогло получить более качественный и точный результат. Кроме того, теперь я лучше понимаю присваиваемые константы. Но я все еще получаю неправильный результат с точки зрения диапазона процентных значений кислорода, который я должен получать. Я получаю около 6-8% кислорода, что все еще слишком мало. В обычном воздухе он должен быть 19-21%. Я проверил, работают ли датчики, которые я использую, с помощью мультиметра, и они работают. Я обновлю вопрос с измененным кодом и выводом, который я получу через некоторое время. Пожалуйста, проверьте это., @athindra pavan
@athindrapavan: 1. Внутреннее аналоговое опорное напряжение составляет 1,1 В, а не 600 мВ. Вы не можете просто составить число и ожидать, что это сработает. 2. Вы также можете столкнуться с ошибкой смещения АЦП. Смотрите измененный ответ., @Edgar Bonet
@ EdgarB Ваш ответ имел большой смысл, и теперь установка работает. Зависит ли датчик значения ошибки смещения? То есть, если я использую 2 новых датчика Figaro KE-25, то будет ли это вызывать ошибку в одном из 2-х датчиков в зависимости от того, какой из них я использовал для расчета ошибки смещения?, @athindra pavan
@athindrapavan: Нет, ошибка смещения присуща АЦП. Это не должно зависеть от датчика. Однако это может зависеть от того, используете ли вы analogReference(DEFAULT)
(т.е. Vcc) analogReference(INTERNAL)
(т.е. 1,1 В)., @Edgar Bonet
Итак, поскольку я использовал последний, он встроен в АЦП? Кроме того, огромное спасибо! Ваш ответ был очень подробным и очень помог., @athindra pavan
- Как использовать SPI на Arduino?
- Как решить проблему «avrdude: stk500_recv(): programmer is not responding»?
- Как создать несколько запущенных потоков?
- Как подключиться к Arduino с помощью WiFi?
- avrdude ser_open() can't set com-state
- Как узнать частоту дискретизации?
- Что такое Serial.begin(9600)?
- Я закирпичил свой Arduino Uno? Проблемы с загрузкой скетчей на плату
Если вы удалите
pinMode (A0, INPUT_PULLUP);
это улучшит показания?, @MajenkoПрочтите эту страницу: https://www.arduino.cc/en/Tutorial/AnalogInputPins — особенно часть, озаглавленную «Подтягивающие резисторы»., @Majenko
@Majenko Спасибо! Это действительно помогло. Я изменил
pinMode(A0,INPUT_PULLUP);
наpinMode(A0,INPUT);
Я прочитал эту страницу перед тем, как напечатать свой скетч, но я не обратил особого внимания на строку, которая гласила: "Осторожно ! однако включение подтягивания повлияет на значения, сообщаемые с помощью AnalogRead()». Это потому, что за короткий промежуток времени, например, 1000 мс, недостаточно времени, чтобы напряжение упало до низкого уровня, а затем снова поднялось до правильного входного сигнала, подаваемого датчиком?, @athindra pavan