• Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

Делюсь опытом MAX31855, датчик к-термопары с компенсацией температуры холодного спая

enjoynering

Well-known member
Библиотека для MAX31855 от Maxim Integrated. На борту два АЦП. 14-bit для термопары и 12-bit для холодного спая. Время преобразования около 100 миллисекунд или 10 измерений в секунду. По мимо температуры термопары умеет выдавать температуру холодного спая. Обладает улучшенными диагностическими функциями - замыкание термопары на землю, замыкание на питание, обрыв термопары. Для уменьшения наводок на входе производитель советует допаять параллельно "-T" и "+T" конденсатор на 10nF/0.01mF. Ребята из Adafruit по мимо этого еще и ферритовые бусинки на холодный спай одевают.

Библиотека поддерживает все плюшки сенсора. Работает с железным SPI или эмулирует последовательный протокол ногодрыгом/bitbang.

Забирать тут.
 

Jaeger

New member
Либа неплохая. Отлично прокомментирована. Но тупо ждать в лупе 100 мс завершения конверсии и ни чего не делать, как то не кошерно. Я имею ввиду: delay(MAX31855_CONVERSION_TIME) в функции readRawData.
 

Jaeger

New member
Ну я типа такого сколхозил, заменил delay стандартным способом, у меня работает:
Код:
int32_t MAX31855::readRawData(void)
{
int32_t rawData = 0;
uint32_t previousMillis = 0;

digitalWrite(_cs, LOW);  //stop  measurement/conversion
delay(1);               //4MHz  is 0.25usec, do we need it???
digitalWrite(_cs, HIGH); //start measurement/conversion

if(millis() - previousMillis > MAX31855_CONVERSION_TIME) {
        previousMillis = millis(); 
        ........

      return rawData;
}
     return false;
}
В примере:
Код:
if(myMAX31855.readRawData()); { //если конверсия закончилась, получаем температуру
   c = myMAX31855.getTemperature(rawData);
}
 

enjoynering

Well-known member
Да можно, но осторожно. Дело в том, что вы можете словить о-о-о-очень редкий глюк, когда mills() переполнился и стал например 10, а previousMillis все еще за 4-е миллиона и у вас будет отрицельный результат, который вызовет краш модуля. Чтоб этого не произошло используйте функцию abs().

Кстати у вас ошибка, тк вы обявляте previousMillis внутри функции, она всегда будет 0 при вычитании из mills(). Ее надо объявлять как глобальную, или уж если не хотите захламлять код то можно оставить переменную внутри функции, но объявить ее как static uint32_t. Тогда она станет глобальной, но будет доступна только той функции в которой объявлена.

Изначально данная либа писалась под avr для фена с PID регулировкой. Мне была важна точность поддержания температуры, а не скорость работы камня. Отсюда и delay().
 
Последнее редактирование:

CodeNameHawk

Moderator
Команда форума
о-о-о-очень редкий глюк, когда mills() переполнился и стал например 10, а previousMillis все еще за 4-е миллиона и у вас будет отрицельный результат, который вызовет краш модуля.
IMHO так как все переменные беззнаковые, отрицательного результата не может быть (просто получиться переполнение, пропадет один бит и результат получиться "малым") и краша тоже не будет.
Раз в примерно 50 суток, может быть неточно выдержанный интервал задержки.
 
Последнее редактирование:

enjoynering

Well-known member
получиться переполнение, пропадет один бит и результат получиться "малым") и краша тоже не будет.
Вы уверенны? Проверяли?

Я только показал как правильно, а дальше как хотите.

Можно и знак поворота не показывать на дороге, но настанет после дождичка в четверг вас нехило накажет.
 
Последнее редактирование:

CodeNameHawk

Moderator
Команда форума
Вы уверенны? Проверяли?
Стал бы я тут распинаться...
Код:
unsigned long old_Value = UINT64_MAX;
unsigned long delay_value = 10;

unsigned long replace_millis_function(void)
{
    return 5;
}


void setup()
{

  /* add setup code here */
    Serial.begin(115200);
   
    Serial.println();
    Serial.println("Start.");

    Serial.print("old_Value ");
    Serial.println(old_Value);

    Serial.print("replace_millis_function ");
    Serial.println(replace_millis_function());

    Serial.print("delay_value ");
    Serial.println(delay_value);

    Serial.print("Result ");
    Serial.println(replace_millis_function() - old_Value);
   

    if ((replace_millis_function() - old_Value) > delay_value)
    {
        Serial.println("True.");
    }
    else Serial.println("False.");
}

void loop()
{

  /* add main program code here */

}
Код:
Start.
old_Value 4294967295
replace_millis_function 5
delay_value 10
Result 6
False.
Вам не показалось странным, что почти все используют код без проверки переполнения?
 

enjoynering

Well-known member
Нет, не показалось. Ардунщики на 90% копипастеры. Уже не раз в этом убеждался. Поэтому очень редко пользуюсь чужими библиотеками.
 
Последнее редактирование:

CodeNameHawk

Moderator
Команда форума
Вся суть ардуино, взять куски готового и добавить немного своего кода.
 

Jaeger

New member
Изначально данная либа писалась под avr для фена с PID регулировкой. Мне была важна точность поддержания температуры, а не скорость работы камня. Отсюда и delay().
Во, у меня такая же сейчас задача, соорудить контроллер для китайского термофена. Планирую на ардуине про мини + OLED 128х64 желто-синий, энкодер, max31855, шим на вентилятор, ардуиновский PID с выходом на твердотельное реле. Вот только мне не очень понятно, как delay() влияет на точность регулирования PID? PID тоже ваш?
 

enjoynering

Well-known member
моя логика была такая - с delay(MAX31855_CONVERSION_TIME) я гарантированно получаю температуру СРАЗУ ПОСЛЕ ИЗМЕРЕНИЯ. с (millis() - previousMillis > MAX31855_CONVERSION_TIME непонятно когда это случится. через 100 или 150, или 200мс?

PID не мой. еще только в планах осилить а пока самым популярным пользуюсь (по мне так неплохо написан).
 

Jaeger

New member
enjoynering, каким образом с (millis() - previousMillis > MAX31855_CONVERSION_TIME время конверсии может быть меньше MAX31855_CONVERSION_TIME?
 

Jaeger

New member
Больше не меньше, в данном случае это не повредит результату. Застрять можно где угодно, все зависит от кодера.
Я просто хочу выяснить, delay(200) в лупе - это нормально?
И еще немного конструктивной критики:
Функция getTemperature(int32_t rawValue)возвращает число с двумя знаками после запятой, на дисплей выводим
целое число, на "месте" бы округлять, да и вообще отказаться бы от операций с "плавающей точкой", уж больно жрет до хрена памяти.
 

enjoynering

Well-known member
Я люблю по точнее. в память никогда не упирался. откажитесь от oled. одни недостатки: шрифты, он же массив символов висящий в памяти (он просто огромен по сравнению с одним float из моей либы), выгорает со временем, маааленький и читать неудобно. по мне так - Универсальная библиотека LiquidCrystal_I2C на базе расширителя портов PCF8574 самое то для таких поделок и дешевле.

ну и в догонку вам - MAX31855, датчик к-термопары с компенсацией температуры холодного спая

если упираетесь в размер скеча, а не памяти можно поменять загрузчик - Optiboot загрузчик для Arduino даст лишних 1.5kb!!!
 
Последнее редактирование:

pvvx

Активный участник сообщества
Да можно, но осторожно. Дело в том, что вы можете словить о-о-о-очень редкий глюк, когда mills() переполнился и стал например 10, а previousMillis все еще за 4-е миллиона и у вас будет отрицельный результат, который вызовет краш модуля.
(unsigned)0x0000000a - (unsigned)0xffffffff = 0x0000000b и ? Где отрицательное? Значение константы с которым сравнивается? Но оно же не больше 2147483647 микросекунд (35 минут) и указывать тип unsigned нет смысла.
millis считывает и выдает младшие 32 бита 64-х аппаратного счетчика микросекунд.
То, что переменная не глобальная и не инициализирована - это ошибка, т.к. желательно ей присвоить значение millis() в процедурах инициализации проекта, перед запросами данной функции, а не в setup().
Но это всё безразлично, т.к. Arduino на ESP8266 не рассчитано работу без глюков в течении десятка минут :)
 
Последнее редактирование:

pvvx

Активный участник сообщества
Я просто хочу выяснить, delay(200) в лупе - это нормально?
А в чем беда?
Всё в ESP8266 работает по событиям. Эмуляция поллинга в loop() - это чуждо её системе и сделано для тех, кто не понимает основ программирования кроме как в линеечку...
Системе и нормальному коду всё равно, даже если loop() содержит всего одну функцию delay(100500). WiFi, работа TCP стека и все прерывания только в этом случае работают правильно, не нарушая спецификаций WiFi и прочих RFC (рекомендаций).
И еще немного конструктивной критики:
Функция getTemperature(int32_t rawValue)возвращает число с двумя знаками после запятой, на дисплей выводим
целое число, на "месте" бы округлять, да и вообще отказаться бы от операций с "плавающей точкой", уж больно жрет до хрена памяти.
Плавающая точка жрет всего несколько блоков с инициализацией библиотеки в RAM, а остальной код находится в Flash (XIP). XIP у вас 1 МегаБайт и не понятно, что туда не влезает при правильном подходе и разработке приложения. Константы, скрипты и даже код могут подгружаться на время исполнения, к примеру как оверлеи, из всей доступной области одного чипа Flash на 16 МБайт. А можно и несколько чипов Flash или внешний сервер, включающий оплату за загружаемый код в IRAM и исполняемый код у пользователя :). По этому ограничений нет. Тем более для ваших приложений, где какие либо события или опрос происходят и производятся не чаще 1 раза в несколько минут. Даже если переписывать flash для запуска разного кода, всё равно за время использования ESP8266 дырки там не будет, т.к. все процессы у вас очень медленные... а все задачи в loop() сводятся к разбивке на малые блоки кода по времени исполнения для быстрейшего ухода в delay(), чтобы система работала. Проще всё эти куски повесить на "калбэки" уже имеющиеся в системе у LwIP, да совт-таймерные "калбэки" и аппаратные прерывания... Код у вас сократиться на никому ненужный "поллинг" - т.е. loop() станет пустым, с одной строчкой - delay(100500). Ну и т.к. все события в ESP8266 обрабатываются по раздельности, с нулевой глубиной стека (вызываются из ets_run()), то каждое событие имеет возможность на время обработки использовать всю память ESP8266, по выходу предоставив пару байт ответа и новые назначенные события для последующей обработки, да с указанием уровня приоритета, чтобы не мешать работать системе.
Arduino - это атавизм, созданный для того, чтобы вы не смогли работать с современными мультизадачными системами в последующем.
 
Последнее редактирование:

Jaeger

New member
Все мои вопросы были относительно ардуины на AVR. С ESP8266 я еще не работал (хотя и есть несколько штук) поэтому информацию из ваших постов я, к сожалению, ни хрена не понял.

если упираетесь в размер скеча, а не памяти можно поменять загрузчик - Optiboot загрузчик для Arduino даст лишних 1.5kb!!!
Давно уже поставлен. Более того, можно обойтись вообще без бутлодыря.
 
Сверху Снизу