Датчик отключения паяльника при бездействии

INRI
Offline
Зарегистрирован: 12.10.2019
По просьбе внука (увлекается изготовлением изделий из кожи) решил собрать ему к НГ кризер (считай, паяльная станция с пониженной температурой). За основу взял вот этот проект: https://cxem.net/master/113.php , выкинув из него фен и применив ардуинку нано.
 
   Все собрано на макете и работает. Но вот незадача - никак не могу вставить в код датчик отключения паяльника в зависимости от бездействия. Решил применить пару ртутных датчиков в ручке паяльника. Пока они едут из города Китая, на макете кнопка.
 
   Делаю код с задержкой , отключается, а назад никак. Появилась идея отключать по длительному нажатию кнопки (срабатыванию датчика). Бьюсь уже неделю, не выходит ничего... 
 
Код у меня такой:
[code]
/*
Creaser Station



*/

#include <Bounce.h>
#include <EEPROM2.h>
#include <TimerOne.h>
#include <Encod_er.h>
#include <Wire.h> 
#include <LiquidCrystal_I2C.h> 


LiquidCrystal_I2C lcd(0x27,16,2); //Подключаем дисплей



const int pinSolderOut = 5;  // Выход нагревателя
int pinSolderTCouple = A3;  // Термопара

int pinSolderButton = 2;  // Кнопка энкодера (вкл. \ выкл.)
Bounce SolderButton = Bounce(pinSolderButton,5); 
int pinSensor = 4;
Bounce Sensor = Bounce(pinSensor,5);
int s = 0; //переменная кнопки
int h = 1; //переменная кнопки

int pinSensorState = 1;

 Encod_er encoder1(A0, A2 , 5);   
int encoderPosCount1;
void timerInterrupt() {
  encoder1.scanState(); 
 }

 
void setup()  
{
 
  pinMode(pinSolderOut, OUTPUT);
  pinMode(pinSolderButton, INPUT);
  pinMode(pinSensor, INPUT_PULLUP);
 
  lcd.begin(16, 2);
  EEPROM_read(1, encoderPosCount1);
  
  Timer1.initialize(250); //  таймер, период 250 мкс
  Timer1.attachInterrupt(timerInterrupt, 250); //  обработчик прерываний

  lcd.init(); 
  lcd.backlight(); 
  // Вывод приветствия
  lcd.setCursor(0, 0);
  lcd.print("Creaser station");
  lcd.setCursor(4, 1);
  lcd.print("ver. 1.0"); 
//  задержка
  delay (3000);
  lcd.clear();
}

void loop()
{
  
 static unsigned long int lastouttime=0;
 pinSensorState = digitalRead(pinSensor);
unsigned long last_time=0;
 //Энкодер
    //Обработчик кнопки энкодера
   if ( SolderButton.update() ) {
    //если считано значение 1
    if ( SolderButton.read() == LOW)   {
      if (s == 0) s = 1;
      else s = 0;
  EEPROM_write(1,  encoderPosCount1);
    }
  }
  
 if ( Sensor.update() ) { // ***********Тут пытаюсь присобачить датчик
   
   if ( Sensor.read() == LOW ) 
   {    
     if (h == 1){ h = 0;}
     else h = 0;
     delay (30000); //*************задержка 30 сек (для экспериментов)
   if (h == 0){s = 0;}
     //else s = 1;
   
 }}
     
  
 
    //Крутилка***********************************
  if(encoder1.timeRight != 0) {
  lastouttime = millis()+ lastouttime;
    if (encoderPosCount1 < 400) {
      if (encoder1.timeRight > 60)  encoderPosCount1 ++;
      else encoderPosCount1 = encoderPosCount1 + 10;
    }
    encoder1.timeRight= 0;
  }
  if(encoder1.timeLeft != 0) {
  lastouttime = millis()+ lastouttime;
    if (encoderPosCount1 > 40) {
      if (encoder1.timeRight > 60)  encoderPosCount1 --;
      else encoderPosCount1 = encoderPosCount1 - 10;
    }
    encoder1.timeLeft= 0;
  }    
  //lastouttime=millis();  
      
  // Преобразовываем значения
  int setSolderTemp = encoderPosCount1;
  int solderTCouple = map(analogRead(pinSolderTCouple), 0, 750, 0, 480);
  
  // Защита
  if (solderTCouple > 400) {
    setSolderTemp == 0 ;
  }
 

 

  // Поддержка установленной температуры 
  if (setSolderTemp >= solderTCouple && s == 1  )
  {
    digitalWrite(pinSolderOut, LOW);
    digitalWrite(pinSolderOut, HIGH);
  }
 
  else {
    digitalWrite(pinSolderOut, LOW);
  }
   
    //  дисплей

if ((millis()-lastouttime)>500)
{
  lcd.print("Setting:");
  lcd.setCursor(12, 0);
  if (s == 1) {
  if (solderTCouple < 400) {      
      lcd.print(setSolderTemp);   
      lcd.print("\xdf");//выводим значок "°"
      lcd.print (" ");
  if (setSolderTemp < 100) lcd.print (" ");
  if (setSolderTemp < 10) lcd.print (" ");
      lcd.setCursor(0,1);   
      lcd.print ("Heating:     ");
      lcd.setCursor(12, 1);
  if ((setSolderTemp +5) > solderTCouple && (setSolderTemp - 5) < solderTCouple)
      lcd.print(setSolderTemp );
 else {if (solderTCouple < 40) lcd.print ("Cold");
      lcd.print(solderTCouple);
 }
      lcd.print("\xdf"); //выводим значок "°"
      lcd.print (" ");
      lcd.print (" ");
  if (solderTCouple < 100) lcd.print (" ");
  if (solderTCouple < 10) lcd.print (" ");
    }
    else {
      lcd.print(" Error   ");
    }
  }
  //Температура при выключении
    else if 
    ( s == 0 ) {
    lcd.print(" Off ");
    lcd.setCursor(0, 1);
    lcd.print("Temperature:");
    if (solderTCouple < 40) lcd.print ("Cold");
    lcd.print(solderTCouple);
    lcd.print("\xdf"); //выводим значок "°"
    if (solderTCouple < 100) lcd.print (" ");
    if (solderTCouple < 10) lcd.print (" ");
   
  }
  
lastouttime=millis();
}
}
  
[/code]

 

 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

возьмите библиотеку Гайвера для кнопки, пример использования там есть

v258
v258 аватар
Offline
Зарегистрирован: 25.05.2020

Сначала советуем взять гайвера, потом плюемся на его библиотеки в коде? ))

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

v258 пишет:

Сначала советуем взять гайвера, потом плюемся на его библиотеки в коде? ))

это не ко мне, кстати, некоторые из плюющихся таки используют его библиотеку кнопок )))

v258
v258 аватар
Offline
Зарегистрирован: 25.05.2020

В любом случае использовать кнопочную библиотеку тут слишком жирно.

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

if ( Sensor.update() ) { // ***********Тут пытаюсь присобачить датчик
  static bool flag = false;
  static uint32_t timer = 0;

  if ( Sensor.read() == LOW )
  {
    if (!flag) { // если датчик только что замкнулся, поднять флаг и сохранить значение таймера
      flag = true;
      timer = millis();
    }
  } else
    flag = false;
  // если флаг поднят, разбираетесь с задержкой отключения
  if (flag) {
    if (millis() - timer >= 30000) {
      // здесь выполнете действия при превышении интервала бездействия
    }
  }
}

 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

v258 пишет:

В любом случае использовать кнопочную библиотеку тут слишком жирно.


оставшаяся память кода совсем не то, что можно передать по наследству внукам )))
PS тут я с Дракулой солидарен

v258
v258 аватар
Offline
Зарегистрирован: 25.05.2020

ua6em пишет:

v258 пишет:

В любом случае использовать кнопочную библиотеку тут слишком жирно.


оставшаяся память кода совсем не то, что можно передать по наследству внукам )))
PS тут я с Дракулой солидарен

Дело не в этом. Тут делов-то на несколько строк ))

Green
Offline
Зарегистрирован: 01.10.2015

+1. Для простой кнопки (без выкрутасов) достаточно 10-ти строк. И всё ясно как божий день.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Green пишет:

+1. Для простой кнопки (без выкрутасов) достаточно 10-ти строк. И всё ясно как божий день.

RE - Бьюсь уже неделю, не выходит ничего...

я только о том, что не надо биться с ветряными мельницами когда есть простое решение на пять минут...

PS Хочу лицезреть код длительного нажатия кнопки на 10 строк (я бы так не смог) )))

v258
v258 аватар
Offline
Зарегистрирован: 25.05.2020

ua6em пишет:

PS Хочу лицезреть код длительного нажатия кнопки на 10 строк (я бы так не смог) )))

Дык, я ж код привел ))

Green
Offline
Зарегистрирован: 01.10.2015
every(1) {
  static bool key;
  static uint16_t timer;
  if (key != get_key()) {
    key = !key;
    timer = DEBOUNCE_TIME;
  }
  else if (timer && !--timer && key)
  //есть нажатие
}

 

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

Green пишет:

every(1) {
  static bool key;
  static uint16_t timer;
  if (key != get_key()) {
    key = !key;
    timer = DEBOUNCE_TIME;
  }
  else if (timer && !--timer && key)
  //есть нажатие
}

а в его код и чтоб оно работало, смотришь за твоё здоровье бокал поднимет )))
PS я с утра на расслабоне сходу код не одолел, а выше - с ошибками

v258
v258 аватар
Offline
Зарегистрирован: 25.05.2020

С какими ошибками?

sadman41
Offline
Зарегистрирован: 19.10.2016

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

v258
v258 аватар
Offline
Зарегистрирован: 25.05.2020

При длительном удержании кнопки дребезгом можно вообще пренебречь, ибо интересует именно длительное нажатие, а не короткий клик

Upper
Offline
Зарегистрирован: 23.06.2020

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

bool flagSleep = false;
uint32_t timeLastMove;

if ( Sensor.update() ) { // ***********Тут пытаюсь присобачить датчик
	flagSleep = false;	// если двигали, то сбрасываем флаг и счетчик
	timeLastMove = millis();
 }
else (		// если долго не двигали, то ставим флаг, что нужно отключить
	if ((millis() - timeLastMove) > 10000) {
		flagSleep = true;
	}
)

 

SAB
Offline
Зарегистрирован: 27.12.2016

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

Тогда вообще всё просто.  Таймаут, как было уже предложено. Так же можно имперически вычислить время на подогрев, чтобы не с 25 градусов шёл разогрев,  а с допустим 100. Не используя при этом температурного датчика. Ведь параметры паяльника можно, в первом приближении, принять за константу.

Kakmyc
Offline
Зарегистрирован: 15.01.2018

Тс не мелочись, суй туда mpu6050.

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

v258 пишет:

С какими ошибками?

как минимум в строке 11 )))

 } else
    flag = false;
  // если флаг поднят, разбираетесь с задержкой отключения
  if (flag) {
    if (millis() - timer >= 30000) {
      // здесь выполнете действия при превышении интервала бездействия
    }

PS да, не надо из себя бессмертных Маклаудов не ошибающихся программистов изображать, все мы просто люди

v258
v258 аватар
Offline
Зарегистрирован: 25.05.2020

ua6em пишет:

v258 пишет:

С какими ошибками?

как минимум в строке 11 )))

 } else
    flag = false;
  // если флаг поднят, разбираетесь с задержкой отключения
  if (flag) {
    if (millis() - timer >= 30000) {
      // здесь выполнете действия при превышении интервала бездействия
    }

PS да, не надо из себя бессмертных Маклаудов не ошибающихся программистов изображать, все мы просто люди

Это не ошибка. Если датчик замкнулся (только что), флаг поднять, таймер взвести, иначе флаг опустить. 

ЗЫ: про Маклауда не понял - вопрос был об ошибке, которую пропустил. Вполне закономерный вопрос - ошибки нужно исправлять ;))

ua6em
ua6em аватар
Offline
Зарегистрирован: 17.08.2016

синтаксис, если рваный то мой мозг с этим не справится, ибо смотрится как "bush"

if() { } else { }

 

v258
v258 аватар
Offline
Зарегистрирован: 25.05.2020

Да ничего там рваного нету. И отформатировано по Ctrl+T ))

PS: понял, 12 строка не в скобках. Ну бывает )))

INRI
Offline
Зарегистрирован: 12.10.2019

SAB пишет:

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

У всех подставки под паяльник разные. У меня, например, на подставке паяльник лежит жалом вверх, а иногда вообще валяется на столе без подставки (тоже жало приподнято получается). Геркон подразумевает магнит в подставке (хорошо для фена) и без неё паяльник не отключится.

INRI
Offline
Зарегистрирован: 12.10.2019

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

Спасибо за код, сегодня попробую разобраться. 

INRI
Offline
Зарегистрирован: 12.10.2019

Сначала хочу всех поблагодарить за содействие. Наконец-то всё получилось! :)

Узнал много нового, в частности о флагах и , кажется, научился ими пользоваться.

С кодом от v258 не заладилось что-то, хотя в нем вроде разобрался. Поковырялся в инете, посмотрел примеры разные... Короче, вот что получилось: отключается при длительном замыкании датчика (10 мин), включается кнопкой энкодера, как мне и хотелось.

Код получился такой:

[code]
/*
Creaser Station
v1.0

*/

#include <Bounce.h>
#include <EEPROM2.h>
#include <TimerOne.h>
#include <Encod_er.h>
#include <Wire.h> 
#include <LiquidCrystal_I2C.h> 


LiquidCrystal_I2C lcd(0x27,16,2); //Подключаем дисплей

//Глобальные переменные***************

const int pinSolderOut = 5;  // Выход нагревателя
int pinSolderTCouple = A3;  // Термопара
int pinSolderButton = 2;  // Кнопка энкодера (вкл. \ выкл.)
Bounce SolderButton = Bounce(pinSolderButton,5); 
int pinSensor = 4; // Датчик
Bounce Sensor = Bounce(pinSensor,100);
int s = 0; //переменная кнопки энкодера
int h = 1; //переменная датчика 

//Переменная энкодера*****************
 Encod_er encoder1(A0, A2 , 5);   
int encoderPosCount1;
void timerInterrupt() {
  encoder1.scanState(); 
 }

 
void setup()  
{
//Настройка портов*******************
  pinMode(pinSolderOut, OUTPUT);
  pinMode(pinSolderButton, INPUT);
  pinMode(pinSensor, INPUT_PULLUP);
   
  lcd.begin(16, 2);
  EEPROM_read(1, encoderPosCount1);
  lcd.init(); 
  lcd.backlight();
  Timer1.initialize(250); //  таймер, период 250 мкс
  Timer1.attachInterrupt(timerInterrupt, 250); //  обработчик прерываний
  
// Вывод приветствия***************
  lcd.setCursor(0, 0);
  lcd.print("Creaser station");
  lcd.setCursor(4, 1);
  lcd.print("ver. 1.0"); 
  delay (3000);
  lcd.clear();
}

void loop()
{
  static unsigned long int lastouttime=0;
//Обработчик кнопки энкодера
    if ( SolderButton.update() ) {
    if ( SolderButton.read() == LOW)   {
    if (s == 0) s = 1;
       else s = 0;
  EEPROM_write(1,  encoderPosCount1);
    }
  }
  
//Датчик выключения при бездействии***************
 
   static bool flag = false;
   static  uint32_t timer = 0;
   bool Sensor = !digitalRead(4);
    if ( Sensor && !flag && millis()-timer >100)
  {
             flag = true;
             timer = millis();
     }
     
    if (Sensor && flag && millis() - timer > 600000) { 
       
             timer = millis();
             if (h == 1){ h = 0;}
             else {h = 0;}
    
             if (h == 0)
             {s = 0;}
   }
    if (!Sensor && flag && millis() - timer > 600000) {
             flag = false;
             timer = millis;
   }
   
// Крутилка энкодера***************************************

      if(encoder1.timeRight != 0) {
  lastouttime = millis()+ lastouttime;
      if (encoderPosCount1 < 400) {
      if (encoder1.timeRight > 60)  encoderPosCount1 ++;
      else encoderPosCount1 = encoderPosCount1 + 10;
    }
    encoder1.timeRight= 0;
  }
    if(encoder1.timeLeft != 0) {
  lastouttime = millis()+ lastouttime;
    if (encoderPosCount1 > 40) {
      if (encoder1.timeRight > 60)  encoderPosCount1 --;
      else encoderPosCount1 = encoderPosCount1 - 10;
    }
    encoder1.timeLeft= 0;
  }    
  //lastouttime=millis();  
      
  // Преобразовываем значения температуры************************
  
  int setSolderTemp = encoderPosCount1;
  int solderTCouple = map(analogRead(pinSolderTCouple), 0, 750, 0, 480);
  
  // Защита
  if (solderTCouple > 400) {
    setSolderTemp == 0 ;
  }
 

 

  // Поддержка установленной температуры 
  if (setSolderTemp >= solderTCouple && s == 1  )
  {
    digitalWrite(pinSolderOut, LOW);
    digitalWrite(pinSolderOut, HIGH);
  }
 
  else {
    digitalWrite(pinSolderOut, LOW);
  }
   
    //  дисплей

if (millis()-lastouttime >500)
{
  lcd.print("Setting:");
  lcd.setCursor(12, 0);
  if (s == 1) {
  if (solderTCouple < 400) {      
      lcd.print(setSolderTemp);   
      lcd.print("\xdf");//выводим значок "°"
      lcd.print (" ");
  if (setSolderTemp < 100) lcd.print (" ");
  if (setSolderTemp < 10) lcd.print (" ");
      lcd.setCursor(0,1);   
      lcd.print ("Heating:     ");
      lcd.setCursor(12, 1);
 //Чтобы цифры не прыгали
  if ((setSolderTemp +5) > solderTCouple && (setSolderTemp - 5) < solderTCouple)  
      lcd.print(setSolderTemp );
 else {if (solderTCouple < 40) lcd.print ("Cold");
      lcd.print(solderTCouple);
 }
      lcd.print("\xdf"); //выводим значок "°"
      lcd.print (" ");
      lcd.print (" ");
  if (solderTCouple < 100) lcd.print (" ");
  if (solderTCouple < 10) lcd.print (" ");
    }
    else {
      lcd.print(" Error   ");
    }
  }
  //температура при остывании
    else if 
    ( s == 0 ) {
    lcd.print(" Off ");
    lcd.setCursor(0, 1);
    lcd.print("Temperature:");
    if (solderTCouple < 40) lcd.print ("Cold");
    lcd.print(solderTCouple);
    lcd.print("\xdf"); //выводим значок "°"
    if (solderTCouple < 100) lcd.print (" ");
    if (solderTCouple < 10) lcd.print (" ");
  
  }
  
 lastouttime=millis();
}
}
  
[/code]

 

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

Кактус дело говорит, и не дорого: https://aliexpress.ru/item/1734534460.html

И любые подставки можно «обслужить»)))

INRI
Offline
Зарегистрирован: 12.10.2019

BOOM пишет:

Кактус дело говорит, и не дорого: https://aliexpress.ru/item/1734534460.html

И любые подставки можно «обслужить»)))

Даже если удастся разместить  такой датчик в ручке паяльника, он потребует дополнительного питания, а лишняя жила под датчик в проводе паяльника только одна -  заземление корпуса,  в моём случае лишнее.

Alexey_Rem
Offline
Зарегистрирован: 09.09.2019

Я бы сделал так:

uint16_t timer_off;

void setup() {

}

void loop() {
...
if (сработка датчика)
{
 timer_off=millis();
}
if(millis()- timer_off>off_interval)//off_interval=время задержки(мин)*100*60
{
код перехода в спящий режим;
}
...

}

 

BOOM
BOOM аватар
Offline
Зарегистрирован: 14.11.2018

INRI пишет:

BOOM пишет:

Кактус дело говорит, и не дорого: https://aliexpress.ru/item/1734534460.html

И любые подставки можно «обслужить»)))

Даже если удастся разместить  такой датчик в ручке паяльника, он потребует дополнительного питания, а лишняя жила под датчик в проводе паяльника только одна -  заземление корпуса,  в моём случае лишнее.

Что мешает пятижильный или более использовать? А ссылка на готовый датчик, он на 99,99% будет с рабочими компонентами. Потом из можно «махнуть» на свою плату или «обпилить» ту плату. Она мизерная на самом деле. В ручку паяльника должна влезть (если обпилить). Зато куча возможностей появится. Не только признак «сняли с держателя», но и при встряхивании (например) увеличение мощности и так далее. Пробуйте, экспериментируйте. Если это Вам, конечно же, нужно...

INRI
Offline
Зарегистрирован: 12.10.2019

BOOM пишет:
Что мешает пятижильный или более использовать?
 

Спасибо за участие. Но хочу объяснить. У кризера (паяльника)  пятижильный кабель:

- два конца на нагрев (24в), причем регулировка по "земле", т.о. в сам паяльник чистая "земля не приходит;

- два конца на термопару (один из них "земля") ;

 - один провод - корпус паяльника (будет использоваться для датчика положения).

Трясти и менять мощность совершенно ни к чему. Для кожи главное - поддержка заданной температуры на наконечнике. А выключение нагрева (не сон) - только для безопасности при забытом на столе включенном приборе. 

А датчики такие у меня имеются. В свое время хотел использовать для индикации поклевки на донке. Отказался. Колокольчик из латунной гильзы все же гораздо ламповей...