Взаимодействие датчика кислорода 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». O/P(мВ) и концентрация O2(%) Информация о продукте (техническое описание)

вывод, который я получил на последовательном мониторе, выглядит следующим образом: SerialMonitor

Такое высокое напряжение от датчика невозможно. Мое выходное чтение вообще невозможно. Где я допустил ошибку и как ее исправить?

Обновление 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);
 }

Вывод: Вывод

, 👍0

Обсуждение

Если вы удалите 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


3 ответа


Лучший ответ:

1

Ваша проблема связана с тем, что внутренний подтягивающий резистор для 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).

,

0

Ваш расчет 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


0

Здесь у вас три разные проблемы:

  1. неправильное использование подтягивающего резистора
  2. неправильная интерпретация аналогового показания
  3. слишком слабый входной сигнал

Подтягивающий резистор

Маженко уже рассказал о первом выпуске, дав очень хорошие советы.

Интерпретация аналоговых показаний

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