Неадекватное поведение вроде бы простой программы, гуру направьте.
- Войдите на сайт для отправки комментариев
Добрый день, уважаемые любители ардуино!
Краткая предыстория:
Решил я заново автоматизировать свой процесс самогоноварения.
Взял Arduino Mega2560, присоединил LCD дисплей 320х240 с тачскрином, SD карточку, несколько датчиков 18В20 и пачку реле.
И начал программировать.
Функционально вся программа должна выполнять несколько производственных процессов по выбору пользователя.
Каждый процесс состоит из нескольких стадий, переход от стадии к стадии переходит либо по событию (повышение температуры) или по таймеру (либо вручную, мало ли чего).
На экране должно быть вначале меню выбора процесса, после выбора и старта процесса выводится стадия, температуры и состояния некоторых реле, ну и отдельно должна быть настройка некоторых параметров.
Вроде все просто, никакого ООП, никаких прерываний, никаких ссылок, никакой ядреной математики.
И начал я писать программу. Написал несколько разных экранов, обработку первого процесса и вроде все работало.
Потом добавил ещё немного и столкнулся с тем, что ардуина стала вести себя непредсказуемо - переключала пины сама по себе, перезагружалась.
Я решил, что израсходовал оперативную память. Померял известной функцией "расстояние" между кучей и стэком, памяти оказалось дофига.
Тогда я безотносительно к памяти решил что в программе слишком много строковых данных для вывода на экран и перенёс все строки на SD карточку, проблема ушла.
Стал я пилить программу дальше отладил все экраны, и рабочий и настройки и регулировки параметров, довольный я идеально отладил процедуру первого процесса и решил взятся за отладку второго. И снова заново неожиданное включение реле, внезапные перезагрузки. Одним словом глюки.
На этот момент вес скомпилированного скетча был около 45 килобайт и по словам компилятора просил около 1,5 килобайта оперативной памяти.
Долго я ломал голову. Крутил и так и этак. Ничего умного в голову не приходило, пока не родилась мысль отключить оптимизацию компилятора.
Сменил я -Os на -O0, скомпилировал. Скетч получился больше 130 килобайт, запрос оперативки 5,5 килобайт. Правда компилятор ругается на delay.h Ругается, но компилирует.
Загрузил в плату. Работает идеально, никаких глюков, все как запрограммировано. Но чтение с карты и вывод на экран так медленно, что видно как отдельные буквы отрисовываются.
Попробовал поменять оптимизацию на -O1. Скетч получился около 100 килобайт и опять глюк на глюке и глюком погоняет.
В принципе можно конечно скомпилировать без оптимизации и смирится с тормозами, памяти много, программа почти закончена.
Но может все таки можно как-то и без тормозов и без глюков!?
Я конечно сомневаюсь, что кто нибудь сможет прошерстить более полутора тысяч строк моего говнокода, но всё таки приложу программу.
#define ThermoPin 3 // Назначение выводов #define DCPowSensPin A2 // Датчик напряжения 12в #define DCPowISensPin A0 // Датчик тока 12в #define MixSensPin A3 // Датчик напряжения миксера #define PumpBtnPin 47 // !!! Кнопка включеня мини насоса #define PumpRelPin A15 // Реле Мини насоса #define PumpSensPin A4 // Датчик напряжения мини насоса #define FanRelPin A14 // Реле вентиляторов #define FanSensPin A5 // Датчик напряжения вентиляторов #define SirRelPin A11 // Реле Сирены #define ActLRelPin A12 // Реле активатор - налево #define ActLSensPin 5 // Левый датчик активатора #define ActRRelPin A13 // Реле активатор - направо #define ActRSensPin 6 // Правый датчик активатора #define FltrSensPin 7 // Датчик - поплавок #define ACPowSensPin 15 // Датчик питания 220 в #define CircRelPin A10 // Реле циркуляционного насоса #define CircSensPin 18 // Датчик напряжения циркуляционного насоса #define WCircSensPin 2 // !!! Датчик протока воды #define SHtrRelPin A9 // Реле малого нагревателя #define SHtrSensPin 14 // Датчик напряжения малого нагревателя #define SHtrISensPin 16 // Датчик тока малого нагревателя #define BHtrRelPin A8 // Реле большого нагревателя #define BHtrSensPin 17 // Датчик напряжения большого нагревателя #define BHtrISensPin 19 // Датчик тока большого нагревателя #define ACFail 1 // Типы ошибок #define DCFail 2 #define MixerFail 3 #define MiniPumpRelayFail 4 #define MiniPumpFail 5 #define FanRelayFail 6 #define FanFail 7 #define WtrPumpRelayFail 8 #define WtrPumpFail 9 #define SHtrRelayFail 10 #define SHtrFail 11 #define BHtrRelayFail 12 #define BHtrFail 13 #define BotSwFail 14 #define BottleFull 15 #define CoolantOverheat 16 #define DSFail 17 #define DegasTime 1 // Назначение номеров параметров #define CCHeadsTime 2 #define St2HeadsTime 3 #define RTDHeadsTime 4 #define CoolantEdge 5 #define DeflEdge 6 #define MaxTempMaxPow 7 #define MaxTempMedPow 8 #define MaxTempLowPow 9 #define MaxTempStage2 10 #define MaxTempRTD 11 #define DegasStartTemp 12 #define CoolingTime 13 #define SBottleWait 14 #define RTDRdyTime 15 #define RTDContTime 16 #define ParamNumber 17 #define NoHeat 0 // Варианты мощностей СС #define MaxHeat 1 #define MedHeat 2 #define LowHeat 3 #define DeviceOn 1 // Назначение режимов устройств и сенсоров #define DeviceOff 0 #define SensorOn 0 #define SensorOff 1 #define StageOff 1 #define StageOn 0 #define NoScreen 0 // Назначение номеров экранов #define MnScreen 1 #define SetScreen 2 #define St1SScreen 3 #define St2SScreen 4 #define ComSScreen 5 #define AdjScreen 6 #define DoStageScreen 7 #define ChActionScreen 8 #define NoStage 0 #define PreHeat 1 // Стадии для всех циклов #define Degasation 2 #define Heating 3 #define DoHeads 4 #define DoBody 5 #define DoCool 6 #define DoFinish 7 #define OprDecr 2 // Типы изменения параметра #define OprIncr 3 #define BottleHeads 1 // Типы бутылок #define BottleBody 2 #define BeepAlarm 1 // Назначение типов сигналов #define BBeepAlarm 2 #define FullAlarm 3 #define StopAlarm 4 #define ActPeriod 1000 // Нерегулируемые параметры #define DCIMixThreshold 514 #define DCIFanThreshold 522 #define AdjDelay 120 byte DoCCStage = StageOff; // Переменные включения производственных циклов byte DoStage2 = StageOff; byte DoContSt2 = StageOff; byte DoRTD = StageOff; byte DoContRTD = StageOff; byte DoClean = StageOff; int Params[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; // Массив хранения настраиваемых параметров const byte ParamType[17] = {0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,}; // Массив хранения типа вывода параметров на дисплей // Не забыть удалить комментарий в Аджусте #include <OneWire.h> #include <EEPROM.h> #include <SPI.h> #include <SD.h> #include <UTFT.h> #include <URTouch.h> extern uint8_t SmallFont[]; File dataFile; UTFT myGLCD(ITDB32S,38,39,40,41); URTouch myTouch( 46, 45, 44, 43, 42); OneWire ds(ThermoPin); const int chipSelect = 4; const char StrEnd = '\0'; char Str[20]; int x,y; byte MainScr = 1; // Переменные определяющие отрисован экран или нет byte StageScr = 1; byte SettsScr = 1; byte St1StScr = 1; byte St2StScr = 1; byte CommStScr = 1; byte AdjustScr = 1; byte ActionsScr = 1; byte ScrMode = MnScreen; //Текущий экран для отображения byte AdjParam =0; //Номер параметра для настройки byte TmpParam; byte addr1[8]; // Адрес 1-го датчика температуры (Воды) byte addr2[8]; // Адрес 2-го датчика температуры (Куба) byte addr3[8]; // Адрес 3-го датчика температуры (Дефлегматор) int ClntTemp = 0; // Температура охл. жидкости int CubeTemp = 0; // Температура в кубе int DeflTemp = 0; // Температура входа дефлегматора byte SHeater = DeviceOff; //Переменные включения-выключения исполнительных устройств byte BHeater = DeviceOff; byte WtrPump = DeviceOff; byte MiniPump = DeviceOff; byte WtrFan = DeviceOff; unsigned long MyTimer; //Разнообразные таймеры unsigned long TouchedTime; unsigned long FltrTimer; byte BotSwTst = 1; byte Stage = NoStage; byte TmpStage = NoStage; byte SysError = 0; byte NumOfBottles = 0; byte CurrentBottle; byte IgnoreFltr = 0; byte HeaterPower = NoHeat; byte Cooling = 0; boolean TakeTouch (); void ToEE (); int MakeCool (); void ErrorHandler (int ErrorType) { //Это будет обработчик разнообразных ошибок железа } void FromEE () { //Считываем параметры из EEPROM int i = 0; EEPROM.get(0,Params[ParamNumber]); // Считываем первый элемент из ЕЕПРОМ if (i == -1) { // Если чип новый заполняем массив параметров из переменных и зыписываем в ЕЕПРОМ ToEE (); } else { // Если чип не новый, то считываем массив параметров из ЕЕПРОМ for (byte i=0; i < ParamNumber; i++) { EEPROM.get((i*sizeof(int)), Params[i]); } } } void ToEE () { // Массив параметров в цикле записывается в ЕЕПРОМ for (byte i=0; i < ParamNumber; i++) { EEPROM.put((i*sizeof(int)), Params[i]); } } void MyPinsSetup () { Params[DegasTime] = 45; Params[CCHeadsTime] = 17; Params[St2HeadsTime] = 24; Params[RTDHeadsTime] = 25; Params[CoolantEdge] = 500; Params[DeflEdge] = 500; Params[MaxTempMaxPow] = 820; Params[MaxTempMedPow] = 830; Params[MaxTempLowPow] = 840; Params[MaxTempStage2] = 830; Params[MaxTempRTD] = 820; Params[DegasStartTemp] = 720; Params[CoolingTime] = 3; Params[SBottleWait] = 5; Params[RTDRdyTime] = 150; Params[RTDContTime] = 180; pinMode (DCPowSensPin,INPUT); digitalWrite (DCPowSensPin,HIGH); pinMode (MixSensPin,INPUT); digitalWrite (MixSensPin,HIGH); pinMode (PumpBtnPin,INPUT); digitalWrite (PumpBtnPin,HIGH); pinMode (PumpSensPin,INPUT); digitalWrite (PumpSensPin,HIGH); pinMode (FanSensPin,INPUT); digitalWrite (FanSensPin,HIGH); pinMode (ActLSensPin,INPUT); digitalWrite (ActLSensPin,HIGH); pinMode (ActRSensPin,INPUT); digitalWrite (ActRSensPin,HIGH); pinMode (FltrSensPin,INPUT); digitalWrite (FltrSensPin,HIGH); pinMode (ACPowSensPin,INPUT); digitalWrite (ACPowSensPin,HIGH); pinMode (CircSensPin,INPUT); digitalWrite (CircSensPin,HIGH); pinMode (WCircSensPin,INPUT); pinMode (SHtrSensPin,INPUT); digitalWrite (SHtrSensPin,HIGH); pinMode (SHtrISensPin,INPUT); digitalWrite (SHtrISensPin,HIGH); pinMode (BHtrSensPin,INPUT); digitalWrite (BHtrSensPin,HIGH); pinMode (BHtrISensPin,INPUT); digitalWrite (BHtrISensPin,HIGH); pinMode (WCircSensPin, INPUT); digitalWrite (WCircSensPin, HIGH); digitalWrite (PumpRelPin,DeviceOff); pinMode (PumpRelPin,OUTPUT); digitalWrite (FanRelPin,DeviceOff); pinMode (FanRelPin,OUTPUT); digitalWrite (SirRelPin,DeviceOff); pinMode (SirRelPin,OUTPUT); digitalWrite (ActLRelPin,DeviceOff); pinMode (ActLRelPin,OUTPUT); digitalWrite (ActRRelPin,DeviceOff); pinMode (ActRRelPin,OUTPUT); digitalWrite (CircRelPin,DeviceOff); pinMode (CircRelPin,OUTPUT); digitalWrite (SHtrRelPin,DeviceOff); pinMode (SHtrRelPin,OUTPUT); digitalWrite (BHtrRelPin,DeviceOff); pinMode (BHtrRelPin,OUTPUT); } void GetTemp() { // Функция измерения температуры ds.reset(); ds.select(addr1); ds.write(0x44); ds.reset(); ds.select(addr1); ds.write(0xBE); // Read Scratchpad ClntTemp = int((ds.read() | (ds.read() << 8)) / 1.6); //ds.reset_search(); ds.reset(); ds.select(addr2); ds.write(0x44); ds.reset(); ds.select(addr2); ds.write(0xBE); // Read Scratchpad CubeTemp = int((ds.read() | (ds.read() << 8)) / 1.6); ds.reset(); ds.select(addr3); ds.write(0x44); ds.reset(); ds.select(addr3); ds.write(0xBE); // Read Scratchpad DeflTemp = int((ds.read() | (ds.read() << 8)) / 1.6); } void SwitchAllOff () { // Выключаем ВСЁ SHeater = DeviceOff; BHeater = DeviceOff; WtrPump = DeviceOff; MiniPump = DeviceOff; WtrFan = DeviceOff; DoCCStage = StageOff; DoStage2 = StageOff; DoContSt2 = StageOff; DoRTD = StageOff; DoContRTD = StageOff; DoClean = StageOff; MainScr = 1; StageScr = 1; SettsScr = 1; St1StScr = 1; St2StScr = 1; CommStScr = 1; AdjustScr = 1; ActionsScr = 1; ScrMode = MnScreen; BotSwTst = 1; Stage = 0; } int WaterFlowChk () { // Проверяем состояние поплавка на переполнение бутылки int State = digitalRead (WCircSensPin); unsigned long WtrFTimer = millis()+250; while (millis () < WtrFTimer ) { if (!(State == digitalRead (WCircSensPin))) { return (0); } } return (1); } void Alarm (int AlarmType) { // Разнообразные сигналы сирены switch (AlarmType) { case BeepAlarm : digitalWrite (SirRelPin,DeviceOn); delay (150); digitalWrite (SirRelPin,DeviceOff); break; case BBeepAlarm : digitalWrite (SirRelPin,DeviceOn); delay (130); digitalWrite (SirRelPin,DeviceOff); delay (130); digitalWrite (SirRelPin,DeviceOn); delay (130); digitalWrite (SirRelPin,DeviceOff); break; case FullAlarm : digitalWrite (SirRelPin,DeviceOn); break; case StopAlarm : digitalWrite (SirRelPin,DeviceOff); break; } } int SwitchBottle (int BottleType) { // Функция переключения выхода на разные бутылки с контролем выполнения static int LSens,RSens; static unsigned long SwTime; LSens = digitalRead (ActLSensPin); RSens = digitalRead (ActRSensPin); CurrentBottle = BottleType; if ((LSens==SensorOn) && (RSens==SensorOn)) { return (1); } if ((LSens==SensorOff) && (RSens==SensorOff)) { SwTime = millis (); digitalWrite (ActLRelPin,DeviceOn); cycle1: LSens=digitalRead (ActLSensPin); if (LSens) { if ((SwTime+ActPeriod) < millis ()) { digitalWrite (ActLRelPin,DeviceOff); return (1); } goto cycle1; } digitalWrite (ActLRelPin,DeviceOff); return (0); } if (LSens==SensorOn) { if (BottleType == BottleHeads) { return (0); } if (BottleType == BottleBody) { SwTime = millis (); digitalWrite (ActRRelPin,DeviceOn); cycle2: RSens=digitalRead (ActRSensPin); if (RSens) { if ((SwTime+ActPeriod) < millis ()) { digitalWrite (ActRRelPin,DeviceOff); return (1); } goto cycle2; } digitalWrite (ActRRelPin,DeviceOff); return (0); } return (1); } if (RSens==SensorOn) { if (BottleType == BottleBody) { return (0); } if (BottleType == BottleHeads) { SwTime = millis (); digitalWrite (ActLRelPin,DeviceOn); cycle3: LSens=digitalRead (ActLSensPin); if (LSens) { if ((SwTime+ActPeriod) < millis ()) { digitalWrite (ActLRelPin,DeviceOff); return (1); } goto cycle3; } digitalWrite (ActLRelPin,DeviceOff); return (0); } } return (1); } int SysCheck () { // Проверка системы if (digitalRead (DCPowSensPin) == SensorOff) { return (DCFail); } if (BotSwTst) { if ( SwitchBottle (BottleHeads) ) { return (BotSwFail); } if ( SwitchBottle (BottleBody) ) { return (BotSwFail); } BotSwTst = 0; } if (digitalRead (ACPowSensPin) == SensorOff) { return (ACFail); } if (digitalRead (MixSensPin) == SensorOn) { if (analogRead (DCPowISensPin) < DCIMixThreshold) { return (MixerFail); } } if (MiniPump == DeviceOff) { if (digitalRead (PumpSensPin) == SensorOn) { return (MiniPumpRelayFail); } } if (MiniPump == DeviceOn) { if (digitalRead (PumpSensPin) == SensorOff) { return (MiniPumpRelayFail); } if (analogRead (DCPowISensPin) < DCIMixThreshold) { return (MiniPumpFail); } } if (WtrFan == DeviceOff) { if (digitalRead (FanSensPin) == SensorOn) { return (FanRelayFail); } } if (WtrFan == DeviceOn) { if (digitalRead (FanSensPin) == SensorOff) { return (FanRelayFail); } if (analogRead (DCPowISensPin) < DCIFanThreshold) { return (FanFail); } } if (WtrPump == DeviceOff) { if (digitalRead (CircSensPin) == SensorOn) { return (WtrPumpRelayFail); } } if (WtrPump == DeviceOn) { if (digitalRead (CircSensPin) == SensorOff) { return (WtrPumpRelayFail); } if (WaterFlowChk ()) { return (WtrPumpFail); } } if (SHeater == DeviceOff) { if (digitalRead (SHtrSensPin) == SensorOn) { return (SHtrRelayFail); } } if (SHeater == DeviceOn) { if (digitalRead (SHtrSensPin) == SensorOff) { return (SHtrRelayFail); } if (digitalRead (SHtrISensPin) ==SensorOff) { return (SHtrFail); } } if (BHeater == DeviceOff) { if (digitalRead (BHtrSensPin) == SensorOn) { return (BHtrRelayFail); } } if (SHeater == DeviceOn) { if (digitalRead (BHtrSensPin) == SensorOff) { return (BHtrRelayFail); } if (digitalRead (BHtrISensPin) ==SensorOff) { return (BHtrFail); } } return (0); } void SwitchDevs () { // Включение-выключение устройств согласно значениям переменных digitalWrite(SHtrRelPin,SHeater); digitalWrite(BHtrRelPin,BHeater); digitalWrite(CircRelPin,WtrPump); digitalWrite(PumpRelPin,MiniPump); digitalWrite(FanRelPin,WtrFan); } int SDintRead(File CurFile) { // Читаем число из файла, не более 3 знаков, ограниченное ";" byte byte1 = 0; byte byte2 = 0; byte byte3 = 0; int number = 0; if (CurFile.available()) { byte1 = CurFile.read()-48; if (!(byte1 == 11)) { byte2 = CurFile.read()-48; if (byte2 == 11) { number = byte1; } else { byte3 = CurFile.read()-48; if (byte3 == 11) { number = byte1*10+byte2; } else { number = byte1*100+byte2*10+byte3; CurFile.read(); } } } if (number == 999) { number = 9998; } return (number); } else return (65535); } void SDStrRead (File CurFile) { // Читаем строку из файла byte temp = 0; int i = 0; do { if (CurFile.available()) { temp = CurFile.read(); } else { temp = 59; } if ( temp == 59 ) { Str [i] = StrEnd; } else { Str [i] = char (temp); } i++; } while (temp != 59); } void DrawFile (int FileNum) { // Отрисовываем экран по данным из файла под номером FileNum String FName = String (FileNum); dataFile = SD.open(FName,FILE_READ); while (dataFile.available()) { switch (char (dataFile.read ())) { case '^': myGLCD.drawLine(SDintRead (dataFile),SDintRead (dataFile),SDintRead (dataFile),SDintRead (dataFile)); break; case '&': myGLCD.drawRoundRect(SDintRead (dataFile),SDintRead (dataFile),SDintRead (dataFile),SDintRead (dataFile)); break; case '%': case '<': myGLCD.setColor(SDintRead (dataFile),SDintRead (dataFile),SDintRead (dataFile)); break; case '$': myGLCD.drawRect(SDintRead (dataFile),SDintRead (dataFile),SDintRead (dataFile),SDintRead (dataFile)); break; case '@': myGLCD.fillScr(SDintRead (dataFile),SDintRead (dataFile),SDintRead (dataFile)); break; case '#': SDStrRead (dataFile); myGLCD.print (Str,SDintRead (dataFile),SDintRead (dataFile),SDintRead (dataFile)); break; case '*': myGLCD.fillRect(SDintRead (dataFile),SDintRead (dataFile),SDintRead (dataFile),SDintRead (dataFile)); break; case '!': myGLCD.setBackColor(SDintRead (dataFile),SDintRead (dataFile),SDintRead (dataFile)); break; } } dataFile.close(); } void MainScreen () { // Отрисовка и опрос тачскрина в основном экране if (MainScr) { DrawFile (1); MainScr = 0; } if (TakeTouch () ) { while (myTouch.dataAvailable()) myTouch.read(); if ((y>21) && (y<69)) { if ((x>16) && (x<104)) { DoCCStage = StageOn; ScrMode = DoStageScreen; MainScr = 1; Stage = 0; HeaterPower = NoHeat; } if ((x>116) && (x<204)) { DoStage2 = StageOn; ScrMode = DoStageScreen; MainScr = 1; Stage = 0; NumOfBottles = 0; } if ((x>216) && (x<304)) { DoRTD = StageOn; ScrMode = DoStageScreen; MainScr = 1; NumOfBottles = 0; } } if ((y>86) && (y<134)) { if ((x>16) && (x<104)) { DoClean = StageOn; ScrMode = DoStageScreen; MainScr = 1; } if ((x>116) && (x<204)) { DoContSt2 = StageOn; ScrMode = DoStageScreen; MainScr = 1; NumOfBottles = 0; } if ((x>216) && (x<304)) { DoContRTD = StageOn; ScrMode = DoStageScreen; MainScr = 1; NumOfBottles = 0; } } if ((y>151) && (y<199)) { ScrMode = SetScreen; MainScr = 1; } } } void SettsScreen () { // Отрисовка и опрос тачскрина в экране выбора настроек if (SettsScr) { DrawFile (2); SettsScr = 0; } if (TakeTouch () ) { while (myTouch.dataAvailable()) myTouch.read(); if ((x>16) && (x<119)) { if ((y>86) && (y<134)) { ScrMode = St1SScreen; SettsScr = 1; } if ((y>151) && (y<199)) { ScrMode = ComSScreen; SettsScr = 1; } } if ((x>201) && (x<304)) { if ((y>86) && (y<134)) { ScrMode = St2SScreen; SettsScr = 1; } if ((y>151) && (y<199)) { ScrMode = ComSScreen; SettsScr = 1; } } if ((x>136) && (x<184)) { SettsScr = 1; ScrMode = MnScreen; } } } void St2StScreen () { // Отрисовка и опрос тачскрина в экране настроек 2 и 3 процессов if (St2StScr) { DrawFile (4); St2StScr = 0; } if (TakeTouch () ) { while (myTouch.dataAvailable()) myTouch.read(); if ((x>16) && (x<119)) { if ((y>41) && (y<79)) { AdjParam = St2HeadsTime; ScrMode = AdjScreen; St2StScr = 1; } if ((y>161) && (y<199)) { AdjParam = RTDHeadsTime; ScrMode = AdjScreen; St2StScr = 1; } } if ((x>201) && (x<304)) { if ((y>41) && (y<79)) { AdjParam = MaxTempStage2; ScrMode = AdjScreen; St2StScr = 1; } if ((y>161) && (y<199)) { AdjParam = MaxTempRTD; ScrMode = AdjScreen; St2StScr = 1; } } if ((x>136) && (x<184)) { St2StScr = 1; ScrMode = MnScreen; } } } void St1StScreen () { // Отрисовка и опрос тачскрина в экране настроек 1 процесса if (St1StScr) { DrawFile (3); St1StScr = 0; } if (TakeTouch () ) { while (myTouch.dataAvailable()) myTouch.read(); if ((x>16) && (x<119)) { if ((y>41) && (y<79)) { AdjParam = DegasStartTemp; ScrMode = AdjScreen; St1StScr = 1; } if ((y>101) && (y<139)) { AdjParam = DegasTime; ScrMode = AdjScreen; St1StScr = 1; } if ((y>161) && (y<199)) { AdjParam = CCHeadsTime; ScrMode = AdjScreen; St1StScr = 1; } } if ((x>201) && (x<304)) { if ((y>41) && (y<79)) { AdjParam = MaxTempMaxPow; ScrMode = AdjScreen; St1StScr = 1; } if ((y>101) && (y<139)) { AdjParam = MaxTempMedPow; ScrMode = AdjScreen; St1StScr = 1; } if ((y>161) && (y<199)) { AdjParam = MaxTempLowPow; ScrMode = AdjScreen; St1StScr = 1; } } if ((x>136) && (x<184)) { St2StScr = 1; ScrMode = MnScreen; } } } void CommStScreen () { // Отрисовка и опрос тачскрина в экране общих настроек if (CommStScr) { DrawFile (5); CommStScr = 0; } if (TakeTouch () ) { while (myTouch.dataAvailable()) myTouch.read(); if ((x>16) && (x<119)) { if ((y>41) && (y<79)) { AdjParam = DeflEdge; ScrMode = AdjScreen; CommStScr = 1; } if ((y>101) && (y<139)) { AdjParam = SBottleWait; ScrMode = AdjScreen; CommStScr = 1; } if ((y>161) && (y<199)) { AdjParam = 0; ScrMode = AdjScreen; CommStScr = 1; } } if ((x>201) && (x<304)) { if ((y>41) && (y<79)) { AdjParam = CoolingTime; ScrMode = AdjScreen; CommStScr = 1; } if ((y>101) && (y<139)) { AdjParam = CoolantEdge; ScrMode = AdjScreen; CommStScr = 1; } if ((y>161) && (y<199)) { AdjParam = 0; ScrMode = AdjScreen; CommStScr = 1; } } if ((x>136) && (x<184)) { CommStScr = 1; ScrMode = MnScreen; } } } void AdjustScreen () { // Отрисовка и опрос тачскрина в экране настройки параметров, и собственно настройка int Oper = 0; if (AdjustScr) { DrawFile (6); AdjustScr = 0; TmpParam = Params [AdjParam]; DrawFile (AdjParam+49); } if (ParamType [AdjParam]) { myGLCD.printNumF ((TmpParam/10), 1, CENTER, 105); } else { myGLCD.printNumI(TmpParam, CENTER, 105,3,'0'); } if (TakeTouch () ) { if ((y>86) && (y<134)) { TouchedTime = millis (); if ((x>16) && (x<109)) { Oper = OprDecr; TmpParam--; if (ParamType [AdjParam]) { myGLCD.printNumF ((TmpParam/10), 1, CENTER, 105); } else { myGLCD.printNumI(TmpParam, CENTER, 105,3,'0'); } } if ((x>201) && (x<304)) { Oper = OprIncr; TmpParam++; if (ParamType [AdjParam]) { myGLCD.printNumF ((TmpParam/10), 1, CENTER, 105); } else { myGLCD.printNumI(TmpParam, CENTER, 105,3,'0'); } } while (myTouch.dataAvailable()) { myTouch.read(); if ((TouchedTime+300) < millis ()) { TouchedTime = millis (); while (myTouch.dataAvailable()) { myTouch.read(); if ((TouchedTime + AdjDelay) < millis ()) { if (Oper == OprDecr) { TmpParam--; } if (Oper == OprIncr) { TmpParam++; } if (ParamType [AdjParam]) { myGLCD.printNumF ((TmpParam/10), 1, CENTER, 105); } else { myGLCD.printNumI(TmpParam, CENTER, 105,3,'0'); } TouchedTime = millis (); } } } } } if ((y>151) && (y<199)) { while (myTouch.dataAvailable()) myTouch.read(); if ((x>16) && (x<149)) { AdjustScr = 1; ScrMode = MnScreen; } if ((x>181) && (x<304)) { Params [AdjParam] = TmpParam; AdjustScr = 1; ScrMode = MnScreen; // ToEE (); } } } } void HeatPause () { // Экран паузы в нагревании DrawFile (32); digitalWrite(SHtrRelPin,DeviceOff); digitalWrite(BHtrRelPin,DeviceOff); delay (150); while (!(myTouch.dataAvailable())) { } myTouch.read (); } void ActionsScreen () { // Отрисовка и опрос тачскрина в экране действий внутри процесса if (ActionsScr) { DrawFile (8); switch (TmpStage) { case PreHeat: DrawFile (25); break; case Degasation: DrawFile (26); break; case Heating: DrawFile (27); break; case DoHeads: DrawFile (28); break; case DoBody: DrawFile (29); break; case DoCool: DrawFile (30); break; } ActionsScr = 0; } if (TakeTouch () ) { while (myTouch.dataAvailable()) myTouch.read(); if ((x>16) && (x<119)) { if ((y>41) && (y<79)) { ActionsScr = 1; SwitchAllOff (); ScrMode = MnScreen; } if ((y>101) && (y<139)) { ActionsScr = 1; HeatPause (); ScrMode = DoStageScreen; } if ((y>161) && (y<199)) { ActionsScr = 1; NumOfBottles = 1; } } if ((x>201) && (x<304)) { if ((y>41) && (y<79)) { ActionsScr = 1; if (DoCCStage == StageOff) { TmpStage++; } else { if (Stage == DoBody) { if (HeaterPower == LowHeat) { TmpStage++; } else { HeaterPower++; } } else { TmpStage++; } } if (TmpStage == (DoCool+1)) { TmpStage = DoCool; } } if ((y>101) && (y<139)) { ActionsScr = 1; Stage = TmpStage; ScrMode = DoStageScreen; if ((TmpStage == Degasation) || (TmpStage == DoHeads) || (TmpStage == DoCool)) { MyTimer = millis (); } } if ((y>161) && (y<199)) { ActionsScr = 1; IgnoreFltr = 0; FltrTimer = millis (); } } if ((x>136) && (x<184)) { ActionsScr = 1; ScrMode = DoStageScreen; } } } void ParamsScreen () { // Отрисовка текущих параметров процесса myGLCD.printNumF ((ClntTemp/10), 1, 105, 100); myGLCD.printNumF ((DeflTemp/10), 1, 290, 100); if (SHeater == DeviceOn) { DrawFile (70); } else { DrawFile (71); } if (BHeater == DeviceOn) { DrawFile (72); } else { DrawFile (73); } if (WtrPump == DeviceOn) { DrawFile (74); } else { DrawFile (75); } if (WtrFan == DeviceOn) { DrawFile (76); } else { DrawFile (77); } if (DoCCStage == StageOff) { DrawFile (31); myGLCD.printNumI ((NumOfBottles+1), 1, 290, 175); if (CurrentBottle == BottleHeads) { DrawFile (78); } else { DrawFile (79); } } else { if (CurrentBottle == BottleHeads) { DrawFile (80); } else { DrawFile (81); } } myGLCD.printNumF ((CubeTemp/10), 1, 105, 175); } void StageScreen () { // Отрисовка основного экрана процесса if (StageScr) { DrawFile (7); if (DoCCStage == StageOn) { DrawFile (14); } if (DoStage2 == StageOn) { DrawFile (15); } if (DoRTD == StageOn) { DrawFile (16); } if (DoContSt2 == StageOn) { DrawFile (17); } if (DoContRTD == StageOn) { DrawFile (18); } StageScr = 0; } switch (Stage) { case PreHeat: DrawFile (19); break; case Degasation: DrawFile (20); myGLCD.printNumI ((int (((MyTimer + Params[DegasTime]*60000)-millis ())/60000)+1), 235, 60); myGLCD.print ((char *)F("Min"), 255, 60); break; case Heating: DrawFile (21); break; case DoHeads: DrawFile (22); break; case DoBody: DrawFile (24); break; case DoCool: DrawFile (23); myGLCD.printNumI ((int (((MyTimer + Params[CoolingTime]*60000)-millis ())/60000)+1), 235, 60); myGLCD.print ((char *)F("Min"), 255, 60); break; } ParamsScreen (); if (TakeTouch () ) { while (myTouch.dataAvailable()) myTouch.read(); if ((x>136) && (x<184)) { StageScr = 1; ActionsScr = 1; TmpStage = Stage; ScrMode = ChActionScreen; } } } void Screens () { // Выбор экрана для отрисовки switch (ScrMode) { case MnScreen: MainScreen (); break; case SetScreen: SettsScreen (); break; case St1SScreen: St1StScreen (); break; case St2SScreen: St2StScreen (); break; case ComSScreen: CommStScreen (); break; case AdjScreen: AdjustScreen (); break; case DoStageScreen: StageScreen (); break; case ChActionScreen: ActionsScreen (); break; } } int MakeCC () { // Процесс первого перегона if (DoCCStage) { // Если цикл не включен возвращаемся без ошибок. return (0); } switch (Stage) { case 0: // Если начался цикл переходим к стадии преднагрева Stage = PreHeat; break; case PreHeat: // Преднагрев - включаем обегрелки SHeater = DeviceOn; BHeater = DeviceOn; if (CubeTemp >= Params[DegasStartTemp]) { // Если температура достигла дегазации засекаем время и переходим к стадии дегазации Stage = Degasation; MyTimer = millis (); } break; case Degasation: // Дегазация - выключаем обе грелки SHeater = DeviceOff; BHeater = DeviceOff; if (millis () >= (MyTimer + Params[DegasTime]*60000)) { // Проверяем время и если вышло - переходим к нагреву Stage = Heating; } break; case Heating: // Нагрев - включаем обе грелки SHeater = DeviceOn; BHeater = DeviceOn; if (DeflTemp > Params[DeflEdge]) { //Если температура дефлегматора достигла границы переходим к головам - выключаем большую грелку и включаем насос. MyTimer = millis (); //Засекаем время Stage = DoHeads; Alarm (BeepAlarm); } break; case DoHeads: // Делаем головы WtrPump = DeviceOn; BHeater = DeviceOff; if (SwitchBottle (BottleHeads)) { // Если выход не переключился - пытаемся обработать ошибку SHeater = DeviceOff; ErrorHandler (BotSwFail); return (1); } else { if (millis () >= (MyTimer + Params[CCHeadsTime]*60000)) { // Проверяем время - если вышло - переходим к телу Stage = DoBody; Alarm (BeepAlarm); } } break; case DoBody: if (SwitchBottle (BottleBody)) { // Если выход не переключился - пытаемся обработать ошибку SHeater = DeviceOff; ErrorHandler (BotSwFail); return (1); } switch (HeaterPower) { // Разные действия для разной мощности case NoHeat: // Если только началось - включаем обе грелки и переходим в режим максимальной мощности WtrPump = DeviceOn; SHeater = DeviceOn; BHeater = DeviceOn; HeaterPower = MaxHeat; return (0); break; case MaxHeat: // Проверяем граници температуры куба и охлаждающей жидкости если превысило - снижаем мощность if (CubeTemp >= Params[MaxTempMaxPow]) { SHeater = DeviceOff; HeaterPower = MedHeat; } if (ClntTemp >= Params[CoolantEdge]) { SHeater = DeviceOff; HeaterPower = MedHeat; } return (0); break; case MedHeat: // Проверяем граници температуры куба и охлаждающей жидкости если превысило - снижаем мощность if (CubeTemp >= Params[MaxTempMedPow]) { BHeater = DeviceOff; SHeater = DeviceOn; HeaterPower = LowHeat; } if (ClntTemp >= Params[CoolantEdge]) { BHeater = DeviceOff; SHeater = DeviceOn; HeaterPower = LowHeat; } return (0); break; case LowHeat: if (CubeTemp >= Params[MaxTempLowPow]) { // Если температура куба превысила границу сбрасываем стадии СС выключаем грелку и переходим к охлаждению HeaterPower = NoHeat; DoCCStage = StageOff; Stage = DoCool; } if (ClntTemp >= Params[CoolantEdge]) { // Если температура охлаждайки превысила границу - пытаемся обработать ошибку SHeater = DeviceOff; HeaterPower = NoHeat; Stage = 0; ErrorHandler (CoolantOverheat); } break; } break; case DoCool: MakeCool (); break; } return (0); } int MakeCool () { // Функция охлаждения системы if (Cooling) { // Если охлаждение включено проверяем не пора ли выключаться если пора всё выключаем и сигналим. if (millis () >= (MyTimer+Params[CoolingTime]*60000)) { WtrPump = DeviceOff; SwitchAllOff (); Alarm (BBeepAlarm); return (0); } } else { // Если охлаждение не включено - включаем и засекаем время. SHeater = DeviceOff; BHeater = DeviceOff; WtrPump = DeviceOn; MyTimer = millis (); Cooling = 1; } } int MakeSt2 () { // Процесс повторного перегона if (DoStage2) { return (0); } switch (Stage) { case 0: Stage = Heating; break; case Heating: SHeater = DeviceOn; BHeater = DeviceOn; if (DeflTemp > Params[DeflEdge]) { //Если температура дефлегматора достигла границы переходим к головам - выключаем большую грелку и включаем насос. MyTimer = millis (); //Засекаем время Stage = DoHeads; WtrPump = DeviceOn; Alarm (BeepAlarm); } break; case DoHeads: // Делаем головы BHeater = DeviceOff; if (SwitchBottle (BottleHeads)) { // Если выход не переключился - пытаемся обработать ошибку SHeater = DeviceOff; ErrorHandler (BotSwFail); return (1); } else { if (millis () >= (MyTimer + Params[St2HeadsTime]*60000)) { // Проверяем время - если вышло - переходим к телу if (SwitchBottle (BottleBody)) { // Если выход не переключился - пытаемся обработать ошибку SHeater = DeviceOff; ErrorHandler (BotSwFail); return (1); } Stage = DoBody; Alarm (BeepAlarm); } } break; case DoBody: if (!(IgnoreFltr)) { if (digitalRead (FltrSensPin)) { if (NumOfBottles) { if (SwitchBottle (BottleHeads)) { // Если выход не переключился - пытаемся обработать ошибку SHeater = DeviceOff; ErrorHandler (BotSwFail); return (1); } Alarm (BBeepAlarm); } else { SHeater = DeviceOff; Alarm (BBeepAlarm); delay (300); Alarm (BBeepAlarm); MyTimer = millis (); if (millis () >= (MyTimer + Params[SBottleWait]*60000)) { DoStage2 = StageOff; Stage = DoCool; } } } } if (CubeTemp >= Params[MaxTempStage2]) { // Если температура куба превысила границу сбрасываем стадии выключаем грелку и переходим к охлаждению SHeater = DeviceOff; DoStage2 = StageOff; Stage = DoCool; Alarm (BeepAlarm); } if (ClntTemp >= Params[CoolantEdge]) { // Если температура охлаждайки превысила границу - пытаемся обработать ошибку SHeater = DeviceOff; Stage = 0; ErrorHandler (CoolantOverheat); } break; case DoCool: MakeCool (); break; } return (0); } int ContSt2 () { // Функция продолжения процесса повторного перегона if (DoContSt2) { return (0); } switch (Stage) { case 0: Stage = Heating; break; case Heating: SHeater = DeviceOn; BHeater = DeviceOn; if (DeflTemp > Params[DeflEdge]) { //Если температура дефлегматора достигла границы переходим к телу - выключаем большую грелку и включаем насос. if (SwitchBottle (BottleBody)) { // Если выход не переключился - пытаемся обработать ошибку SHeater = DeviceOff; ErrorHandler (BotSwFail); return (1); } Stage = DoBody; WtrPump = DeviceOn; Alarm (BeepAlarm); } break; case DoBody: if (!(IgnoreFltr)) { if (digitalRead (FltrSensPin)) { if (NumOfBottles) { if (SwitchBottle (BottleHeads)) { // Если выход не переключился - пытаемся обработать ошибку SHeater = DeviceOff; ErrorHandler (BotSwFail); return (1); } Alarm (BBeepAlarm); } else { SHeater = DeviceOff; Alarm (BBeepAlarm); delay (300); Alarm (BBeepAlarm); MyTimer = millis (); if (millis () >= (MyTimer + Params[SBottleWait]*60000)) { DoContSt2 = StageOff; Stage = DoCool; } } } } if (CubeTemp >= Params[MaxTempStage2]) { // Если температура куба превысила границу сбрасываем стадии выключаем грелку и переходим к охлаждению SHeater = DeviceOff; DoContSt2 = StageOff; Stage = DoCool; Alarm (BeepAlarm); } if (ClntTemp >= Params[CoolantEdge]) { // Если температура охлаждайки превысила границу - пытаемся обработать ошибку SHeater = DeviceOff; Stage = 0; ErrorHandler (CoolantOverheat); } break; case DoCool: MakeCool (); break; } return (0); } int MakeRTD () { // Процесс заключительного перегона if (DoRTD) { return (0); } switch (Stage) { case 0: Stage = Heating; break; case Heating: SHeater = DeviceOn; BHeater = DeviceOn; if (DeflTemp > Params[DeflEdge]) { //Если температура дефлегматора достигла границы переходим к головам - выключаем большую грелку и включаем насос. MyTimer = millis (); //Засекаем время Stage = DoHeads; WtrPump = DeviceOn; Alarm (BeepAlarm); } break; case DoHeads: // Делаем головы BHeater = DeviceOff; if (SwitchBottle (BottleHeads)) { // Если выход не переключился - пытаемся обработать ошибку SHeater = DeviceOff; ErrorHandler (BotSwFail); return (1); } else { if (millis () >= (MyTimer + Params[RTDHeadsTime]*60000)) { // Проверяем время - если вышло - переходим к телу if (SwitchBottle (BottleBody)) { // Если выход не переключился - пытаемся обработать ошибку SHeater = DeviceOff; ErrorHandler (BotSwFail); return (1); } Stage = DoBody; Alarm (BeepAlarm); MyTimer = millis (); } } break; case DoBody: if (!(IgnoreFltr)) { if (digitalRead (FltrSensPin)) { if (NumOfBottles) { if (SwitchBottle (BottleHeads)) { // Если выход не переключился - пытаемся обработать ошибку SHeater = DeviceOff; ErrorHandler (BotSwFail); return (1); } Alarm (BBeepAlarm); } else { SHeater = DeviceOff; Alarm (BBeepAlarm); delay (300); Alarm (BBeepAlarm); MyTimer = millis (); if (millis () >= (MyTimer + Params[SBottleWait]*60000)) { DoRTD = StageOff; Stage = DoCool; } } } } if (millis () >= (MyTimer + Params[RTDRdyTime]*60000)) { Alarm (BBeepAlarm); MyTimer = millis() + 900000; } if (CubeTemp >= Params[MaxTempRTD]) { // Если температура куба превысила границу сбрасываем стадии выключаем грелку и переходим к охлаждению SHeater = DeviceOff; DoRTD = StageOff; Stage = DoCool; Alarm (BeepAlarm); } if (ClntTemp >= Params[CoolantEdge]) { // Если температура охлаждайки превысила границу - пытаемся обработать ошибку SHeater = DeviceOff; Stage = 0; ErrorHandler (CoolantOverheat); } break; case DoCool: MakeCool (); break; } return (0); } int ContRTD () { // Функция продолжения процесса заключительного перегона if (DoContRTD) { return (0); } switch (Stage) { case 0: Stage = Heating; break; case Heating: SHeater = DeviceOn; BHeater = DeviceOn; if (DeflTemp > Params[DeflEdge]) { //Если температура дефлегматора достигла границы переходим к головам - выключаем большую грелку и включаем насос. MyTimer = millis (); //Засекаем время Stage = DoBody; WtrPump = DeviceOn; Alarm (BeepAlarm); } break; case DoBody: if (!(IgnoreFltr)) { if (digitalRead (FltrSensPin)) { if (NumOfBottles) { if (SwitchBottle (BottleHeads)) { // Если выход не переключился - пытаемся обработать ошибку SHeater = DeviceOff; ErrorHandler (BotSwFail); return (1); } Alarm (BBeepAlarm); } else { SHeater = DeviceOff; Alarm (BBeepAlarm); delay (300); Alarm (BBeepAlarm); MyTimer = millis (); if (millis () >= (MyTimer + Params[SBottleWait]*60000)) { Stage = 0; DoContRTD = StageOff; Stage = DoCool; } } } } if (millis () >= (MyTimer + Params[RTDContTime]*60000)) { Alarm (BBeepAlarm); MyTimer = millis() + 900000; } if (CubeTemp >= Params[MaxTempRTD]) { // Если температура куба превысила границу сбрасываем стадии выключаем грелку и переходим к охлаждению SHeater = DeviceOff; DoContRTD = StageOff; Stage = DoCool; Stage = 0; Alarm (BeepAlarm); } if (ClntTemp >= Params[CoolantEdge]) { // Если температура охлаждайки превысила границу - пытаемся обработать ошибку SHeater = DeviceOff; Stage = 0; ErrorHandler (CoolantOverheat); } break; case DoCool: MakeCool (); break; } return (0); } void setup() { MyPinsSetup (); Serial.begin(9600); while (!Serial) { } SD.begin(chipSelect); myGLCD.InitLCD(); myGLCD.setFont(SmallFont); myGLCD.clrScr(); myTouch.InitTouch(); myTouch.setPrecision(PREC_MEDIUM); if (!ds.search(addr1)) { ErrorHandler (DSFail); } if (!ds.search(addr2)) { ErrorHandler (DSFail); } if (!ds.search(addr3)) { ErrorHandler (DSFail); } Serial.println("Start"); } boolean TakeTouch () { // Обслуживает тачскреен if (myTouch.dataAvailable()) { myTouch.read(); x=myTouch.getX(); y=myTouch.getY(); return (true); } else { return (false); } } extern int __bss_end; extern void *__brkval; int memoryFree() { int freeValue; if((int)__brkval == 0) freeValue = ((int)&freeValue) - ((int)&__bss_end); else freeValue = ((int)&freeValue) - ((int)__brkval); return freeValue; } void loop() { Screens (); MakeCC (); MakeSt2 (); ContSt2 (); MakeRTD (); ContRTD (); SwitchDevs (); SysError = SysCheck (); ErrorHandler (SysError); Serial.println (memoryFree ()); if (IgnoreFltr) { if ((FltrTimer+300000) < millis ()) { IgnoreFltr = 0; } } }
Можете подсказать что-нибудь умное?
Единственное, что могу подсказать сходу - не передавать сложные объекты по значению в функции, т.е. вот такое:
заменять на такое:
Спасибо!
Я хоть и старый, но тоже чайник. Объясните мне, пожалуйста, что означает вышенаписанная крокозябра.
Или где почитать про это доступным языком?
А может его вообще не передавать?
Объявить как "volatile" и обращаться напрямую?
Решил я заново автоматизировать свой процесс самогоноварения.
Пункт 8 вот здесь не смущает? :)
Для себя уже лет 10 разрешено! А я принципиально не торгую, друзей за так угощаю, ну если шашлыка привезут ;)
Не рекламы ради а здоровия для: homedistiller.ru
Спасибо!
Я хоть и старый, но тоже чайник. Объясните мне, пожалуйста, что означает вышенаписанная крокозябра.
Или где почитать про это доступным языком?
Вышенаписанная кракозябра означает передачу по ссылке. Подробности - в любом учебнике по языку С++.
Кстати, если кто из Питера и любитель бани и самогона - Вэлкам!
А может его вообще не передавать?
Объявить как "volatile" и обращаться напрямую?
Как volatile не надо объявлять, избыточно. А если объект класса File используется всего один - то тогда можно и не передавать в функции, а сделать его глобальной переменной и обращаться напрямую.
В том-то и дело, что в каждый конкретный момент времени только один, а всего в программе штук 70 файлов открывается, можно конечно переделать всё в один, но такая каша будет у меня мозг закипит. :(
Спасибо за помощь.
До завтра я в ауте.
А я понял. Вы ООП и классы не использовали. Вот и ваша простыня стремиться к саморазрушению.
в самогоноварении главное - объем аппарата для закладки исходного продукта, 200-400 литров и будет вам щастье
Главное это головы отделить, а остальное дело вкуса ;)
посмотрел код. Труд то какой , и комменты и отформатировано . Зачотно.
как то странно выглядит процесс отгона голов. Не понял, чем обеспечивается объем 10-15% от АС в режиме капельного отбора. То есть мощность для капельного отбора уже подобрана? И чисто по времени?
тс походу применяет дробный процесс с автоматической сменой приемных емкостей.
интересно подача линейная , или карусельная?
Главное это головы отделить, а остальное дело вкуса ;)
посмотрел код. Труд то какой , и комменты и отформатировано . Зачотно.
как то странно выглядит процесс отгона голов. Не понял, чем обеспечивается объем 10-15% от АС в режиме капельного отбора. То есть мощность для капельного отбора уже подобрана? И чисто по времени?
тс походу применяет дробный процесс с автоматической сменой приемных емкостей.
интересно подача линейная , или карусельная?
Головы отделяю на всех трех этапах.
Сейчас процесс автоматизирован на 328 меге с LCD 16х2, только функционал убогий. Зато технология отработана.
Поэтому с написанием скетча неторопился и комментировал и форматировал, месяца два писал, торопиться то некуда.
Головы отбираются просто на минимальной мощности - маленький ТЭН, потому-что число-импульсную регулировку применить нельзя, а с фазовым управлением пока не заморачивался, да и помехи... Заполняя куб на второй - третьей перегонке стараюсь довести крепость до одного значения около 40%, поэтому по времени отбор получается адекватным.
Смена емкостей это громко сказано, одна емкость для голов, вторая для тела. Будет тупо переключается выход холодильника.
Сейчас емкости надо менять руками, поэтому требуется присмотр при отборе голов, и потом нужно следить чтобы приемная емкость не переполнилась. Да и вообще мало ли что, потому что ни проток воды не контролируется ни работа тэнов.
А хочется чтобы залил, емкости поставил, кнопку нажал и пошел на халтуру не беспокоясь о возможных факапах.
Вот и пилю железяку:
А собственно по теме вопроса идеи есть? А то пока только полтора совета было.
У Вас есть место в программной памяти. Попробуйте строки для экранов хранить не в файлах, а в пямяти программ( flash) через PROGMEM.
Мне видится, что файловые операции жрут немеряно оперативки.
Вам что рассказывать про ООП и как писать структурированую программу? И самое главное зачем это надо.
Честно говоря об ООП у меня весьма смутные представление, во времена молодости, когда меня учили программированию, "в тренде" были бэйсик и паскаль, а там ООП не было, а сейчас на пятом десятке сложно менять парадигму программирования.
Тем более, что я очень плохо представляю ЗАЧЕМ ООП в этой программе, по сути построенной на конечных автоматах.
Так что если сможете дать несколько понятных советов или объяснений буду вам премного благодарен.
У Вас есть место в программной памяти. Попробуйте строки для экранов хранить не в файлах, а в пямяти программ( flash) через PROGMEM.
Мне видится, что файловые операции жрут немеряно оперативки.
Я думал об этом, но там в файлах еще прорва чисел - координат на экране, так что придется наворотить пару процедур вокруг преобразования pgm_read в int и string, что тоже не облегчит программу.
К тому же судя по
Памяти до вала (примерно 6000 байт).
А без оптимизации, когда все работает memoryFree() дает 2800 байт.
Сложно, но надо. Тем более фундаментальных объянений что такое ООП и сигнальное программирование нет. По крайней мере книг, хотя попытки есть. Рассказывать про закон перехода количества в качество вам не надо. Вот и в программировании он тоже работает. Чем больше кода, тем сложнее за ним уследить. Вот и начинают структурировать код программы. И цепочка Деталь->Изделие превращается Деталь->Узел->Изделие или в Деталь->Мелкие Узелы->Крупные Узелы->Изделие. Вот по этой причине произошел переход к Си , а потом с Си++ , и затем ООП Си++. Другие языки это обеспечивали хуже. Опять же есть 4 этап- заливка и отладка скетча. Вот вы на этом и зависли. Потому что чем длинее программы, тем сложнее ее тестировать. Но если у вас была бы структурирована программа. То тестировали каждый узел отдельно , а потом сборку целиком. Так меньше времени занимает этот процесс. Ну ООП позволяет написать именно структурированую программу. И опять же хорошо структурированую программу легче всего абгдейдить добавив дополнительные функции.
Единственное, что могу подсказать сходу - не передавать сложные объекты по значению в функции, т.е. вот такое:
заменять на такое:
Отделался я от передачи File в функции. Поскольку dataFile объявлен глобально, то и мороки было немного.
Но ничего не изменилось, как глючило при включеной оптимизации так и глючит.
Чёрт с ним, буду жить без оптимизации, а к тормознутости привыкну.
Кстате о тормознутости
0341
void
Alarm (
int
AlarmType) {
// Разнообразные сигналы сирены
0342
switch
(AlarmType) {
0343
case
BeepAlarm :
0344
digitalWrite (SirRelPin,DeviceOn);
0345
delay (150);
0346
digitalWrite (SirRelPin,DeviceOff);
0347
break
;
0348
case
BBeepAlarm :
0349
digitalWrite (SirRelPin,DeviceOn);
0350
delay (130);
0351
digitalWrite (SirRelPin,DeviceOff);
0352
delay (130);
0353
digitalWrite (SirRelPin,DeviceOn);
0354
delay (130);
0355
digitalWrite (SirRelPin,DeviceOff);
0356
break
;
0357
case
FullAlarm :
0358
digitalWrite (SirRelPin,DeviceOn);
0359
break
;
0360
case
StopAlarm :
0361
digitalWrite (SirRelPin,DeviceOff);
0362
break
;
0363
}
0364
}
delay видете . Привет тормознутость. К ней не привыкать надо, а от нее "лечить"
Вот еще пример тормознутости
0330
int
WaterFlowChk () {
// Проверяем состояние поплавка на переполнение бутылки
0331
int
State = digitalRead (WCircSensPin);
0332
unsigned
long
WtrFTimer = millis()+250;
0333
while
(millis () < WtrFTimer ) {
0334
if
(!(State == digitalRead (WCircSensPin))) {
0335
return
(0);
0336
}
0337
}
0338
return
(1);
0339
}
Скрытый delay
За делай в аларме не согласен, оно же не постоянно пищит. Ну тормозит во время бибипа, экран то выводится не в этот момент!
За делай в аларме не согласен, оно же не постоянно пищит. Ну тормозит во время бибипа, экран то выводится не в этот момент!
Именно так, все чтение с карты и вывод на экран идет внутри процедуры DrawFile();
А проверка протока воды, если этот самый проток есть 250 миллисекунд тоже не ждет, а завершается по приходу импульса от датчика, да и происходит не чаще раза за проход loop{}.
Другое дело, что внутри библиотеки UTFT может delay быть... Пойду поищу.
По любому писать блокирующие процедуры это плохая привычка ведущая к тормозам программы.