Помогите использовать термистор с esp8266.

Итак, я пытаюсь использовать это термистор для измерения температуры, и этот код ниже всегда устанавливает одно и то же значение (2147483647). Я использовал это руководство для подключения и кодирования. Я не думаю, что проблема в проводке, но думаю, что проблема где-то в моем коде или, возможно, я использую термистор неправильного типа? Я что-то упускаю? Любая помощь приветствуется.

Я использую только резистор номиналом 1 кОм последовательно с термистором, но не думаю, что это будет проблемой, верно?

Изменить: я должен был упомянуть, что использую adafruit huzzah esp8266, поэтому здесь есть несколько контактов.

#include <DHT.h>
#include <ESP8266WiFi.h>
#include <Phant.h>
#include <ESP.h>


#define DHTPIN 2
#define DHTTYPE DHT22
#define THERMISTORPIN 4


DHT dht(DHTPIN, DHTTYPE);

const char* ssid = "xxxx";
const char* password = "yyyyyy";
const char* host = "data.sparkfun.com";
const String publickey = "uuuuuu";
const String privatekey = "ttttttt";
const byte NUM_FIELDS = 5;
const String fieldNames[NUM_FIELDS] = {"ghumidity", "gtemp", "light", "otemp", "wtemp"};
String fieldData[NUM_FIELDS];

//переменные термистора
const int thermresistor = 987; //значение резистора последовательно с термистором
int thermtemp = 0;
uint8_t i;
uint8_t numsamples = 5;
uint8_t To = 25;
const int B = 3950;



void setup(){
    Serial.begin(115200);
    delay(10);
    WiFi.begin(ssid, password);

    while (WiFi.status() != WL_CONNECTED) {
  delay(500);
}

    fieldData[0] = 1; //влажность
    fieldData[1] = 2; //температура в саду
    fieldData[2] = 3; //свет
    fieldData[3] = 4; //внешняя температура
    fieldData[4] = 8; //температура воды


//поворотнасос();
posttophant();
//поворотнасос();
ESP.deepSleep(1200000000, WAKE_RF_DEFAULT);

}


void posttophant()
{
    fieldData[0] = dht.readHumidity();
    fieldData[1] = dht.readTemperature(true);


    //читаем внешние временные данные (otemp) и преобразуем во временные
    for (i=0; i<numsamples; i++){
      thermtemp = analogRead(THERMISTORPIN);
      thermtemp += thermtemp;
      delay(10);
    }

    //берем сумму всех показаний и делим на количество образцов, чтобы получить среднее значение.
    thermtemp = thermtemp / numsamples;

    #voltage divider equation
    thermtemp = thermresistor / (1023 / thermtemp - 1);


    //Уравнение Стейнхарта.
    thermtemp = 1 / (log(thermtemp / thermresistor) / B + (1 / (To + 273))) - 273;
    fieldData[3] = String(thermtemp);

    WiFiClient client;

    const int httpPort = 80;
if (!client.connect (host, httpPort)){
  return;
}

    client.print("POST /input/");
    client.print(publickey);
    client.print("?private_key=");
    client.print(privatekey);
    for (int i=0; i<NUM_FIELDS; i++)
    {
      client.print("&");
      client.print(fieldNames[i]);
      client.print("=");
      client.print(fieldData[i]);
    }
    client.println(" HTTP/1.1");
    client.print("Host: ");
    client.println(host);
    client.println("Connection: close");
    client.println();
}

, 👍1

Обсуждение

Я бы рассмотрел возможность использования термистора в качестве RC-резистора, что позволит проводить более точные измерения, чем 10 бит., @dandavis

Последовательный резистор сопротивлением 10 кОм должен обеспечить значительно лучшее разрешение., @Edgar Bonet

Можете ли вы подсказать, как мне решить следующую проблему? Из-за ограничений по пространству мне приходится делить АЦП и один из GPIO, то есть в одном случае управляемый программным обеспечением GPIO должен использоваться для своего исходного значения (цифровой ввод-вывод), игнорируя АЦП, а в другом случае АЦП должен использоваться без перегрузки током GPIO. Возможно ли теоретически использовать один терминал для обоих контактов? Спасибо., @Sergiy


3 ответа


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

3

Соображения по поводу аналогового вывода ESP8266

ESP8266 имеет только один вывод, который позволяет аналоговое чтение. Этот вывод называется A0 на модуле NodeMCU или A на ESP8266 Huzzah (некоторые другие модули ESP не открывают эту площадку - например, ESP8266-01) или могут обозначать ее по-другому - проверьте документацию вашего модуля ESP. После редактирования: убедитесь, что вы подключили термистор к контакту A модуля Huzzah ESP8266.

Следует помнить, что этот аналоговый вывод представляет собой 10-битный АЦП с принципиально ограниченным диапазоном входного напряжения.

Чтобы считать внешнее напряжение, приложенное к выводу АЦП, используйте analogRead(A0). Если вы не используете плату, специально разработанную для увеличения ее диапазона, диапазон входного напряжения составляет 0 — 1,0 В. Как отметил @dandavis, некоторые платы (например, Node MCU) включают в себя делитель напряжения на плате, чтобы дать вам полный входной диапазон 0 — 3,3 В.

Уравнения термистора

В техническом описании вашего термистора указано, что коэффициент TCR составляет 3000 ppm/%C и имеет значение 10K [обратите внимание, что производитель не указывает температуру, при которой R = 10K]. Уравнение изменения сопротивления ∆R при изменении температуры ∆T имеет вид:

∆R = ∆T*10k*3000ppm = 30*∆T

Таким образом, если T_0 — это температура, при которой R = 10k, уравнение значения сопротивления имеет вид:

R = 10k + (T-T_0)*30

Я предполагаю, что вы используете питание 3,3 В вашего ESP и создаете делитель напряжения с помощью резистора 1 кОм и термистора. Есть два способа сделать этот разделитель:

1. Вариант делителя напряжения 1

схема

[Обратите внимание, что термистор необходимо подключить к контакту A вашего ESP8266.]

2. Вариант делителя напряжения 2

схема

Уравнение напряжения в узле A

Для обоих случаев вот напряжение V_A, видимое в узле A:

1. Вариант делителя напряжения 1

V_A = R_серия *3,3 / (R_th + R_серия)

2. Вариант делителя напряжения 2

V_A = R_th *3.3 / (R_th + R_series)

Анализ изменений V_A с температурой

Давайте рассмотрим разницу между двумя приведенными выше формулами:

1. Вариант делителя напряжения 1

Числитель постоянен и зависит от температуры, а знаменатель меняется вместе с T. Вы получите сильное изменение.

2. Вариант делителя напряжения 2

И числитель, и знаменатель увеличиваются с температурой. Вы не получите большого изменения V_A с температурой. Вам следует избегать этой конфигурации.

Анализ максимально допустимого значения R_series

Важным моментом является то, что для вашего модуля ESP V_A не может быть выше 1 В.

1. Вариант делителя напряжения 1

Увеличение R_series увеличит V_A, поэтому мы вычисляем максимальное значение: 1 В = 3,3 В*R_серия_макс/(R_серия_макс+10 кОм)

Это дает вам: R_series_max = 4300 Ом

2. Вариант делителя напряжения 2

Увеличение R_series приведет к уменьшению V_A, поэтому мы вычисляем минимальное значение: 1 В = 3,3 В*10 к/(R_серия_мин+10 к)

Это дает вам: R_series_min = 23 кОм

Именно поэтому вам было предложено использовать в данном случае резистор номиналом 30 кОм.

Соображения относительно точности измерения температуры

Изменение напряжения ∆V на узле A ESP между температурами T1 и T2 можно вычислить следующим образом: ∆V = 3,3 *1К/(1к + 10к + 30*T1) - 3,3 *1К/(1к +10к+ 30*T2)

Если предположить, что термистор имеет сопротивление 10 К при температуре окружающей среды, то базовое напряжение, измеренное на выводе A, составит: 3,3 В*1К/11К = 0,3 В

Для 10-битного ЦАП от 0 до 1 В ESP8266 это примерно: 2^10*0,3 = 307

Изменение на 10С приведет к изменению напряжения на: ∆V = 0,3 - 3,3 *1K/(11k + 300) = 8 мВ ~8ADC код

Уравнение ∆T против ∆V не является линейным, но при небольшом изменении температуры при текущих настройках вы получаете ~1 код АЦП на градус.

В зависимости от вашего приложения этого может быть недостаточно для вас. Как предложено в нескольких комментариях, вы могли бы:

  • Добавьте больше термисторов параллельно
  • Увеличьте сопротивление последовательного резистора 1 кОм (но не слишком сильно, иначе вы перегрузите АЦП).
  • Изменить архитектуру измерительной схемы (RC-генератор с использованием термистора и счетчика прерываний в ESP, схема таймера 555, нагруженная термистором и счетчиком прерываний, ...)
  • Или если вы хотите делать измерения влажности и температуры, почему бы вам не приобрести модуль BME280. Его можно считывать через I2C, и библиотеки легко доступны для его считывания с помощью ESP8266.
,

1.0 nodeMCU платы принимают 0-3.3v. те, которые помещаются на макетной плате и имеют cp2102s, @dandavis

@dandavis не знал об этой интересной функции (до сих пор я сам пользовался только ESP-01)., @vrleboss

@dandavis подумав об этом, этот интегрированный на плате делитель напряжения может быть опасен, если сопротивление источника очень высокое. Хотя это не тот случай., @vrleboss

можно рассмотреть возможность параллельного подключения двух термосов для снижения R и усреднения ошибок (они в любом случае дешевые), @dandavis

vrleboss, знаменатель (11k + 0,003*10), что равно 11000,03, вместо этого должен быть 1KΩ + (1 + 0,003*10)*10KΩ, что равно 11300. То есть, 3000 ppm от 10KΩ равно 10000 * 3000/1000000 Ω, или 30 Ω на градус., @James Waldby - jwpat7

@jwpat7 верно подмечено. Я отредактировал свой пост., @vrleboss

@vrle, какой резистор будет слишком большим для использования последовательно с термистором? SortOfEngineer ниже предложил >30k, чтобы получить показания в диапазоне 0-1 В. Это слишком много? Моя цель состояла в том, чтобы установить 2 термистора (с DHT22 там), так как они очень дешевы для измерения 2 значений температуры в 2 местах. Я также хочу максимально продлить срок службы батареи, поэтому энергопотребление является проблемой, поэтому подумал, что простой термистор будет лучше, чем дополнительный модуль. Если у вас есть предложения по другому датчику, кроме DHT22, который можно использовать, который будет дешевым и может использовать все 3 из них на одном из моих модулей, я буду признателен за помощь, @willocks1718

@willocks1718, глядя на паспортные данные DHT22, потребление энергии не кажется очень низким. Я вижу 1 мА, указанный здесь: https://www.sparkfun.com/datasheets/Sensors/Temperature/DHT22.pdf. Вы можете получить более точные измерения с меньшим количеством деталей с модулями. Я цитирую BME280, потому что я использую его, он также был победителем в этом прекрасном сравнении бок о бок: https://www.kandrsmith.org/RJS/Misc/Hygrometers/calib_many.html, @vrleboss

@willocks1718 что касается значения резистора последовательно с вашим термистором, то это зависит от того, как сделан ваш делитель напряжения: 3,3 В - R_series - R_th - gnd или 3,3 В - R_th - R_series - gnd. Я обновлю свой ответ, чтобы объяснить лучше., @vrleboss

@vrleboss Я не против использования указанного вами модуля и не настроен на использование dht22, это просто то, что я купил первым и использую. Я бы с радостью заменил его на что-то, что потребляет меньше энергии или в целом лучше. Мне даже не важно измерение влажности, но я использую его, так как он с dht22. Спасибо за подробную помощь, мне теперь нужно много исследовать!, @willocks1718


1

Что касается «проблемы где-то в моем коде», то во многих местах кода есть проблемы.

• Следующий цикл не суммирует показания; он берет кучу показаний и отбрасывает их, затем удваивает последнее. Например, если пять показаний подряд равны 300, 400, 500, 600 и 100, то thermtemp после цикла будет равен 200. Чтобы увидеть это, попробуйте — мысленно смоделируйте, что делает код, записывая значение thermtemp после каждого шага.

for (i=0; i<numsamples; i++) {
   thermtemp = analogRead(THERMISTORPIN);
   thermtemp += thermtemp;
   delay(10);
}

• Ваше «уравнение делителя напряжения» (ниже) имеет форму, подобную той, что показана в руководстве Adafruit, но поскольку ваш thermtemp объявлен как int (а не как float Adafruit), будет использоваться целочисленное деление с усечением, что приведет к неточности.

thermtemp = thermresistor / (1023 / thermtemp - 1);

• Ваше уравнение Стейнхарта-Харта неверно закодировано. На этом этапе значение фиксированного резистора, thermresistor, больше не имеет значения. Соответствующее значение — это показание АЦП, преобразованное в сопротивление термистора.

• В вашей неправильной реализации Стейнхарта-Харта log(thermtemp / thermresistor) принимает логарифм нуля, поскольку в целочисленной арифметике thermtemp / thermresistor равен нулю.

• Выражение 1 / (To + 273) равно нулю в целочисленной арифметике.

,

Что касается цикла for, я думал, что если сказать... thermtemp += thermtemp;, то только что прочитанное значение будет добавлено к предыдущей сумме и сохранено в переменной? Я понимаю, что вы говорите о целых числах, ха-ха, я все еще учусь и пытаюсь сэкономить место для хранения. Я внесу эти изменения., @willocks1718

@willocks1718, да, thermtemp += thermtemp добавляет thermtemp к thermtemp, что удваивает его. Пройдитесь по нему вручную, записывая значение после каждого шага: 300, 600, 400, 800, 500, 1000, 600, 1200, 100, 200., @James Waldby - jwpat7

извините, я имел в виду, что если первое показание было 300, то оно сохраняется в thermtemp. Если следующее показание будет 350 или около того, оно добавит его к предыдущему значению и сохранит его, чтобы получить 650. По сути, это будет суммирование следующих x показаний. Так что это неправильное мышление?, @willocks1718


1

Возможно, у вас возникло несколько проблем:

Во-первых, насколько я понимаю, АЦП ESP8266 считывает только до 1 В. Если подключить его по примеру Arduino, который вы привели, и использовать 1 кОм, у вас будет VCC->1 кОм->ТЕРМИСТОР->GND. При комнатной температуре термистор равен 10 кОм, поэтому напряжение на АЦП будет 3,3*(10 кОм/(1 кОм+10 кОм)), что довольно близко к 3,3 В. Я не знаю поведения АЦП при выходе за пределы диапазона, но я предполагаю, что вы просто получите 0xFFFF. Вероятно, вам понадобится >30 кОм последовательно с термистором, чтобы получить его в пригодном для использования диапазоне.

Я также вижу небольшую ошибку (как мне кажется) в вашем коде:

//считывает внешние данные температуры (otemp) и преобразует их в temp
for (i=0; i<numsamples; i++){
  thermtemp = analogRead(THERMISTORPIN);
  thermtemp += thermtemp;
  delay(10);
}

Должно быть:

//считывает внешние данные температуры (otemp) и преобразует их в temp
thermtemp = 0
for (i=0; i<numsamples; i++){
  thermtemp += analogRead(THERMISTORPIN);
  delay(10);
}

В противном случае thermtemp — это просто последнее показание, добавленное к самому себе.

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

Надеюсь, это поможет.

,

Я не понял, что пин только считывает 0-1 В, спасибо. У меня есть несколько резисторов, и я разберусь, какое значение мне нужно. Что касается цикла for, я пытался добавить новое значение к предыдущему значению и снова сохранить сумму в переменной, по-видимому, способ, которым я пытался это сделать, не работает, поэтому я исправлю цикл, @willocks1718

Кстати, на платах NODEMCU на базе cp2102 уже есть два высокоомных резистора на A0, что позволяет использовать диапазон 0-Vcc, что я считаю очень полезным., @dandavis