/*
#include <iarduino_RTC.h>
#include <LiquidCrystal_I2C.h>
#include <OneWire.h>
#include <DallasTemperature.h>
*/
#include "configs.h"
#include "lcd.h"
#include "Sensor.h"
#include "motor.h"
#include "PZEM004Tv30.h"
// Режим работы аппарата
eMode modeWork = nonMode;
//крылья ноги и хвосты
eCurMode modeCurWork = modeNull;
//*------------------------------------------------------------
// переменные температуры и мощности
float _temp[SENSOR_COUNT], _power, _voltage, _current, setPower, minPower, maxPower, stepPower;
currentData currentPowerData;
//*-----------------------------------------------------------
// Переменные мощности
volatile int nullCross, setT=2251, minT = 2250, maxT = 1;
val_float powerCurWork[MODE_COUNT][CURMODE_COUNT];
EEManager memPower(powerCurWork);
// Флаги остановки
boolean flagStop = true, flagDef = true, flagPressKey = false;
// Флаг первоначальной инициализации текущего процесса
boolean initMode;
// Переменные времени
uint8_t D, M, Y, h, m, s, W, _h, _m, _s;
// Временные метки работы
uint32_t startTime, curTime, curWTime, timeBeep;
// Температура дефлегматора
float minTempDef, maxTempDef, minTempDefC, maxTempDefC, stepTempDef;
val2_float tempDef[MODE_COUNT][CURMODE_COUNT];
EEManager memDef(tempDef);
// Mотор насоса
int minRPM, maxRPM, stepRPM, currentRPM;
// Управление пикалкой
volatile uint8_t bCnt = 0, bTime = 0;
//------------------------------------------------------------------------------------
//
// Основные установки
//
void setup() {
Serial.begin(115200);
//-----------------------------
// Светодиодики
ledInit();
//-----------------------------
// Монитор
lcdInit();
startTime = getTimeUnix();
//-----------------------------
// Power value settin
setupPower();
//minPower = 0; maxPower = 3000; stepPower = 10;
byte start = memPower.begin(0, EE_KEY);
//-----------------------------
// Temperature deflegmator setting
setupDefTemp();
start = memDef.begin(memPower.nextAddr(), EE_KEY);
//minTempDef = 20.0; maxTempDef = 70.0; minTempDefC = 55.0; maxTempDefC = 60.0; stepTempDef = 1;
//-----------------------------
// Инициализация таймеров
TamersInit();
//-----------------------------
pinMode(pBuzzer, OUTPUT); // пикалка
Buzzer(1);
//-----------------------------
// Установка даты и времени
if (Y <= 17) inputTimeValue("Input date/time:");
do {
modeWork = setupMenu();
}
while (modeWork == nonMode);
//-----------------------------
// подключение прерывания частоты сети
attachInterrupt(0, zerroCross, RISING);
//-----------------------------
// Подключение сенсоров
sensorInit();
// инициализация моторов
// Stepper motor value settings
minRPM =10; maxRPM =150; stepRPM = 1; currentRPM = 9;
//-----------------------------
// Дефлегматор
pPumpInit();
motorInit();
}
//*--------------------------------------------------------------------------------------------
// Инициализация мощности
void setupPower(){
//--------------------- первый перегон
// Разогрев
powerCurWork[firstMode][modeStart].min = 2000;
powerCurWork[firstMode][modeStart].max = 3500;
powerCurWork[firstMode][modeStart].step = 10;
powerCurWork[firstMode][modeStart].value = 3500;
// Головы
powerCurWork[firstMode][modeHead].min = 1000;
powerCurWork[firstMode][modeHead].max = 1700;
powerCurWork[firstMode][modeHead].step = 10;
powerCurWork[firstMode][modeHead].value = 1200;
// Рабочий процесс
powerCurWork[firstMode][modeBody].min = 1200;
powerCurWork[firstMode][modeBody].max = 1800;
powerCurWork[firstMode][modeBody].step = 10;
powerCurWork[firstMode][modeBody].value = 1500;
// Хвосты
powerCurWork[firstMode][modeTail].min = 1500;
powerCurWork[firstMode][modeTail].max = 2500;
powerCurWork[firstMode][modeTail].step = 10;
powerCurWork[firstMode][modeTail].value = 1800;
//--------------------- второй перегон
// Разогрев
powerCurWork[secondMode][modeStart].min = 2000;
powerCurWork[secondMode][modeStart].max = 3500;
powerCurWork[secondMode][modeStart].step = 10;
powerCurWork[secondMode][modeStart].value = 3500;
// Головы
powerCurWork[secondMode][modeHead].min = 1000;
powerCurWork[secondMode][modeHead].max = 1700;
powerCurWork[secondMode][modeHead].step = 10;
powerCurWork[secondMode][modeHead].value = 1200;
// Рабочий процесс
powerCurWork[secondMode][modeBody].min = 1200;
powerCurWork[secondMode][modeBody].max = 1800;
powerCurWork[secondMode][modeBody].step = 10;
powerCurWork[secondMode][modeBody].value = 1500;
// Хвосты
powerCurWork[secondMode][modeTail].min = 1500;
powerCurWork[secondMode][modeTail].max = 2500;
powerCurWork[secondMode][modeTail].step = 10;
powerCurWork[secondMode][modeTail].value = 1800;
//--------------------- НБК
// Разогрев
powerCurWork[continuiusMode][modeStart].min = 2000;
powerCurWork[continuiusMode][modeStart].max = 3500;
powerCurWork[continuiusMode][modeStart].step = 10;
powerCurWork[continuiusMode][modeStart].value = 3500;
// Рабочий процесс
powerCurWork[continuiusMode][modeBody].min = 1200;
powerCurWork[continuiusMode][modeBody].max = 1800;
powerCurWork[continuiusMode][modeBody].step = 10;
powerCurWork[continuiusMode][modeBody].value = 1500;
}
//*--------------------------------------------------------------------------------------------
// Инициализация диапазона температуры дефлегматора
void setupDefTemp(){
// -------------------- первый перегон
// головы
tempDef[firstMode][modeHead].min = 50;
tempDef[firstMode][modeHead].max = 70;
tempDef[firstMode][modeHead].minValue = 63;
tempDef[firstMode][modeHead].maxValue = 65;
tempDef[firstMode][modeHead].step = 1;
// рабочий процесс
tempDef[firstMode][modeBody].min = 50;
tempDef[firstMode][modeBody].max = 75;
tempDef[firstMode][modeBody].minValue = 67;
tempDef[firstMode][modeBody].maxValue = 69;
tempDef[firstMode][modeBody].step = 1;
// хвост
tempDef[firstMode][modeTail].min = 50;
tempDef[firstMode][modeTail].max = 75;
tempDef[firstMode][modeTail].minValue = 68;
tempDef[firstMode][modeTail].maxValue = 70;
tempDef[firstMode][modeTail].step = 1;
// -------------------- второй перегон
// головы
tempDef[secondMode][modeHead].min = 50;
tempDef[secondMode][modeHead].max = 70;
tempDef[secondMode][modeHead].minValue = 63;
tempDef[secondMode][modeHead].maxValue = 65;
tempDef[secondMode][modeHead].step = 1;
// рабочий процесс
tempDef[secondMode][modeBody].min = 50;
tempDef[secondMode][modeBody].max = 75;
tempDef[secondMode][modeBody].minValue = 67;
tempDef[secondMode][modeBody].maxValue = 69;
tempDef[secondMode][modeBody].step = 1;
// хвост
tempDef[secondMode][modeTail].min = 50;
tempDef[secondMode][modeTail].max = 75;
tempDef[secondMode][modeTail].minValue = 68;
tempDef[secondMode][modeTail].maxValue = 70;
tempDef[secondMode][modeTail].step = 1;
}
//*--------------------------------------------------------------------------------------------
// Инициализация таймеров
void TamersInit(){
//------ Timer1 ---------- Таймер задержки времени открытия триака после детектирования нуля (0 триак не откроется)
TCCR1A = 0x00; //
TCCR1B = 0x00; //
TCCR1B = (0 << CS12) | (1 << CS11) | (1 << CS10) | (1 << WGM12); // Тактирование от CLK.
OCR1A = 0; // Верхняя граница счета. Диапазон от 0 до 65535.
// Частота прерываний будет = Fclk/(N*(1+OCR1A))
// где N - коэф. предделителя (1, 8, 64, 256 или 1024)
TIMSK1 |= (1 << OCIE1A) | (1 << TOIE1); // Разрешить прерывание по совпадению и переполнению
//TIMSK1 = 0x00; //запретить прерывания
PORTC &= ~(1 << PORTC0);
flagStop = true;
//------ Timer4 ---------- Настройка таймера 130 Гц чтение энкодера
TCCR4A = 0; // установить регистры в 0
TCCR4B = 0;
// Установка битов CS10 и CS12 на коэффициент деления 1024
TCCR4B |= (1 << CS40) | (1 << CS42);
OCR4A = 120; // установка регистра совпадения
TCCR4B |= (1 << WGM42); // включение в CTC режим
TIMSK4 |= (1 << OCIE4A);
//------ Timer5 ---------- Настройка ШИМ для помпы
TCCR5A = 0; TCCR5B = 0;
TCCR5B |= (1<<CS50); // prescaler 0
ICR5 = 500;
OCR5A = 150;
TCCR5A |= (1<<COM5B1);
TCCR5B |= (1<<WGM53);
}
//*--------------------------------------------------------------------------------------------
// Проверка состояния кнопок и энкодера
// Вызов опроса состояния
//
ISR (TIMER4_COMPA_vect)
{
tick();
if (bCnt > 0) {
if (bTime == 0) PORTG |= (1 << PORTG2);
if (bTime >= TIME_BUZER) {
PORTG &= ~(1 << PORTG2);
bCnt--;
//Serial.printf("bCnt = %u\n", bCnt);
if (bCnt == 0) bTime=1;
}
if ((PORTG >> PORTG2) & 1) {
bTime++;
//Serial.printf("bCnt++ = %u, bTime = %u\n", bCnt, bTime);
}
else {
bTime--;
//Serial.printf("bCnt-- = %u, bTime = %u\n", bCnt, bTime);
}
}
}
//---------------------------------------------------------------------------------------------
//Обработка таймера по совпадению нуля
ISR (TIMER1_COMPA_vect)
{
uint8_t oldSREG = SREG; // запомнинаем были ли включены прерывания
cli();
PORTC |= (1 << PORTC0);
TCNT1 = 65535 - 200; //Импульс включения симистора 65536 - 1 - 4 мкс, 2 - 8 мкс, 3 - 12 мкс и тд
SREG = oldSREG;
}
ISR (TIMER1_OVF_vect) { //timer1 overflow
uint8_t oldSREG = SREG; // запомнинаем были ли включены прерывания
cli();
PORTC &= ~(1 << PORTC0);
TCNT1 = OCR1A + 1;
SREG = oldSREG;
}
//*--------------------------------------------------------------------------------------------
// Прерывангие по пересечениею нуля
//
void zerroCross(){
uint8_t oldSREG = SREG; // запомнинаем были ли включены прерывания
cli();
TCNT1 = 0;
OCR1A = setT;
SREG = oldSREG;
}
//*--------------------------------------------------------------------------------------------
// Бибикалка
//
void Buzzer(uint8_t _cnt){
bCnt = _cnt;
}
unsigned long prevoisMillisLCD, prevoisMillisPW, prevoisMillisT, pmW;
unsigned int nomSensor;
void loop() {
static float _t0, _t1, _t2, _t3, _t4;
//static float _tmpPower;
//Serial.println("loop");
unsigned long thisMillis;
thisMillis = millis();
// Опрос состояния датчика мощности
if (thisMillis - prevoisMillisPW >= 50){
currentPowerData = getPowerMetr();
_power = currentPowerData.power;
prevoisMillisPW = thisMillis;
}
// Опрос датчиков температуры
if (thisMillis - prevoisMillisT >= 100){
_temp[nomSensor] = getTemp(nomSensor);
nomSensor++;
if (nomSensor >= SENSOR_COUNT) nomSensor = 0;
prevoisMillisT = thisMillis;
}
// Прорисовка экрана
if (thisMillis - prevoisMillisLCD >= 1000){
printSensor();
prevoisMillisLCD = thisMillis;
nullCross = 0;
}
//Регулировка мощности
if (flagStop) {
if (setPower != 0){
TIMSK1 |= (1 << OCIE1A) | (1 << TOIE1);
flagStop = false;
//Serial.println(F("Enable intrrupt"));
}
}
else{
if (setPower == 0){
TIMSK1 = 0x00;
PORTC &= ~(1 << PORTC0);
flagStop = true;
//Serial.println(F("Disable intrrupt"));
}
else{
if (TIMSK1 == 0x00) TIMSK1 |= (1 << OCIE1A) | (1 << TOIE1);
if (thisMillis - pmW > 25){
// регулировка мощности
// Уменьшаем мощность
if (_power > setPower + 10) setT++;
// Увеличиваем мощность
if (_power < setPower - 10) setT--;
if (_power > setPower + 10 && _power < setPower - 10) setT = setT;
if (setT > minT) setT = minT;
if (setT < maxT) setT = maxT;
//Serial.printf("setPower = %7.2f, _power = %7.2f, setT = %u\n", setPower, _power, setT);
pmW = thisMillis;
}
}
}
// Вызов меню установки мощности и других параметров
if (!flagPressKey){
if (isHolded()) setupParam();
}
// обработка самогоноварения
if (modeCurWork == 0){ //Мах мощность и разгон для всех
modeCurWork = modeStart;
setPower = maxPower;
setT = maxT;
initMode = false;
}
switch (modeWork) {
case firstMode:
doFirstModeProcess();
break;
case secondMode:
doSecondModeProcess();
break;
case continuiusMode:
doContinuiusModeProcess();
break;
}
/*
// SUPER ALARM !!!!!!!!!
if ( _temp[4] > 55) {
setPower = 0;
}
*/
}
//------------------------------------------------------------------------------------
//
// первый перегон
//
void doFirstModeProcess(){
static boolean flagHeadStart;
uint32_t _timeTemp;
// Управление работой дефлегматора
if (flagDef){
if (_temp[1] > 50) pumpStart();
else {
pumpStop();
fanStop();
}
}
_timeTemp = getTimeUnix(); // временная метка текущего цикла
switch (modeCurWork){
case modeNull:
if (!initMode){
setPower = powerCurWork[modeWork][modeNull].value;
curWTime = getTimeUnix();
}
break;
case modeStart: // разгон аппарата
if (!initMode) {
setPower = powerCurWork[modeWork][modeCurWork].value;
flagStop = false;
curTime = getTimeUnix();
curWTime = curTime;
initMode = true;
onLed(pRed1);
}
// нагрев верхней точки до 70 градусов, переход к режиму отбора голов
if (_temp[2] > 70){
initMode = false;
offLed(pRed1); onLed(pGreen1);
modeCurWork = modeHead;
}
break;
case modeHead:
if (!initMode){
setPower = powerCurWork[modeWork][modeCurWork].value;
curWTime = _timeTemp;
initMode = true;
onLed(pRed2);
flagHeadStart = true;
fanStart();
}
if (_timeTemp - curWTime < 300 ){ // не даем кипеть и ипаряться, выбиваем головы
if (_temp[2] > 75){
setPower = powerCurWork[modeWork][modeCurWork].value - 200;
onLed(pBlue2);
offLed(pGreen2);
fanStart();
}
else{
setPower = powerCurWork[modeWork][modeCurWork].value + 200;
offLed(pBlue2);
onLed(pGreen2);
}
}
else{
// чисто получаем головы при испарении
if (setPower != powerCurWork[modeWork][modeCurWork].value) { // очищаем переменные для извлечения голов
flagHeadStart = false;
setPower = powerCurWork[modeWork][modeCurWork].value;
offLed(pBlue2);
offLed(pGreen2);
}
if (_timeTemp - curWTime > 1200 ){ // Конец времени выпаривания голов
flagPressKey = true;
if (_timeTemp - timeBeep >= TIME_BUZER){
timeBeep = _timeTemp;
Buzzer(2);
}
if (isPress()){
flagPressKey = false; initMode = false;
offLed(pRed2); onLed(pGreen2);
modeCurWork = modeBody;
}
}
}
break;
case modeBody: // Режим извлечения тела
if (!initMode){
setPower = powerCurWork[modeWork][modeCurWork].value;
curWTime = _timeTemp;
initMode = true;
onLed(pRed3);
}
if (_temp[1] > 95.00){ // тестовая хрень работаем по температуре
flagPressKey = true;
if (_timeTemp - timeBeep >= TIME_BUZER){
timeBeep = _timeTemp;
Buzzer(3);
}
if (isPress()){
flagPressKey = false; initMode = false;
offLed(pRed3); onLed(pGreen3);
modeCurWork = modeTail;
}
}
break;
case modeTail:
if (!initMode){
setPower = powerCurWork[modeWork][modeCurWork].value;
curWTime = getTimeUnix();
initMode = true;
onLed(pRed4);
}
if (_temp[1] > 99.00){
flagPressKey = true;
if (_timeTemp - timeBeep >= TIME_BUZER){
timeBeep = _timeTemp;
Buzzer(5);
}
if (isPress()){
flagPressKey = false; initMode = false;
offLed(pRed4); onLed(pGreen4);
modeCurWork = modeNull;
}
}
break;
}
if (!flagHeadStart){
if (flagDef && _temp[3] >= maxTempDefC) fanStart();
if (flagDef && _temp[3] <= minTempDefC) fanStop();
}
}
//------------------------------------------------------------------------------------
//
// Второй перегон
//
void doSecondModeProcess(){
static boolean flagHeadStart;
uint32_t _timeTemp;
// Управление работой дефлегматора
if (_temp[1] > 50) pumpStart();
else {pumpStop();fanStop();}
_timeTemp = getTimeUnix(); // временная метка текущего цикла
switch (modeCurWork){
case modeStart: // разгон аппарата
if (!initMode) {
setPower = powerCurWork[modeWork][modeCurWork].value;
flagStop = false;
curTime = _timeTemp;
curWTime = curTime;
initMode = true;
onLed(pRed1);
}
// нагрев верхней точки до 70 градусов, переход к режиму отбора голов
if (_temp[1] > 65){
initMode = false;
offLed(pRed1); onLed(pGreen1);
modeCurWork = modeHead;
}
break;
case modeHead:
if (!initMode){
setPower = powerCurWork[modeWork][modeCurWork].value;
curWTime = _timeTemp;
initMode = true;
flagHeadStart = true;
onLed(pGreen2);
fanStart();
}
if (_timeTemp - curWTime <= 600 ){ // не даем кипеть и испаряться, выбиваем головы
if (_temp[2] > 65.00){
setPower = powerCurWork[modeWork][modeCurWork].value - 200;
onLed(pBlue2); offLed(pGreen2);
}
else{
setPower = powerCurWork[modeWork][modeCurWork].value + 200;
offLed(pBlue2); onLed(pGreen2);
}
}
else{
// чисто получаем головы при испарении
if (flagHeadStart) { // очищаем переменные для извлечения голов
flagHeadStart = false;
onLed(pRed2); offLed(pBlue2); offLed(pGreen2);
if (setPower != powerCurWork[modeWork][modeCurWork].value) { // очищаем переменные для извлечения голов
setPower = powerCurWork[modeWork][modeCurWork].value;
}
}
if (_timeTemp - curWTime > 3600 ){ // Конец времени выпаривания голов
flagPressKey = true;
if (_timeTemp - timeBeep >= TIME_BUZER){
timeBeep = _timeTemp;
Buzzer(2);
}
if (isPress()){
flagPressKey = false; initMode = false;
offLed(pRed2); onLed(pGreen2);
modeCurWork = modeBody;
}
}
}
break;
case modeBody: // Режим извлечения тела
if (!initMode){
setPower = powerCurWork[modeWork][modeCurWork].value;
curWTime = _timeTemp;
initMode = true;
onLed(pRed3);
}
if (_temp[0] > 91.00){ // тестовая хрень работаем по температуре
flagPressKey = true;
if (_timeTemp - timeBeep >= TIME_BUZER){
timeBeep = _timeTemp;
Buzzer(3);
}
if (isPress()){
flagPressKey = false; initMode = false;
offLed(pRed3); onLed(pGreen3);
modeCurWork = modeTail;
}
}
break;
case modeTail:
if (!initMode){
setPower = powerCurWork[modeWork][modeCurWork].value;
curWTime = getTimeUnix();
initMode = true;
onLed(pRed4);
}
if (_temp[0] > 99.00){
flagPressKey = true;
if (_timeTemp - timeBeep >= TIME_BUZER){
timeBeep = _timeTemp;
Buzzer(5);
}
if (isPress()){
flagPressKey = false; initMode = false;
offLed(pRed4); onLed(pGreen4);
modeCurWork = modeNull;
}
}
break;
}
if (!flagHeadStart){
if (_temp[3] >= tempDef[modeWork][modeCurWork].maxValue) fanStart();
if (_temp[3] <= tempDef[modeWork][modeCurWork].minValue) fanStop();
}
}
//------------------------------------------------------------------------------------
//
// Режим НБК
//
void doContinuiusModeProcess(){
uint32_t _timeTemp;
_timeTemp = getTimeUnix();
pPumpRPM();
switch (modeCurWork){
case modeStart: // разгон аппарата
if (!initMode) {
setPower = powerCurWork[modeWork][modeCurWork].value;
flagStop = false;
curTime = getTimeUnix();
curWTime = curTime;
initMode = true;
onLed(pRed1);
}
// нагрев верхней точки до 97 градусов, переход к режиму отбора голов
if (_temp[2] > 97){
initMode = false;
offLed(pRed1); onLed(pGreen1);
modeCurWork = modeBody;
pPumpStart();
currentRPM = 25;
pPumpRPM();
}
break;
case modeBody: // Режим извлечения тела
if (!initMode){
setPower = powerCurWork[modeWork][modeCurWork].value;
curWTime = _timeTemp;
initMode = true;
onLed(pRed3);
}
break;
}
}