Четыре зоны управления температурой + ШД

SONIC300077
Offline
Зарегистрирован: 15.10.2013

Здравствуйте ! Я совсем недавно увлекся ардуинкой, так сказать азы  впитываю. Но все больше и больше хочется творить самому, и поэтому я обращаюсь к вам. если у вас есть время повозиться со мной в данном проекте, то я буду очень рад этому. Ну и как положено - с меня причитается!

Проект будет полностью открытым с фото, видео и конечно же кодом ! 

  Творение мое называется экструдер ! 

  У  меня есть: "Ардуино мега 2560"  

LCD-дисплей + 5 кнопок 

четыре  EPCOS B57560G104F NTC 100k THERMISTOR

четыре твердотельных реле управление 3в-30в

один  драйвер ШД  от pololu А4988

и ШД тоже один 

Как это должно работать:

 

 четыре зоны со спиральными нагревателями (разные диапазоны температуры на всех спиралях). 

Нужно видеть текущую температуру всех четырех датчиков  и заданное значение,

ну и соответственно иметь возможность с помощью кнопок задавать температуру для каждой зоны отдельно. 

 на экране что-то вроде этого  "1Т 150°с/160°с" "2Т 200°с./210°"                  

                                                     "3Т 230°с/250°с" "4Т 275°с./280°"

  Ну а третьей строкой управление  ШД,  нужны только обороты.                            

Я  взял готовый похожий скетч и пытаюсь доточить его под свои нужды . Сейчас работаю на тем, чтобы вкрутить в этот скетч свой датчик (EPCOS B57560G104F NTC 100k THERMISTOR). Вроде  много чего перечитал, а прикрутить не получается. Может не там читал ? 

Ниже прилагаю сам скетч. Заранее благодарю.

// Подключаем библиотеку для работы с шиной OneWire
// Термометр будет подключен на Pin2
#include <OneWire.h>
OneWire oneWire(2);

//Подключаем библиотеку для работы с термометром
#include <DallasTemperature.h>

//Создаем объект sensors, подключенный по OneWire
DallasTemperature sensors(&oneWire);

//Создаем переменные для работы с термометром
DeviceAddress tempDeviceAddress;  //переменная для хранения адреса датчика
float temp1=0; //переменная для текущего значения температуры
int setTmp=0; // переменная для заданного значения температуры

//Подключаем LCD-дисплей
#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

//Подсветка управляется через пин D10
#define BACKLIGHT_PIN 10

//Создаем переменную для хранения состояния подсветки
boolean backlightStatus = 1;

// Подключаем библиотеку для работы с ARDUINO EEPROM
//Заданная температура будет храниться по адресу 0
#include <EEPROM2.h>

//Реле подключено к пину D11
#define RELAY_PIN 11

//Объявим переменную для хранения состояния реле
boolean relayStatus1=LOW;

//Объявим переменные для задания задержки
long previousMillis1 = 0;
long interval1 = 1000; // интервал опроса датчиков температуры

//Аналоговая клавиатура подключена к пину A0
#define KEYPAD_PIN A0
//Определим значения на аналоговом входе для клавиатуры 
#define ButtonUp_LOW 90
#define ButtonUp_HIGH 100
#define ButtonDown_LOW 240
#define ButtonDown_HIGH 280
#define ButtonLeft_LOW 390
#define ButtonLeft_HIGH 450
#define ButtonRight_LOW 0
#define ButtonRight_HIGH 50
#define ButtonSelect_LOW 620
#define ButtonSelect_HIGH 650

void setup() {

//Настроим пин для управления реле
  pinMode(RELAY_PIN,OUTPUT);
  digitalWrite(RELAY_PIN,LOW);

//Считаем из постоянной памяти заданную температуру
  setTmp=EEPROM_read_byte(0);

//Инициализируем термодатчик и установим разрешающую способность 12 бит (обычно она установлена по умолчанию, так что последнюю строчку можно опустить)
  sensors.begin();
  sensors.getAddress(tempDeviceAddress, 0);
  sensors.setResolution(12);
    
//Настроим подсветку дисплея
  pinMode(BACKLIGHT_PIN, OUTPUT);
  digitalWrite(BACKLIGHT_PIN, backlightStatus);

//Выведем на дисплей стартовое сообщение на 2 секунды
  lcd.begin(16, 2);
  lcd.setCursor(0, 0);
  lcd.print("Temp. Controller");
  lcd.setCursor(0, 1);
  lcd.print("      v1.0      ");
  delay(2000);

// выведем на дисплей заданное значение температуры на 2 секунды
  lcd.setCursor(0, 1);
  lcd.print("  Set temp:     ");
  lcd.setCursor(12,1);
  lcd.print(setTmp);
  delay(2000);

//Очистим дисплей
  lcd.begin(16, 2);
}



//Определим функцию для опроса аналоговой клавиатуры
//Функция опроса клавиатуры, принимает адрес пина, к которому подключена клавиатура, и возвращает код клавиши:
// 1 - UP
// 2 - DOWN
// 3 - LEFT
// 4 - RIGHT
// 5 - SELECT

int ReadKey(int keyPin)
{
 int KeyNum=0;
 int KeyValue1=0;
 int KeyValue2=0;

//Читаем в цикле аналоговый вход, для подавления дребезга и нестабильности читаем по два раза подряд, пока значения не будут равны.
//Если значения равны 1023 – значит не была нажата ни  одна клавиша.

do {
KeyValue1=analogRead(keyPin);
 KeyValue2=analogRead(keyPin);
 } while (KeyValue1==KeyValue2&&KeyValue2!=1023);

//Интерпретируем полученное значение и определяем код нажатой клавиши
 if (KeyValue2<ButtonUp_HIGH&&KeyValue2>ButtonUp_LOW) {KeyNum=1;}//Up
 if (KeyValue2<ButtonDown_HIGH&&KeyValue2>ButtonDown_LOW) {KeyNum=2;}//Down
 if (KeyValue2<ButtonLeft_HIGH&&KeyValue2>ButtonLeft_LOW) {KeyNum=3;}//Left
 if (KeyValue2<ButtonRight_HIGH&&KeyValue2>ButtonRight_LOW) {KeyNum=4;}//Right
 if (KeyValue2<ButtonSelect_HIGH&&KeyValue2>ButtonSelect_LOW) {KeyNum=5;}//Select

//Возвращаем код нажатой клавиши
return KeyNum;
}

//Определим процедуру редактирования заданной температуры
//Вызывается по нажатию клавиши Select, отображает на дисплее заданную температуру и позволяет изменять ее клавишами Up и Down

void setTemperature() {

  int keyCode=0;

//выводим на дисплей заданное значение температуры  
  lcd.begin(16,2);
  lcd.setCursor(0, 0);
  lcd.print("  Setting temp  ");
  lcd.setCursor(7, 1);
  lcd.print(setTmp);

//Опрашиваем клавиатуру, если нажата клавиша Up увеличиваем значение на 1, если Down – уменьшаем на 1
//Если нажаты клавиши Select или Right – цикл опроса прерывается
//Задержки введены для борьбы с дребезгом, если клавиши срабатывают четко – можно уменьшить время задержек или вообще их убрать
do {
  keyCode=ReadKey(KEYPAD_PIN);
  if (keyCode==1){setTmp++;delay(200);lcd.setCursor(7, 1);lcd.print(setTmp);}
  if (keyCode==2){setTmp--;delay(200);lcd.setCursor(7, 1);lcd.print(setTmp);}
} while (keyCode!=5 && keyCode!=4);
  delay(200);

//По клавише Select – созраняем в EEPROM измененное значение
//По клавише Right – восстанавливаем старое значение
if (keyCode==5) {EEPROM_write_byte(0, setTmp);}
if (keyCode==4) {setTmp = EEPROM_read_byte(0);}
}

void loop() {

//Модуль опроса датчиков и получения сведений о температуре
//Вызывается 1 раз в секунду
  unsigned long currentMillis1 = millis();
if(currentMillis1 - previousMillis1 > interval1) {
    previousMillis1 = currentMillis1;  

//Запуск процедуры измерения температуры
  sensors.setWaitForConversion(false);
  sensors.requestTemperatures();
  sensors.setWaitForConversion(true);

Delay(750) // задержка для обработки информации внутри термометра, в данном случае можно не задавать

//Считывание значения температуры
  sensors.getAddress(tempDeviceAddress, 0);
  temp1=sensors.getTempC(tempDeviceAddress);

// Вывод текущего значения температуры на дисплей
  lcd.setCursor(0, 0);
  lcd.print("  Current temp  ");
  lcd.setCursor(5, 1);
  lcd.print(temp1);
//  Serial.println(temp1,4);
}

//Проверка условия включения/выключения нагревателя
if (temp1<setTmp&&relayStatus1==LOW){relayStatus1=HIGH; digitalWrite(RELAY_PIN,HIGH);}
if (temp1>setTmp&&relayStatus1==HIGH){relayStatus1=LOW; digitalWrite(RELAY_PIN,LOW);}

// Опрос клавиатуры 
int Feature = ReadKey(KEYPAD_PIN);
if (Feature==1 ) {backlightStatus=1;digitalWrite(BACKLIGHT_PIN, backlightStatus);} //Включение подсветки
if (Feature==2 ) {backlightStatus=0;digitalWrite(BACKLIGHT_PIN, backlightStatus);} //Отключение подсветки
if (Feature==5 ) {delay(200);setTemperature();} //Переход к редактированию заданной температуры
}

 

 

Andrey_Y_Ostanovsky
Offline
Зарегистрирован: 03.12.2012

//Проверка условия включения/выключения нагревателя

НИже должен идти Ваш код сравнения данных, считанных с делителя на NTC с заданными эталонными значениями. А все, что про Dallas DS18B20 - можно закомментировать. Хотя по-мне, так проще купить (даже по $2)  далласовские цифровые термометры.

SONIC300077
Offline
Зарегистрирован: 15.10.2013

 Не проблема купить, Я не нашел датчиков с диапазоном температуры  0 до 300 г с 

SONIC300077
Offline
Зарегистрирован: 15.10.2013

Andrey_Y_Ostanovsky пишет:

//Проверка условия включения/выключения нагревателя

НИже должен идти Ваш код сравнения данных, считанных с делителя на NTC с заданными эталонными значениями. 

вот этот код 

#define THERMISTORTABLE0  {\

  {1*4,864*8},{21*4,300*8},{25*4,290*8},{29*4,280*8},{33*4,270*8},{39*4,260*8},{46*4,250*8},{54*4,240*8},{64*4,230*8},{75*4,220*8},\
  {90*4,210*8},{107*4,200*8},{128*4,190*8},{154*4,180*8},{184*4,170*8},{221*4,160*8},{265*4,150*8},{316*4,140*8},{375*4,130*8},\
  {441*4,120*8},{513*4,110*8},{588*4,100*8},{734*4,80*8},{856*4,60*8},{938*4,40*8},{986*4,20*8},{1008*4,0*8},{1018*4,-20*8} }
 
если незатруднит можно по подробнее .

Andrey_Y_Ostanovsky
Offline
Зарегистрирован: 03.12.2012

SONIC300077 пишет:

#define THERMISTORTABLE0  {\

  {1*4,864*8},{21*4,300*8},{25*4,290*8},{29*4,280*8},{33*4,270*8},{39*4,260*8},{46*4,250*8},{54*4,240*8},{64*4,230*8},{75*4,220*8},\
  {90*4,210*8},{107*4,200*8},{128*4,190*8},{154*4,180*8},{184*4,170*8},{221*4,160*8},{265*4,150*8},{316*4,140*8},{375*4,130*8},\
  {441*4,120*8},{513*4,110*8},{588*4,100*8},{734*4,80*8},{856*4,60*8},{938*4,40*8},{986*4,20*8},{1008*4,0*8},{1018*4,-20*8} }
 
если незатруднит можно по подробнее .

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

SONIC300077
Offline
Зарегистрирован: 15.10.2013

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

SONIC300077
Offline
Зарегистрирован: 15.10.2013

Ну вот поначалу отчаялся помогать особо некому  «да и мне некогда» но ничего русские просто так не сдаются пару дней с бубном шаманские свистопляски с макеткой и скетчем (не одним) вот слепил. «УРА ЗАРАБОТАЛО» да удовольствие незабываемое, многое стало понятней! Если нетрудно посмотрите на то что я слепил ! а то мне еще три датчика как то надо сюда  воткнуть может что посоветуете ?  

/*Моя первая реальная  программа SONIC300077!
Создана методом научного тыка  )) 18,10,2013  22:54
*/

#include <LiquidCrystal.h>
#include <math.h>
#include <OneWire.h>
#include <EEPROM2.h>


float temp1=0; //переменная для текущего значения температуры
int setTmp=0; // переменная для заданного значения температуры

LiquidCrystal lcd(8, 9, 4, 5, 6, 7); //Подключаем LCD-дисплей
#define BACKLIGHT_PIN 10   //Подсветка управляется через пин D10
boolean backlightStatus = 1; //Создаем переменную для хранения состояния подсветки

#define RELAY_PIN 53  //Реле подключено к пину D11
boolean relayStatus1=LOW;    //Объявим переменную для хранения состояния реле

//Аналоговая клавиатура подключена к пину A0
#define KEYPAD_PIN A0  
//Определим значения на аналоговом входе для клавиатуры 
#define ButtonUp_LOW 130
#define ButtonUp_HIGH 150
#define ButtonDown_LOW 300
#define ButtonDown_HIGH 350
#define ButtonLeft_LOW 490
#define ButtonLeft_HIGH 520
#define ButtonRight_LOW 0
#define ButtonRight_HIGH 50
#define ButtonSelect_LOW 700
#define ButtonSelect_HIGH 780

void setup() {

  //Настроим подсветку дисплея
  pinMode(BACKLIGHT_PIN, OUTPUT);
  digitalWrite(BACKLIGHT_PIN, backlightStatus);


  //Настроим пин для управления реле
  pinMode(RELAY_PIN,OUTPUT);
  digitalWrite(RELAY_PIN,LOW);

  //Считаем из постоянной памяти заданную температуру
  setTmp=EEPROM_read_byte(0);

  //Выведем на дисплей стартовое сообщение на 2 секунды
  lcd.begin(20, 4 );
  lcd.setCursor(0, 0);
  lcd.print("Temp. Controller");
  lcd.setCursor(0, 1);
  lcd.print("      v1.0      ");
  delay(2000);

  // выведем на дисплей заданное значение температуры на 2 секунды
  lcd.setCursor(0, 1);
  lcd.print("  Set temp:     ");
  lcd.setCursor(12,1);
  lcd.print(setTmp);
  delay(2000);

  //Очистим дисплей
  lcd.begin(20, 4);
}

double Thermister(int RawADC) {
  double Temp;
  // See http://en.wikipedia.org/wiki/Thermistor for explanation of formula
  Temp = log(((10240000/RawADC) - 10000));
  Temp = 1 / (0.001129148 + (0.000234125 * Temp) + (0.0000000876741 * Temp * Temp * Temp));
  Temp = Temp - 273.15;           // Convert Kelvin to Celcius
  return Temp;
}

//Определим функцию для опроса аналоговой клавиатуры
//Функция опроса клавиатуры, принимает адрес пина, к которому подключена клавиатура, и возвращает код клавиши:
// 1 - UP
// 2 - DOWN
// 3 - LEFT
// 4 - RIGHT
// 5 - SELECT

int ReadKey(int keyPin)
{
 int KeyNum=0;
 int KeyValue1=0;
 int KeyValue2=0;

//Читаем в цикле аналоговый вход, для подавления дребезга и нестабильности читаем по два раза подряд, пока значения не будут равны.
//Если значения равны 1023 – значит не была нажата ни  одна клавиша.
do {
KeyValue1=analogRead(keyPin);
 KeyValue2=analogRead(keyPin);
 } while (KeyValue1==KeyValue2&&KeyValue2!=1023);

//Интерпретируем полученное значение и определяем код нажатой клавиши
 if (KeyValue2<ButtonUp_HIGH&&KeyValue2>ButtonUp_LOW) {KeyNum=1;}//Up
 if (KeyValue2<ButtonDown_HIGH&&KeyValue2>ButtonDown_LOW) {KeyNum=2;}//Down
 if (KeyValue2<ButtonLeft_HIGH&&KeyValue2>ButtonLeft_LOW) {KeyNum=3;}//Left
 if (KeyValue2<ButtonRight_HIGH&&KeyValue2>ButtonRight_LOW) {KeyNum=4;}//Right
 if (KeyValue2<ButtonSelect_HIGH&&KeyValue2>ButtonSelect_LOW) {KeyNum=5;}//Select

//Возвращаем код нажатой клавиши
return KeyNum;
}

void setTemperature() {

  int keyCode=0;

//выводим на дисплей заданное значение температуры  
  lcd.begin(20,4);
  lcd.setCursor(0, 0);
  lcd.print("  Setting temp  ");
  lcd.setCursor(7, 1);
  lcd.print(setTmp);

//Опрашиваем клавиатуру, если нажата клавиша Up увеличиваем значение на 1, если Down – уменьшаем на 1
//Если нажаты клавиши Select или Right – цикл опроса прерывается
//Задержки введены для борьбы с дребезгом, если клавиши срабатывают четко – можно уменьшить время задержек или вообще их убрать
do {
  keyCode=ReadKey(KEYPAD_PIN);
  if (keyCode==1){setTmp++;delay(200);lcd.setCursor(7, 1);lcd.print(setTmp);}
  if (keyCode==2){setTmp--;delay(200);lcd.setCursor(7, 1);lcd.print(setTmp);}
} while (keyCode!=5 && keyCode!=4);
  delay(200);
  
  //По клавише Select – созраняем в EEPROM измененное значение
  //По клавише Right – восстанавливаем старое значение
  if (keyCode==5) {EEPROM_write_byte(0, setTmp);}
  if (keyCode==4) {setTmp = EEPROM_read_byte(0);}
}


void loop() {
  double temp = Thermister(analogRead(7));  // Read sensor
  lcd.setCursor(0, 0);
  lcd.print("  Current temp  ");
  lcd.setCursor(5, 1);
  lcd.print(temp);
 
  //Проверка условия включения/выключения нагревателя
  if (temp<setTmp&&relayStatus1==LOW){relayStatus1=HIGH; digitalWrite(RELAY_PIN,HIGH);}
  if (temp>setTmp&&relayStatus1==HIGH){relayStatus1=LOW; digitalWrite(RELAY_PIN,LOW);}


  // Опрос клавиатуры 
  int Feature = ReadKey(KEYPAD_PIN);
  if (Feature==1 ) {backlightStatus=1;digitalWrite(BACKLIGHT_PIN, backlightStatus);} //Включение подсветки
  if (Feature==2 ) {backlightStatus=0;digitalWrite(BACKLIGHT_PIN, backlightStatus);} //Отключение подсветки
  if (Feature==5 ) {delay(200);setTemperature();} //Переход к редактированию заданной температуры
}

             

SONIC300077
Offline
Зарегистрирован: 15.10.2013

Я закончил сегодня скетч ! если нетрудно мне нужна оценка  , критика и.т.д!!

Вот код:

#include <EEPROM2.h>
#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
#include <TimerOne.h>
//переменная для текущего значения температуры
// переменная для заданного значения температуры
float temp1=0;
int setTmp1=0;

float temp2=0;
int setTmp2=0;

float temp3=0;
int setTmp3=0;

float temp4=0;
int setTmp4=0;

#define RELAY1_PIN 31  //Реле подключено к пину D53
boolean relayStatus1=LOW;  //Объявим переменную для хранения состояния реле

#define RELAY2_PIN 33  //Реле подключено к пину D52
boolean relayStatus2=LOW;  //Объявим переменную для хранения состояния реле

#define RELAY3_PIN 35   //Реле подключено к пину D51
boolean relayStatus3=LOW;   //Объявим переменную для хранения состояния реле

#define RELAY4_PIN 37   //Реле подключено к пину D50
boolean relayStatus4=LOW; //Объявим переменную для хранения состояния реле

//Аналоговая клавиатура подключена к пину A8
#define KEYPAD_PIN A8  
//Определим значения на аналоговом входе для клавиатуры 
#define ButtonT1Up_LOW 170
#define ButtonT1Up_HIGH 190
#define ButtonT1Down_LOW 300
#define ButtonT1Down_HIGH 315
#define ButtonT2Up_LOW 345
#define ButtonT2Up_HIGH 365
#define ButtonT2Down_LOW 430
#define ButtonT2Down_HIGH 445
#define ButtonSelect_LOW 490
#define ButtonSelect_HIGH 515
#define ButtonT3Up_LOW 670
#define ButtonT3Up_HIGH 686
#define ButtonT3Down_LOW 690
#define ButtonT3Down_HIGH 710
#define ButtonT4Up_LOW 735
#define ButtonT4Up_HIGH 750
#define ButtonT4Down_LOW 790
#define ButtonT4Down_HIGH 810
#define ButtonRight_LOW 940
#define ButtonRight_HIGH 960


// buttons code 
#define btnRIGHT  0
#define btnUP     1
#define btnDOWN   2
#define btnLEFT   3
#define btnSELECT 4
#define btnNONE   5


// directions
#define FORWARD   HIGH
#define BACKWARD  LOW

// debounce time (milliseconds)
#define DEBOUNCE_TIME  200

// PINs for Pololu controller
#define PIN_STEP  51

#define PIN_DIR   52

// lookup table speed - ticks (interrupts)
const int speed_ticks[] = {-1, 600, 300, 200, 150, 120,100, 86, 75, 67, 60, 55, 50, 46, 43};


int actual_speed;
int actual_direction;

int ticks;
int tick_count;

int button;
boolean debounce;
unsigned long previous_time;

// custom LCD square symbol for progress bar
byte square_symbol[8] = {
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  };

// string constants
char forward_arrow[] = "->->->";
char backward_arrow[] = "<-<-<-";


void setup() {
  
  //Настроим пин для управления реле
  pinMode(RELAY1_PIN,OUTPUT);
  digitalWrite(RELAY1_PIN,LOW);
  
  pinMode(RELAY2_PIN,OUTPUT);
  digitalWrite(RELAY2_PIN,LOW);
  
  pinMode(RELAY3_PIN,OUTPUT);
  digitalWrite(RELAY3_PIN,LOW);
  
  pinMode(RELAY4_PIN,OUTPUT);
  digitalWrite(RELAY4_PIN,LOW);
  
  setTmp1=EEPROM_read_byte(0);
  setTmp2=EEPROM_read_byte(1);
  setTmp3=EEPROM_read_byte(2);
  setTmp4=EEPROM_read_byte(3);
  
  
//Выведем на дисплей стартовое сообщение на 2 секунды
  lcd.begin(20, 4 );
  lcd.setCursor(0, 0);
  lcd.print("  Controller Temp. ");
  lcd.setCursor(0, 1);
  lcd.print("     OOO Sputnik   ");
  lcd.setCursor(0, 2);
  lcd.print("         v2.2      ");
  delay(3000);

 // выведем на дисплей заданное значение температуры на 2 секунды
  lcd.setCursor(0, 0);
  lcd.print("  Set temp1:    ");
  lcd.setCursor(16,0);
  lcd.print(setTmp1);
  
  lcd.setCursor(0, 1);
  lcd.print("  Set temp2:    ");
  lcd.setCursor(16,1);
  lcd.print(setTmp2); 
  
  lcd.setCursor(0, 2);
  lcd.print("  Set temp3:    ");
  lcd.setCursor(16,2);
  lcd.print(setTmp3);
  
  lcd.setCursor(0, 3);
  lcd.print("  Set temp4:    ");
  lcd.setCursor(16,3);
  lcd.print(setTmp4);
  
  delay(2000);
 
 //////////////////////////////
  // init the timer1, interrupt every 0.1ms
  Timer1.initialize(100);
  Timer1.attachInterrupt(timerIsr);
  
  // init LCD and custom symbol  
  lcd.begin(20, 4);
  lcd.setCursor(0,3);
  lcd.createChar(0, square_symbol);
  
  // pins direction
  pinMode(PIN_STEP, OUTPUT);
  pinMode(PIN_DIR, OUTPUT);
  
  // initial values
  actual_speed = 0;
  actual_direction = FORWARD;
  tick_count = 0;
  ticks = -1;
  debounce = false;

  digitalWrite(PIN_DIR, actual_direction);  
  updateLCD();
}


 double Thermister(int RawADC) {
  double Temp;
  double Temp1;
  // See http://en.wikipedia.org/wiki/Thermistor for explanation of formula
  Temp = log(((10240000/RawADC) - 10000));
  Temp = 1 / (0.001129148 + (0.000234125 * Temp) + (0.0000000876741 * Temp * Temp * Temp));
  Temp = Temp - 273.15;           // Convert Kelvin to Celcius
  return Temp;
}
  
  //Определим функцию для опроса аналоговой клавиатуры
//Функция опроса клавиатуры, принимает адрес пина, к которому подключена клавиатура, и возвращает код клавиши:
// 1 - T1up
// 2 - T1Down
// 3 - LEFT
// 4 - RIGHT
// 5 - SELECT
// 6 - Ok
// 7 - T3up
// 8 _ T3down
// 9 - T4up
int ReadKey(int keyPin)
{
 int KeyNum=0;
 int KeyValue1=0;
 int KeyValue2=0;

//Читаем в цикле аналоговый вход, для подавления дребезга и нестабильности читаем по два раза подряд, пока значения не будут равны.
//Если значения равны 1023 – значит не была нажата ни  одна клавиша.
do {
KeyValue1=analogRead(keyPin);
 KeyValue2=analogRead(keyPin);
 } while (KeyValue1==KeyValue2&&KeyValue2!=1023);

//Интерпретируем полученное значение и определяем код нажатой клавиши
 if (KeyValue2<ButtonT1Up_HIGH&&KeyValue2>ButtonT1Up_LOW) {KeyNum=1;}//T1Up
 if (KeyValue2<ButtonT1Down_HIGH&&KeyValue2>ButtonT1Down_LOW) {KeyNum=2;}//T1Down
 if (KeyValue2<ButtonT2Up_HIGH&&KeyValue2>ButtonT2Up_LOW) {KeyNum=3;}//T2Up
 if (KeyValue2<ButtonT2Down_HIGH&&KeyValue2>ButtonT2Down_LOW) {KeyNum=4;}//T2Down
 if (KeyValue2<ButtonSelect_HIGH&&KeyValue2>ButtonSelect_LOW) {KeyNum=5;}//Select
 if (KeyValue2<ButtonT3Up_HIGH&&KeyValue2>ButtonT3Up_LOW) {KeyNum=6;}//T3up
 if (KeyValue2<ButtonT3Down_HIGH&&KeyValue2>ButtonT3Down_LOW) {KeyNum=7;}//T3Down
 if (KeyValue2<ButtonT4Up_HIGH&&KeyValue2>ButtonT4Up_LOW) {KeyNum=8;}//T3up
 if (KeyValue2<ButtonT4Down_HIGH&&KeyValue2>ButtonT4Down_LOW) {KeyNum=9;}//T3Down
 if (KeyValue2<ButtonRight_HIGH&&KeyValue2>ButtonRight_LOW) {KeyNum=10;}//T3Down
//Возвращаем код нажатой клавиши
return KeyNum;
}
  
  void loop() {
  
    double temp1 = Thermister(analogRead(12));  // Read sensor
  delay(10);
  lcd.setCursor(0, 0);
  lcd.print("1 ");
  //lcd.setCursor(2, 0);
  lcd.print(temp1);
  lcd.print("/");
  lcd.print(setTmp1);
  lcd.print("* ");
  
  
   double temp2 = Thermister(analogRead(13));
  delay(10);
  lcd.setCursor(0, 1);
  lcd.print("2 ");
  lcd.print(temp2);
  lcd.print("/");
  lcd.print(setTmp2);
  lcd.print("* ");
  
   double temp3 = Thermister(analogRead(14));
  delay(10);
  lcd.setCursor(0, 2);
  lcd.print("3 ");
  lcd.print(temp3);
  lcd.print("/");
  lcd.print(setTmp3);
  lcd.print("* ");
  
   double temp4 = Thermister(analogRead(15));
  delay(10);
  lcd.setCursor(0, 3);
  lcd.print("4 ");
  lcd.print(temp1);
  lcd.print("/");
  lcd.print(setTmp4);
  lcd.print("* ");
  
  
  int Feature = ReadKey(KEYPAD_PIN);
  if (Feature==1){setTmp1++;delay(100);lcd.setCursor(8, 0);lcd.print(setTmp1);}
  if (Feature==2){setTmp1--;delay(100);lcd.setCursor(8, 0);lcd.print(setTmp1);}
  if (Feature==3){setTmp2++;delay(100);lcd.setCursor(8, 1);lcd.print(setTmp2);}
  if (Feature==4){setTmp2--;delay(100);lcd.setCursor(8, 1);lcd.print(setTmp2);}
  if (Feature==6){setTmp3++;delay(100);lcd.setCursor(8, 2);lcd.print(setTmp3);}
  if (Feature==7){setTmp3--;delay(100);lcd.setCursor(8, 2);lcd.print(setTmp3);}
  if (Feature==8){setTmp4++;delay(100);lcd.setCursor(8, 3);lcd.print(setTmp4);}
  if (Feature==9){setTmp4--;delay(100);lcd.setCursor(8, 3);lcd.print(setTmp4);}
  
  if (Feature==5) {EEPROM_write_byte(0,setTmp1);}
 if (Feature==5) {EEPROM_write_byte(1,setTmp2);}
 if (Feature==5) {EEPROM_write_byte(2,setTmp3);}
 if (Feature==5) {EEPROM_write_byte(3,setTmp4);}
  
  //Проверка условия включения/выключения нагревателя
  if (temp1<setTmp1&&relayStatus1==LOW){relayStatus1=HIGH; digitalWrite(RELAY1_PIN,HIGH);}
  if (temp1>setTmp1&&relayStatus1==HIGH){relayStatus1=LOW; digitalWrite(RELAY1_PIN,LOW);}
  if (temp2<setTmp2&&relayStatus2==LOW){relayStatus2=HIGH; digitalWrite(RELAY2_PIN,HIGH);}
  if (temp2>setTmp2&&relayStatus2==HIGH){relayStatus2=LOW; digitalWrite(RELAY2_PIN,LOW);}
  if (temp3<setTmp2&&relayStatus3==LOW){relayStatus3=HIGH; digitalWrite(RELAY3_PIN,HIGH);}
  if (temp3>setTmp2&&relayStatus3==HIGH){relayStatus3=LOW; digitalWrite(RELAY3_PIN,LOW);}
  if (temp4<setTmp2&&relayStatus4==LOW){relayStatus4=HIGH; digitalWrite(RELAY4_PIN,HIGH);}
  if (temp4>setTmp2&&relayStatus4==HIGH){relayStatus4=LOW; digitalWrite(RELAY4_PIN,LOW);}
  
  
  
  
  
  // check if debounce active
  if(debounce) {
    button = btnNONE;
    if(millis() > previous_time + DEBOUNCE_TIME) debounce = false;
  } else button = read_buttons();
  
  // if a button is pressed, start debounce time
  if(button != btnNONE) {
    
    previous_time = millis();
    debounce = true;  
  }
    
  // check which button was pressed
  switch(button) {
   
    case btnUP:
      increase_speed();
      break;
    case btnDOWN:
      decrease_speed();
      break;
    case btnLEFT:
      change_direction(BACKWARD);
      break;
    case btnRIGHT:
      change_direction(FORWARD);
      break;
    case btnSELECT:
      emergency_stop();
      break;
  }
  
  // finally update the LCD
  updateLCD();
}

// increase speed if it's below the max (70)
void increase_speed() {
  
  if(actual_speed < 70) {
    actual_speed += 5;
    tick_count = 0;
    ticks = speed_ticks[actual_speed / 5];
  }
}

// decrease speed if it's above the min (0)
void decrease_speed() {
  
  if(actual_speed > 0) {
    actual_speed -= 5;
    tick_count = 0;
    ticks = speed_ticks[actual_speed / 5];
  }
}

// change direction if needed
void change_direction(int new_direction) {
  
  if(actual_direction != new_direction) {
    actual_direction = new_direction;
    digitalWrite(PIN_DIR, actual_direction);
  }
}

// emergency stop: speed 0
void emergency_stop() {
  actual_speed = 0;
  tick_count = 0;
  ticks = speed_ticks[actual_speed / 5];
}

// update LCD
void updateLCD() {
  
  // print first line:
  // Speed: xxxRPM --> (or <--)
  lcd.setCursor(14,0);
  lcd.print("R: ");
    lcd.print(actual_speed);
    lcd.print("' ");
  lcd.setCursor(14,2);
  lcd.print("Speed:");

  lcd.setCursor(14,1);
  if(actual_direction == FORWARD) lcd.print(forward_arrow);
  else lcd.print(backward_arrow);
  
  // print second line:
  // progress bar [#####         ]
  // 15 speed steps: 0 - 5 - 10 - ... - 70
  lcd.setCursor(14,3);
  lcd.print("[");
  
  for(int i = 1; i <= 4; i++) {
    
    if(actual_speed > (14 * i) - 1) lcd.write(byte(0));
    else lcd.print(" ");
  }
  
  lcd.print("]");
}

// timer1 interrupt function
void timerIsr() {

  if(actual_speed == 0) return;
  
  tick_count++;
  
  if(tick_count == ticks) {  
    
    // make a step
    digitalWrite(PIN_STEP, HIGH);
    digitalWrite(PIN_STEP, LOW);
    
    tick_count = 0;
  }
}




// read buttons connected to a single analog pin
int read_buttons() {
  
 int adc_key_in = analogRead(0);
 
if (adc_key_in > 1000) return btnNONE;
 if (adc_key_in < 50)   return btnRIGHT;  
 if (adc_key_in < 195)  return btnUP; 
 if (adc_key_in < 380)  return btnDOWN; 
 if (adc_key_in < 555)  return btnLEFT; 
 if (adc_key_in < 790)  return btnSELECT; 
 }