#include <Adafruit_GFX.h> // Core graphics library
//#include <Adafruit_ST7735.h> // Hardware-specific library for ST7735
#include "Adafruit_ILI9341.h"
#include <SPI.h>
// #include <U8glib.h> // https://github.com/olikraus/u8glib
#include <PID_v1.h> // https://github.com/wagiminator/ATmega-Soldering-Station/blob/master/software/libraries/Arduino-PID-Library.zip
// (старая версия cpp https://github.com/mblythe86/C-PID-Library/tree/master/PID_v1)
#include <EEPROM.h> // для сохранения пользовательских настроек в EEPROM
#include <avr/sleep.h> // для ожидания во время выборки АЦП
// Новые определения цвета
#define TFT_BLACK 0x0000 /* 0, 0, 0 */
#define TFT_NAVY 0x000F /* 0, 0, 128 */
#define TFT_DARKGREEN 0x03E0 /* 0, 128, 0 */
#define TFT_DARKCYAN 0x03EF /* 0, 128, 128 */
#define TFT_MAROON 0x7800 /* 128, 0, 0 */
#define TFT_PURPLE 0x780F /* 128, 0, 128 */
#define TFT_OLIVE 0x7BE0 /* 128, 128, 0 */
#define TFT_LIGHTGREY 0xC618 /* 192, 192, 192 */
#define TFT_DARKGREY 0x7BEF /* 128, 128, 128 */
#define TFT_BLUE 0x001F /* 0, 0, 255 */
#define TFT_GREEN 0x07E0 /* 0, 255, 0 */
#define TFT_CYAN 0x07FF /* 0, 255, 255 */
#define TFT_RED 0xF800 /* 255, 0, 0 */
#define TFT_MAGENTA 0xF81F /* 255, 0, 255 */
#define TFT_YELLOW 0xFFE0 /* 255, 255, 0 */
#define TFT_WHITE 0xFFFF /* 255, 255, 255 */
#define TFT_ORANGE 0xFD20 /* 255, 165, 0 */
#define TFT_GREENYELLOW 0xAFE5 /* 173, 255, 47 */
#define TFT_PINK 0xF81F
#include <GyverEncoder.h>
//Encoder enc(2, 3, 4); // uno - для работы c кнопкой. CLK, DT, SW
//Encoder enc(7, 8, 6); // nano - для работы c кнопкой. CLK, DT, SW
Encoder enc(A3, A2, A1); // nano - для работы c кнопкой. CLK, DT, SW
// software SPI:
/*
#define TFT_CS 4 // CS Chip select control pin
#define TFT_DC 3 // DC Data Command control pin
#define TFT_RST 2 // RES Reset pin (could connect to Arduino RESET pin)
#define TFT_MOSI 11 // SDA
#define TFT_CLK 13 // SCL
*/
#define TFT_CS 9 // CS 1,77 TFT; CS 2,4 TFT; CS 2,8 TFT - This is the TFT CS (chip select pin). - Chip select control pin - это контакт выбора чипа TFT SPI
#define TFT_DC 8 // DC 1,77 TFT; DC 2,4 TFT; ; D/C 2,8 TFT - This is the TFT DC (data/command select) pin. - Data Command control pin - это вывод данных TFT SPI или селектора команд
#define TFT_RST 7 // RES 1,77 TFT; RESET 2,4 TFT; RST 2,8 TFT - Reset pin (could connect to Arduino RESET pin) - это контакт сброса TFT
#define TFT_MOSI 11 // SDA 1,77 TFT; SDI(MOSI) 2,4 TFT; MOSI 2,8 TFT - ICSP MOSI - This is the hardware SPI Microcontroller Out Serial In pin. - PI Microcontroller Out Serial In, он используется для отправки данных с микроконтроллера на SD-карту и/или TFT
#define TFT_MISO 12 // ICSP MISO - This is the hardware SPI Microcontroller In Serial Out pin.
#define TFT_CLK 13 // SCL 1,77 TFT; SDO(MISO) 2,4 TFT; SCK 2,8 TFT - ICSP SCLK - This is the hardware SPI clock pin.
/* // ESP32
#define TFT_CS 15 // CS 1,77 TFT; CS 2,4 TFT; CS 2,8 TFT - This is the TFT CS (chip select pin). - Chip select control pin - это контакт выбора чипа TFT SPI
#define TFT_DC 2 // DC 1,77 TFT; DC 2,4 TFT; ; D/C 2,8 TFT - This is the TFT DC (data/command select) pin. - Data Command control pin - это вывод данных TFT SPI или селектора команд
#define TFT_RST 4 // RES 1,77 TFT; RESET 2,4 TFT; RST 2,8 TFT - Reset pin (could connect to Arduino RESET pin) - это контакт сброса TFT
#define TFT_MOSI 18 // SDA 1,77 TFT; SDI(MOSI) 2,4 TFT; MOSI 2,8 TFT - ICSP MOSI - This is the hardware SPI Microcontroller Out Serial In pin. - PI Microcontroller Out Serial In, он используется для отправки данных с микроконтроллера на SD-карту и/или TFT
#define TFT_MISO 23 // ICSP MISO - This is the hardware SPI Microcontroller In Serial Out pin.
//#define TFT_CLK 13 // SCL 1,77 TFT; SDO(MISO) 2,4 TFT; SCK 2,8 TFT - ICSP SCLK - This is the hardware SPI clock pin.
*/
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);
// Тип поворотного энкодера
#define ROTARY_TYPE 1 // 0: 2 приращения/шаг; 1: 4 приращения/шаг (по умолчанию)
// Пины
#define SENSOR_PIN A0 // датчик температуры наконечника
#define VIN_PIN A1 // датчик входного напряжения
#define BUZZER_PIN 5 // зуммер
#define ROTARY_1_PIN 2 //7 // поворотный энкодер 1
#define ROTARY_2_PIN 3 //8 // поворотный энкодер 2
#define BUTTON_PIN 4 //6 // переключатель поворотного энкодера
#define CONTROL_PIN 6 //9 // ШИМ-управление МОП-транзистором нагревателя
#define SWITCH_PIN 10 // датчик вибрации в ручке паяльника
// Значения контроля температуры по умолчанию (рекомендуемая температура пайки: 300-380°C)
#define TEMP_MIN 150 // минимальная выбираемая температура
#define TEMP_MAX 400 // максимальная выбираемая температура
#define TEMP_DEFAULT 320 // начальная уставка по умолчанию
#define TEMP_SLEEP 150 // температура в спящем режиме
#define TEMP_BOOST 50 // повышение температуры в режиме форсирования (boost)
#define TEMP_STEP 10 // шаги изменения температуры поворотного энкодера
// Значения калибровки температуры жала по умолчанию
#define TEMP200 216 // температура при ADC = 200
#define TEMP280 308 // температура при ADC = 280
#define TEMP360 390 // температура при ADC = 360
#define TEMPCHP 30 // температура чипа при калибровке
#define TIPMAX 8 // максимальное количество жал
#define TIPNAMELENGTH 6 // максимальная длина имен жал (включая окончание)
#define TIPNAME "BC1.5" // имя жала по умолчанию
// Значения таймера по умолчанию (0 = отключено)
#define TIME2SLEEP 5 // время перехода в спящий режим, в минутах
#define TIME2OFF 15 // время отключения нагревателя, в минутах
#define TIMEOFBOOST 40 // время пребывания в режиме boost, в секундах
// Контрольные значения
#define TIME2SETTLE 950 // время в микросекундах, необходимое для установления выходного сигнала операционного усилителя
#define SMOOTHIE 0.05 // коэффициент сглаживания выходного сигнала операционного усилителя (1 = без сглаживания; 0,05 по умолчанию)
#define PID_ENABLE false // включить ПИД-управление
#define BEEP_ENABLE true // включить/отключить зуммер
#define BODYFLIP false // включить/выключить переворот экрана
#define ECREVERSE false // включение/выключение реверса поворотного энкодера
#define MAINSCREEN 0 // тип основного экрана (0: большие числа; 1: больше информации)
// идентификатор EEPROM
#define EEPROM_IDENT 0xE76C // чтобы определить, была ли EEPROM записана этой программой
// Определения управления MOSFET
#if defined(P_MOSFET) // P-Канальный MOSFET
#define HEATER_ON 255
#define HEATER_OFF 0
#define HEATER_PWM 255 - Output
#elif defined(N_MOSFET) // N-Канальный MOSFET
#define HEATER_ON 0
#define HEATER_OFF 255
#define HEATER_PWM Output
#else
//#error Wrong MOSFET type!
#endif
// Назначим агрессивные и консервативные параметры настройки ПИД-регулятора.
double aggKp = 11, aggKi = 0.5, aggKd = 1;
double consKp = 11, consKi = 3, consKd = 5;
// Значения по умолчанию, которые могут быть изменены пользователем и сохранены в EEPROM.
uint16_t DefaultTemp = TEMP_DEFAULT;
uint16_t SleepTemp = TEMP_SLEEP;
uint8_t BoostTemp = TEMP_BOOST;
uint8_t time2sleep = TIME2SLEEP;
uint8_t time2off = TIME2OFF;
uint8_t timeOfBoost = TIMEOFBOOST;
uint8_t MainScrType = MAINSCREEN;
bool PIDenable = PID_ENABLE;
bool beepEnable = BEEP_ENABLE;
bool BodyFlip = BODYFLIP;
bool ECReverse = ECREVERSE;
bool isOnOf = false;
bool isButtonEncoderHolded = false;
bool isButtonEncoderClick = false;
// Значения по умолчанию для жал
uint16_t CalTemp[TIPMAX][4] = {TEMP200, TEMP280, TEMP360, TEMPCHP};
char TipName[TIPMAX][TIPNAMELENGTH] = {TIPNAME};
uint8_t CurrentTip = 0;
uint8_t NumberOfTips = 1;
// Пункты меню
const char *SetupItems[] = {"Setup Menu", "Tip Settings", "Temp Settings",
"Timer Settings", "Control Type", "Main Screen",
"Buzzer", "Screen Flip", "EC Reverse", "Information", "My Menu", "Return"
};
const char *TipItems[] = {"Tip:", "Change Tip", "Calibrate Tip",
"Rename Tip", "Delete Tip", "Add new Tip", "Return"
};
const char *TempItems[] = {"Temp Settings", "Default Temp", "Sleep Temp",
"Boost Temp", "Return"
};
const char *TimerItems[] = {"Timer Settings", "Sleep Timer", "Off Timer",
"Boost Temp", "Return"
};
const char *ControlTypeItems[] = {"Control Type", "Direct", "PID"};
const char *MainScreenItems[] = {"Main Screen", "Big Numbers", "More Infos"};
const char *StoreItems[] = {"Store Settings ?", "No", "Yes"};
const char *SureItems[] = {"Are you sure ?", "No", "Yes"};
const char *BuzzerItems[] = {"Buzzer", "Disable", "Enable"};
const char *FlipItems[] = {"Screen Flip", "Disable", "Enable"};
const char *ECReverseItems[] = {"EC Reverse", "Disable", "Enable"};
const char *DefaultTempItems[] = {"Default Temp", "\xB0"
"C"
};
const char *SleepTempItems[] = {"Sleep Temp", "\xB0"
"C"
};
const char *BoostTempItems[] = {"Boost Temp", "\xB0"
"C"
};
const char *SleepTimerItems[] = {"Sleep Timer", "Minutes"};
const char *OffTimerItems[] = {"Off Timer", "Minutes"};
const char *BoostTimerItems[] = {"Boost Timer", "Seconds"};
const char *DeleteMessage[] = {"Warning", "You cannot", "delete your", "last tip!"};
const char *MaxTipMessage[] = {"Warning", "You reached", "maximum number", "of tips!"};
const char *SetupItems1[] = {"Setup Menu", "01. Standby", "02. Sleep",
"03. Boost", "04. Cold End Adj", "05. Tip",
"06. Stepping", "07. Password", "08. Screen Saver",
"09. Buzzer", "10. Voltage", "11. LowVol-P",
"12. Power On State", "13. Desolder", "14. Pump set",
"15. Language", "16. Date Time", "17. RTC Adjust",
"18. RTC Init", "19. System Info", "20. Init",
"21. Exit"
};
const char *OnOffItems[] = {"OFF", "ON "};
// Переменные для прерывания смены PIN (Variables for pin change interrupt)
volatile uint8_t a0, b0, c0, d0;
volatile bool ab0;
volatile int count, countMin, countMax, countStep;
volatile bool handleMoved;
// Переменные для контроля температуры
uint16_t SetTemp, ShowTemp, gap, Step;
double Input, Output, Setpoint, RawTemp, CurrentTemp, ChipTemp;
// Переменные для показаний напряжения
uint16_t Vcc, Vin;
// Переменные состояния
bool inSleepMode = false;
bool inOffMode = false;
bool inBoostMode = false;
bool inCalibMode = false;
bool isWorky = true;
bool beepIfWorky = true;
bool TipIsPresent = true;
// Временные переменные
uint32_t sleepmillis;
uint32_t boostmillis;
uint32_t buttonmillis;
uint8_t goneMinutes;
uint8_t goneSeconds;
uint8_t SensorCounter = 255;
// Задаем указатели переменных и начальные параметры настройки ПИД-регулятора.
PID ctrl(&Input, &Output, &Setpoint, aggKp, aggKi, aggKd, REVERSE);
// Переменная размера шрифта вывода информации на экран
int FontSizeSmall = 2; // Для текста малого размера
int FontSizeBig = 8; // Для текста большого размера
// Переменные хранящие состояние действия до его выполнения
volatile bool isTurn = false; // Было ли вращение энкодера
volatile bool isRight = false; // Было ли вращение по часовой стрелке
volatile bool isLeft = false; // Было ли вращение против часовой стрелки
volatile bool isRightH = false; // Было ли вращение по часовой стрелке при удержании кнопки
volatile bool isLeftH = false; // Было ли вращение против часовой стрелке при удержании кнопки
volatile bool isFastR = false; // Было ли быстрое вращение по часовой стрелке
volatile bool isFastL = false; // Было ли быстрое вращение против часовой стрелке
volatile bool isSingle = false; // Было ли нажатие кнопки
volatile bool isClick = false; // Было ли двойное нажатие кнопки
volatile bool isDouble = false; // Было ли долгое удержание кнопки
volatile bool isHolded = false; // Было ли долгое удержание кнопки
int flag = 1;// true;
#define btn_long_push 1000 // Длительность долинного нажатия кнопки
volatile uint8_t lastcomb = 7, enc_state, btn_push = 0;
volatile int enc_rotation = 0, btn_enc_rotate = 0;
volatile boolean btn_press = 0;
volatile uint32_t timer;
void setup () {
// устанавливаем режимы пинов
pinMode(SENSOR_PIN, INPUT);
pinMode(VIN_PIN, INPUT);
pinMode(BUZZER_PIN, OUTPUT);
pinMode(CONTROL_PIN, OUTPUT);
pinMode(ROTARY_1_PIN, INPUT_PULLUP);
pinMode(ROTARY_2_PIN, INPUT_PULLUP);
pinMode(BUTTON_PIN, INPUT_PULLUP);
pinMode(SWITCH_PIN, INPUT_PULLUP);
///////// analogWrite(CONTROL_PIN, HEATER_OFF); // это отключает обогреватель
digitalWrite(BUZZER_PIN, LOW); // должен быть НИЗКИМ, когда зуммер не используется
// настроим АЦП
ADCSRA |= bit(ADPS0) | bit(ADPS1) | bit(ADPS2); // установить предварительный делитель АЦП на 128
ADCSRA |= bit(ADIE); // включить прерывание АЦП
interrupts(); // включить глобальные прерывания
//#define _PR2
// настроить прерывание смены контакта для поворотного энкодера
//#ifdef _PR0
/*PCMSK0 = bit(PCINT0); // Настроить прерывание смены контакта на Pin8
PCICR = bit(PCIE0); // Включить прерывание смены контакта
PCIFR = bit(PCIF0); // Очистить флаг прерывания
//tft.print("000000000");
//#endif
//#ifdef _PR1
PCMSK1 = bit(PCINT1); // Настроить прерывание смены контакта на Pin8
PCICR = bit(PCIE1); // Включить прерывание смены контакта
PCIFR = bit(PCIF1); // Очистить флаг прерывания
//tft.print("1111111111"); */
//#endif
//#ifdef _PR2
PCMSK2 = bit(PCINT2); // Настроить прерывание смены контакта на Pin8
PCICR = bit(PCIE2); // Включить прерывание смены контакта
PCIFR = bit(PCIF2); // Очистить флаг прерывания
//tft.print("22222222222");
//#endif
/*// получить значения по умолчанию из EEPROM
getEEPROM();
// установить переворот экрана
SetFlipTFT();
// считывание напряжения питания в мВ
Vcc = getVCC();
Vin = getVIN();
// читать и устанавливать текущую температуру паяльника
SetTemp = DefaultTemp;
RawTemp = denoiseAnalog(SENSOR_PIN);
ChipTemp = getChipTemp();
calculateTemp();
// включить нагрев, если температура паяльника значительно ниже заданного значения
if ((CurrentTemp + 20) < DefaultTemp)
analogWrite(CONTROL_PIN, HEATER_ON);
*/
// установить диапазон выходного сигнала ПИД-регулятора и запуск ПИД-регулятор.
ctrl.SetOutputLimits(0, 255);
ctrl.SetMode(AUTOMATIC);
// установить начальные значения поворотного энкодера
a0 = PINB & 1;
b0 = PIND >> 7 & 1;
ab0 = (a0 == b0);
setRotary(TEMP_MIN, TEMP_MAX, TEMP_STEP, DefaultTemp);
// сбросить таймер сна
sleepmillis = millis();
tft.begin();
tft.fillScreen(TFT_BLACK);
tft.setRotation(1);
tft.cp437(true);
tft.setTextSize(5);
tft.print("Prerivaniya");
//Активировать прерывание для группы в регистре управления PCICR
PCICR |= 1 << 2;
// Активировать прерывание для конкретного пина в группе.
// Для D03 это бит 3 в группе 2. Ставим его в единичку.
PCMSK2 |= 1 << 3;
// Разрешить прерывания микроконтроллера.
SREG |= 1 << SREG_I; // бит 7
// длинный звуковой сигнал завершения настройки
beep();
beep();
}
void loop() {
}
// издает короткий звуковой сигнал на зуммер
void beep()
{
if (beepEnable)
{
for (uint8_t i = 0; i < 255; i++)
{
digitalWrite(BUZZER_PIN, HIGH);
delayMicroseconds(125);
digitalWrite(BUZZER_PIN, LOW);
delayMicroseconds(125);
}
}
}
// проверить поворотный энкодер; установить температуру, переключить режим форсирования (Boost), соответственно войти в меню настройки
void ROTARYCheck()
{
// установить рабочую температуру в соответствии со значением поворотного энкодера
//SetTemp = getRotary();
/*
buttonmillis = millis();
if (isHolded)
{
beep();
//Serial.println("Долгое нажатие");
SetupScreen();
isHolded = false;
}
if (isClick)
{
beep();
//Serial.println("Нажали кнопку");
inBoostMode = !inBoostMode;
if (inBoostMode)
boostmillis = millis();
handleMoved = true;
isClick = false;
}
*/
// установить рабочую температуру в соответствии со значением поворотного энкодера
SetTemp = getRotary();
// проверить кнопку поворотного энкодера
uint8_t c = digitalRead(BUTTON_PIN);
if (!c && c0) // Если нажата кнопка энкодера
{
beep();
buttonmillis = millis();
while ((!digitalRead(BUTTON_PIN)) && ((millis() - buttonmillis) < 500));
if (((millis() - buttonmillis) >= 500))// || enc.isHolded())
{ // Долгое нажатие кнопки энкодера
//SetupScreen(); //////////////////////
//isHolded = false;
Serial.println("Долгое нажатие кнопки энкодера");
}
else
{ // Одиночное нажатие кнопки энкодера
inBoostMode = !inBoostMode;
if (inBoostMode)
boostmillis = millis();
handleMoved = true;
}
}
c0 = c;
// проверить таймер в режиме boost
if (inBoostMode && timeOfBoost)
{
goneSeconds = (millis() - boostmillis) / 1000;
if (goneSeconds >= timeOfBoost)
{
inBoostMode = false; // остановить режим boost
beep(); // звуковой сигнал, если режим boost закончился
beepIfWorky = true; // звуковой сигнал снова, когда рабочая температура достигнута
}
}
}
// устанавливает начальные значения для поворотного энкодера
void setRotary(int rmin, int rmax, int rstep, int rvalue)
{
countMin = rmin << ROTARY_TYPE;
countMax = rmax << ROTARY_TYPE;
countStep = ECReverse ? -rstep : rstep;
count = rvalue << ROTARY_TYPE;
}
// считывает текущее значение поворотного энкодера
int getRotary()
{
return (count >> ROTARY_TYPE);
}
// Процедура обслуживания прерывания смены контакта для поворотного энкодера
ISR(PCINT0_vect) // Обработчик запросов прерывания от пинов D8..D13
{
uint8_t a = PINB & 1;
uint8_t b = PIND >> 7 & 1;
if (a != a0)
{ // A изменено
a0 = a; Serial.println("PCINT0_vect");
if (b != b0)
{ // B изменено
b0 = b;
count = constrain(count + ((a == b) ? countStep : -countStep), countMin, countMax);
if (ROTARY_TYPE && ((a == b) != ab0))
{
count = constrain(count + ((a == b) ? countStep : -countStep), countMin, countMax);
;
}
ab0 = (a == b);
handleMoved = true;
}
}
}
ISR(PCINT1_vect) // Обработчик запросов прерывания от пинов A0..A5
{
uint8_t a = PINB & 1;
uint8_t b = PIND >> 7 & 1;
if (a != a0)
{ // A изменено
a0 = a; Serial.println("PCINT1_vect");
if (b != b0)
{ // B изменено
b0 = b;
count = constrain(count + ((a == b) ? countStep : -countStep), countMin, countMax);
if (ROTARY_TYPE && ((a == b) != ab0))
{
count = constrain(count + ((a == b) ? countStep : -countStep), countMin, countMax);
;
}
ab0 = (a == b);
handleMoved = true;
}
}
}
ISR(PCINT2_vect) // Обработчик запросов прерывания от пинов D0..D7
{
uint8_t a = PINB & 1;
uint8_t b = PIND >> 7 & 1;
if (a != a0)
{ // A изменено
a0 = a; tft.println("a2");
if (b != b0)
{ // B изменено
b0 = b; tft.println("b2");
count = constrain(count + ((a == b) ? countStep : -countStep), countMin, countMax);
if (ROTARY_TYPE && ((a == b) != ab0))
{
count = constrain(count + ((a == b) ? countStep : -countStep), countMin, countMax);
;
}
ab0 = (a == b);
handleMoved = true;
}
} tft.println("PCINT2_vect");
}