2019-10-04 16:40:19 +02:00
|
|
|
//////////////////////////////////////////////////////////////////////////////////// Stir Control V2 (mwx'2019)
|
2019-02-20 13:34:54 +01:00
|
|
|
#include <EEPROM.h>
|
|
|
|
#include <LiquidCrystal_I2C.h>
|
2019-03-09 15:09:06 +01:00
|
|
|
|
2019-02-20 13:34:54 +01:00
|
|
|
#define MS (long)millis()
|
2019-10-09 11:40:47 +02:00
|
|
|
#define NP 25
|
2019-02-20 13:34:54 +01:00
|
|
|
|
2019-11-05 14:49:48 +01:00
|
|
|
String VERSION = "2.1.2";
|
2019-03-06 08:53:06 +01:00
|
|
|
|
2019-10-08 14:17:10 +02:00
|
|
|
int FANINIT = 0; // initialize fan with high voltage (0/1)
|
2019-10-06 19:46:24 +02:00
|
|
|
|
|
|
|
int SPEEDINC1 = 20; // speed increment values
|
|
|
|
int SPEEDINC2 = 50;
|
|
|
|
int SPEEDINC3 = 100;
|
|
|
|
|
|
|
|
int SPEEDSTEP1 = 400; // speed increment steps (increment changes at these values)
|
|
|
|
int SPEEDSTEP2 = 1000;
|
|
|
|
|
|
|
|
int RNDINC = 50; // random value increment (rpm)
|
2019-02-20 13:34:54 +01:00
|
|
|
|
2019-03-09 15:09:06 +01:00
|
|
|
int FANMIN = 200; // fan minimum speed (should be a value at which the fan runs safely) (rpm)
|
2019-10-04 16:40:19 +02:00
|
|
|
int FANMAX = 2500; // fan maximum speed (should be the real maximum value of the fan) (rpm)
|
2019-02-20 13:34:54 +01:00
|
|
|
|
2019-10-08 14:17:10 +02:00
|
|
|
int BOFF = 0; // if set boost off will also turn the normal mode off (0/1)
|
2019-03-13 09:35:09 +01:00
|
|
|
|
2019-03-29 13:44:32 +01:00
|
|
|
int BINC = 1; // BTIME increment (min)
|
2019-03-13 09:35:09 +01:00
|
|
|
int CINC = 10; // CTIME increment (min)
|
2019-03-15 10:08:22 +01:00
|
|
|
int RINC = 10; // RTIME increment (sec)
|
2019-03-13 09:35:09 +01:00
|
|
|
int OINC = 3; // OTIME increment (hour)
|
|
|
|
|
2019-10-08 14:17:10 +02:00
|
|
|
int CATCHSTOP = 20; // fish catch stop period (sec)
|
2019-02-20 13:34:54 +01:00
|
|
|
|
|
|
|
int PWM0 = 9; // PWM pin for 1. fan
|
|
|
|
int PWM1 = 10; // PWM pin for 2. fan
|
2019-03-29 13:44:32 +01:00
|
|
|
int PWM2 = 11; // PWM pin for LCD brightness
|
|
|
|
|
2019-10-04 16:40:19 +02:00
|
|
|
int I0 = 0; // interrupt for fan 0 rpm signal (use 2 for Leonardo/ProMicro and 0 for Uno)
|
|
|
|
int I1 = 1; // interrupt for fan 1 rpm signal (use 3 for Leonardo/ProMicro and 1 for Uno)
|
2019-10-06 19:46:24 +02:00
|
|
|
|
2019-10-09 11:40:47 +02:00
|
|
|
int SWAPENC = 1; // swap encoder direction
|
2019-02-20 13:34:54 +01:00
|
|
|
|
2019-10-06 19:46:24 +02:00
|
|
|
int CLK = 5; // clk on KY-040 encoder (swap clk and dt to invert direction)
|
2019-02-20 13:34:54 +01:00
|
|
|
int DT = 6; // dt on KY-040 encoder
|
|
|
|
int SW = 4; // sw on KY-040 encoder
|
|
|
|
|
2019-10-04 16:40:19 +02:00
|
|
|
int R0 = 7; // voltage select relais 0
|
|
|
|
int R1 = 8; // voltage select relais 1
|
|
|
|
int RTHRES = 700; // voltage switch threshold (rpm)
|
2019-03-29 13:44:32 +01:00
|
|
|
|
2019-10-09 11:40:47 +02:00
|
|
|
int RINTERVAL = 50; // regulation internval (ds)
|
|
|
|
int RDELAY = 30; // regulation delay on changes (ds)
|
2019-02-25 19:20:47 +01:00
|
|
|
int RTOL = 8; // regulation tolerance (rpm)
|
2019-02-21 10:34:25 +01:00
|
|
|
|
2019-10-08 14:17:10 +02:00
|
|
|
int RNDINTERVAL = 300; // randon value range change interval (sec)
|
2019-06-02 14:20:59 +02:00
|
|
|
|
2019-10-09 11:40:47 +02:00
|
|
|
int SINTERVAL = 20; // speed measurement internval (ds)
|
2019-02-25 19:20:47 +01:00
|
|
|
int SAVERAGE = 4; // speed measurement average
|
|
|
|
|
2019-10-09 11:40:47 +02:00
|
|
|
int SAVETAG = 2017; // save tag
|
2019-03-20 10:24:55 +01:00
|
|
|
long SAVEDELAY = 10000; // EEPROM save delay (ms)
|
2019-02-20 13:34:54 +01:00
|
|
|
|
2019-10-09 11:40:47 +02:00
|
|
|
int RESET = 0; // factory reset, DON'T CHANGE THIS HERE (used from configuration menu)
|
|
|
|
|
2019-10-08 14:17:10 +02:00
|
|
|
int LGHT = 5; // LCD brightness
|
|
|
|
|
2019-03-29 13:44:32 +01:00
|
|
|
byte LCDB[] = {4,8,16,24,32,64,96,128,192,255}; // LCD brightness steps (10 values, 0=off, 255=max)
|
|
|
|
|
2019-03-09 15:09:06 +01:00
|
|
|
byte aright[] = {0x00,0x08,0x0C,0x0E,0x0C,0x08,0x00,0x00}; // LCD character
|
|
|
|
byte aup[] = {0x04,0x0E,0x1F,0x00,0x00,0x00,0x00,0x00};
|
2019-06-02 14:20:59 +02:00
|
|
|
byte arnd[] = {0x0E,0x0E,0x0E,0x00,0x00,0x00,0x00,0x00};
|
|
|
|
|
2019-02-20 13:34:54 +01:00
|
|
|
LiquidCrystal_I2C lcd(0x27,16,2); // LCD display (connect to SDA/SCL)
|
|
|
|
|
2019-03-09 15:09:06 +01:00
|
|
|
int v[2],b[2],r[2]={0};double q,rpm[2]={0},xpm[2]={0},xb[2]={0},xv[2]={0},rtime[2]; // speed and regulation
|
|
|
|
long ac[2]={0},bc[2]={0}; // interrupt rpm counter
|
2019-06-02 14:20:59 +02:00
|
|
|
long xts,sts,rts,swts,buts,savets,catts[2],stop[2],bts[2],vts[2],ots[2],rndts[2]; // timing
|
2019-10-08 14:17:10 +02:00
|
|
|
int bdelay,bprocess=0,enclast,encval,M=2,S=0,C=0; // button/encoder processing
|
2019-03-09 19:38:55 +01:00
|
|
|
int F[2],bstate[2]={0},btime[2],cat[2],ctime[2],cstate[2]={0},bclr=0,SAVE=0,LOCK=0; // operating states
|
2019-03-11 13:40:37 +01:00
|
|
|
int ostate[2]={0},otime[2]={0}; // off timer
|
2019-06-02 14:20:59 +02:00
|
|
|
int rnd[2]={0},rnval[2]={0};long seed; // random speed
|
2019-10-04 16:40:19 +02:00
|
|
|
char form[8],out[20]; // string buffer
|
2019-10-08 14:17:10 +02:00
|
|
|
String CF[NP];int *P[NP],Cinc[NP],Cmin[NP],Cmax[NP]; // configuration menu
|
2019-10-08 14:25:08 +02:00
|
|
|
int clkorg,dtorg; // encoder direction
|
2019-03-06 08:53:06 +01:00
|
|
|
|
2019-10-09 11:40:47 +02:00
|
|
|
void(* resetFunc) (void) = 0;
|
|
|
|
|
2019-03-09 15:09:06 +01:00
|
|
|
void setup() { ////////////////////////////////////////////////////////////////////////////////////////// SETUP
|
2019-10-09 11:40:47 +02:00
|
|
|
|
|
|
|
int i=0;
|
2019-10-08 14:17:10 +02:00
|
|
|
|
2019-10-09 11:40:47 +02:00
|
|
|
P[i]=&LGHT; CF[i]=F("LGHT"); defcon(i, 1, 0, 9 ); i++;
|
|
|
|
P[i]=&SPEEDINC1; CF[i]=F("SPI1"); defcon(i, 10, 10, 500 ); i++;
|
|
|
|
P[i]=&SPEEDINC2; CF[i]=F("SPI2"); defcon(i, 10, 10, 500 ); i++;
|
|
|
|
P[i]=&SPEEDINC3; CF[i]=F("SPI3"); defcon(i, 10, 10, 500 ); i++;
|
|
|
|
P[i]=&SPEEDSTEP1; CF[i]=F("SPS1"); defcon(i, 50, 100, 2000 ); i++;
|
|
|
|
P[i]=&SPEEDSTEP2; CF[i]=F("SPS2"); defcon(i, 50, 100, 2000 ); i++;
|
|
|
|
P[i]=&SWAPENC; CF[i]=F("SWEN"); defcon(i, 1, 0, 1 ); i++;
|
|
|
|
P[i]=&RNDINC; CF[i]=F("RINC"); defcon(i, 1, 0, 9 ); i++;
|
|
|
|
P[i]=&CATCHSTOP; CF[i]=F("CSTP"); defcon(i, 10, 0, 1000 ); i++;
|
|
|
|
P[i]=&FANMIN; CF[i]=F("FMIN"); defcon(i, 50, 100, 1000 ); i++;
|
|
|
|
P[i]=&FANMAX; CF[i]=F("FMAX"); defcon(i, 50, 500, 4000 ); i++;
|
|
|
|
P[i]=&FANINIT; CF[i]=F("FINI"); defcon(i, 1, 0, 1 ); i++;
|
|
|
|
P[i]=&RTHRES; CF[i]=F("RTHR"); defcon(i, 50, 0, 1500 ); i++;
|
|
|
|
P[i]=&RNDINTERVAL; CF[i]=F("RINT"); defcon(i, 1, 0, 60 ); i++;
|
|
|
|
P[i]=&BOFF; CF[i]=F("BOFF"); defcon(i, 1, 0, 1 ); i++;
|
|
|
|
P[i]=&BINC; CF[i]=F("BINC"); defcon(i, 1, 1, 60 ); i++;
|
|
|
|
P[i]=&CINC; CF[i]=F("CINC"); defcon(i, 1, 1, 60 ); i++;
|
|
|
|
P[i]=&RINC; CF[i]=F("RINC"); defcon(i, 1, 1, 60 ); i++;
|
|
|
|
P[i]=&OINC; CF[i]=F("OINC"); defcon(i, 1, 1, 60 ); i++;
|
|
|
|
P[i]=&RINTERVAL; CF[i]=F("XINT"); defcon(i, 1, 10, 250 ); i++;
|
|
|
|
P[i]=&RDELAY; CF[i]=F("XDEL"); defcon(i, 1, 0, 100 ); i++;
|
|
|
|
P[i]=&RTOL; CF[i]=F("XTOL"); defcon(i, 1, 1, 100 ); i++;
|
|
|
|
P[i]=&SINTERVAL; CF[i]=F("SINT"); defcon(i, 1, 0, 100 ); i++;
|
|
|
|
P[i]=&SAVERAGE; CF[i]=F("SAVG"); defcon(i, 1, 1, 100 ); i++;
|
|
|
|
P[i]=&RESET; CF[i]=F("RSET"); defcon(i, 1, 0, 1 ); i++;
|
2019-10-06 19:46:24 +02:00
|
|
|
|
2019-06-02 14:20:59 +02:00
|
|
|
lcd.init();lcd.clear();lcd.backlight(); // initialize lcd
|
|
|
|
lcd.createChar(0,aright);lcd.createChar(1,aup);lcd.createChar(2,arnd); // load lcd characters
|
2019-03-29 13:44:32 +01:00
|
|
|
pinMode(PWM0,OUTPUT);pinMode(PWM1,OUTPUT);pinMode(PWM2,OUTPUT); // setup PWM pins
|
|
|
|
pinMode(CLK,INPUT);pinMode(DT,INPUT);pinMode(SW,INPUT); // setup KY-040 pins
|
2019-03-09 15:09:06 +01:00
|
|
|
digitalWrite(CLK,true);digitalWrite(DT,true);digitalWrite(SW,true); // turn ON pullup resistors
|
2019-10-04 16:40:19 +02:00
|
|
|
pinMode(R0,OUTPUT);pinMode(R1,OUTPUT); // setup voltage selcet relais pins
|
2019-02-21 16:21:32 +01:00
|
|
|
|
2019-02-20 13:34:54 +01:00
|
|
|
attachInterrupt(I0,rpmint0,FALLING); // setup interrupts vor rpm in
|
|
|
|
attachInterrupt(I1,rpmint1,FALLING);
|
|
|
|
|
|
|
|
TCCR1A=0;TCCR1B=0;TCNT1=0; // setup timer for 25 kHz PWM
|
2019-02-21 16:21:32 +01:00
|
|
|
TCCR1A=_BV(COM1A1)|_BV(COM1B1)|_BV(WGM11);TCCR1B=_BV(WGM13)|_BV(CS10);ICR1=320;
|
2019-02-20 13:34:54 +01:00
|
|
|
|
|
|
|
SAVE=0; // load/initialize settings
|
|
|
|
if (eer(0)!=SAVETAG) {
|
2019-10-08 14:17:10 +02:00
|
|
|
for (i=0;i<2;i++) {;v[i]=300;b[i]=700;btime[i]=30;cat[i]=0;ctime[i]=120;rtime[i]=60;F[i]=0;rnval[i]=0;}
|
|
|
|
seed=0;
|
2019-02-21 10:34:25 +01:00
|
|
|
eew(0,SAVETAG);save();
|
2019-02-20 13:34:54 +01:00
|
|
|
} else {
|
2019-10-08 14:17:10 +02:00
|
|
|
for (i=0;i<2;i++) {
|
2019-03-09 15:09:06 +01:00
|
|
|
v[i]=eer(1+i);b[i]=eer(3+i);btime[i]=eer(5+i);cat[i]=eer(7+i);
|
2019-06-02 14:20:59 +02:00
|
|
|
ctime[i]=eer(9+i);F[i]=eer(11+i);rtime[i]=eer(13+i);rnval[i]=eer(15+i);
|
2019-03-09 15:09:06 +01:00
|
|
|
}
|
2019-06-02 14:20:59 +02:00
|
|
|
seed=eer(100)+1;eew(100,seed);randomSeed(seed);
|
2019-10-08 14:17:10 +02:00
|
|
|
for (i=0;i<NP;i++) *P[i]=eer(200+i);
|
2019-02-20 13:34:54 +01:00
|
|
|
}
|
|
|
|
|
2019-10-09 11:40:47 +02:00
|
|
|
clkorg=CLK;dtorg=DT;if (SWAPENC) {;DT=clkorg;CLK=dtorg;} // swap encoder direction
|
2019-10-08 14:17:10 +02:00
|
|
|
|
2019-03-29 13:44:32 +01:00
|
|
|
lset();
|
|
|
|
|
2019-02-20 13:34:54 +01:00
|
|
|
enclast=digitalRead(CLK); // get encoder state
|
2019-02-25 19:20:47 +01:00
|
|
|
|
2019-10-09 11:40:47 +02:00
|
|
|
for (i=0;i<2;i++) catts[i]=stop[i]=vts[i]=ots[i]=rndts[i]=MS;xts=sts=rts=swts=buts=savets=MS; // timer
|
2019-03-09 15:09:06 +01:00
|
|
|
updatePWM();updatelcd();updatespeed();updatemarker(); // update all
|
2019-03-09 19:38:55 +01:00
|
|
|
|
|
|
|
slcd(0,0,5,VERSION); // show version
|
2019-10-08 14:17:10 +02:00
|
|
|
|
|
|
|
if (FANINIT) { // setup fans
|
2019-10-08 14:25:08 +02:00
|
|
|
digitalWrite(R0,LOW);digitalWrite(R1,LOW);delay(3000);digitalWrite(R0,HIGH);digitalWrite(R1,HIGH);
|
2019-10-08 14:17:10 +02:00
|
|
|
}
|
2019-02-20 13:34:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void loop() { //////////////////////////////////////////////////////////////////////////////////////////// LOOP
|
|
|
|
|
2019-03-09 15:09:06 +01:00
|
|
|
if (SAVE>0 && MS-savets>SAVEDELAY) {;save();SAVE=0;savets=MS;} ////////////////////// save settings if needed
|
2019-03-09 19:38:55 +01:00
|
|
|
if (MS-savets>SAVEDELAY/5) bclr=1;
|
|
|
|
|
2019-03-09 15:09:06 +01:00
|
|
|
for (int i=0;i<2;i++) {
|
2019-06-02 14:20:59 +02:00
|
|
|
|
2019-10-08 14:17:10 +02:00
|
|
|
if (MS-rndts[i]>((long)RNDINTERVAL*1000)) { ////////////////////////////////////////////////// random timer
|
2019-06-02 14:20:59 +02:00
|
|
|
rnd[i]=int(random(0,rnval[i]+1)/10)*10;rndts[i]=MS;updatelcd();
|
|
|
|
}
|
|
|
|
|
2019-03-11 13:40:37 +01:00
|
|
|
if (ostate[i] && MS-ots[i]>(long)otime[i]*3600000) { ////////////////////////////////////// check off timer
|
|
|
|
otime[i]=0;ostate[i]=0;fset(i,0);
|
|
|
|
}
|
|
|
|
|
2019-03-09 15:09:06 +01:00
|
|
|
if (cat[i] && MS-catts[i]>(long)ctime[i]*60000 && F[i]==1) { //////////////////////////// initiate cat fish
|
|
|
|
catts[i]=MS;cstate[i]=1;F[i]=0;stop[i]=MS;updatePWM();updatespeed();
|
|
|
|
}
|
|
|
|
|
2019-10-08 14:17:10 +02:00
|
|
|
if (cstate[i] && MS-stop[i]>((long)CATCHSTOP*1000) && F[i]==0) { ///////////// stop cat fish and start over
|
2019-03-09 15:09:06 +01:00
|
|
|
cstate[i]=0;F[i]=1;vts[i]=MS;rts=MS+2000;updatePWM();updatespeed();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bstate[i] && MS-bts[i]>(long)btime[i]*60000) {;bstate[i]=0;S=0;updatelcd();} //////// check boost state
|
|
|
|
|
|
|
|
}
|
2019-02-20 13:34:54 +01:00
|
|
|
|
2019-10-09 11:40:47 +02:00
|
|
|
if (MS-xts>(SINTERVAL*100)) { ///////////////////////////////////////////////////////////// speed measurement
|
2019-03-09 15:09:06 +01:00
|
|
|
for (int i=0;i<2;i++) xpm[i]=xpm[i]*(SAVERAGE-1)/SAVERAGE+(bc[i]/((MS-xts)/1000.0)*30.0)/SAVERAGE;
|
|
|
|
updatespeed();xts=MS;bc[0]=0;bc[1]=0;
|
2019-02-25 19:20:47 +01:00
|
|
|
}
|
|
|
|
|
2019-10-09 11:40:47 +02:00
|
|
|
if (MS-rts>(RINTERVAL*100)) { ////////////////////////////////////////////////////////////// speed regulation
|
2019-03-09 15:09:06 +01:00
|
|
|
for (int i=0;i<2;i++) {
|
|
|
|
rpm[i]=ac[i]/((MS-sts)/1000.0)*30.0;
|
|
|
|
ac[i]=0;
|
|
|
|
calcramp(i);
|
|
|
|
if (!F[i]) {;r[i]=0;setPWM(i,0);}
|
|
|
|
else {
|
|
|
|
q=(bstate[i]?xb[i]:xv[i])-rpm[i];
|
|
|
|
if (abs(q)>RTOL) r[i]=q<0?r[i]-1-abs(q)/10:r[i]+1+abs(q)/10;
|
|
|
|
setPWM(i,cut((bstate[i]?xb[i]:xv[i])/(FANMAX/320.0)+r[i],0,320));
|
|
|
|
}
|
2019-02-25 19:20:47 +01:00
|
|
|
}
|
|
|
|
|
2019-03-09 15:09:06 +01:00
|
|
|
sts=MS;rts=MS;
|
|
|
|
updatespeed();
|
2019-02-25 19:20:47 +01:00
|
|
|
}
|
2019-02-20 13:34:54 +01:00
|
|
|
|
|
|
|
bdelay=0; //////////////////////////////////////////////////////////////////////////////////// process switch
|
|
|
|
if (!bprocess) {
|
|
|
|
while (!digitalRead(SW)){
|
2019-07-07 16:16:53 +02:00
|
|
|
bdelay++;delay(15);bprocess=1;if (bdelay>20) break;
|
2019-02-20 13:34:54 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-09 15:09:06 +01:00
|
|
|
if (bdelay>0 && MS-buts>100) { // long button press
|
2019-02-20 13:34:54 +01:00
|
|
|
if (bdelay>20) {
|
|
|
|
|
2019-03-09 15:09:06 +01:00
|
|
|
if (M==2) { // lock/unlock
|
2019-02-20 13:34:54 +01:00
|
|
|
if (LOCK==0) LOCK=1;
|
|
|
|
else LOCK=0;
|
2019-03-20 10:24:55 +01:00
|
|
|
updatemarker();
|
2019-03-09 15:09:06 +01:00
|
|
|
} else {
|
|
|
|
if (S==0 && !LOCK) { // fan on/off
|
|
|
|
if (F[M]==0) fset(M,1); else fset(M,0);
|
|
|
|
}
|
|
|
|
if (S==1 && !LOCK) { // boost on/off
|
2019-03-13 09:35:09 +01:00
|
|
|
if (bstate[M]==0) bset(M,1); else {;bset(M,0);if (BOFF) fset(M,0);}
|
2019-03-09 19:38:55 +01:00
|
|
|
bclr=1;
|
2019-03-09 15:09:06 +01:00
|
|
|
}
|
2019-10-08 14:17:10 +02:00
|
|
|
if (S==8 && !LOCK) { // exit config mode
|
|
|
|
M=2;save();updatemarker();
|
|
|
|
if (SWAPENC) {;DT=clkorg;CLK=dtorg;}
|
|
|
|
else {;DT=dtorg;CLK=clkorg;}
|
2019-10-09 11:40:47 +02:00
|
|
|
if (RESET==1) {;RESET=0;eew(0,0);save();resetFunc();}
|
2019-10-08 14:17:10 +02:00
|
|
|
}
|
2019-02-20 13:34:54 +01:00
|
|
|
}
|
|
|
|
|
2019-03-20 10:24:55 +01:00
|
|
|
save();updatespeed();bdelay=0;
|
2019-02-20 13:34:54 +01:00
|
|
|
|
2019-02-25 19:20:47 +01:00
|
|
|
} else if (bdelay>0 && bdelay<20 && !LOCK) { // short button press, switch: menu -> fan 0 -> fan 1
|
2019-10-08 14:17:10 +02:00
|
|
|
M++;
|
|
|
|
if (S==8 && M==2) M=0;
|
|
|
|
if (M>2) M=0;
|
2019-02-20 13:34:54 +01:00
|
|
|
updatemarker();
|
|
|
|
bdelay=0;
|
|
|
|
}
|
|
|
|
|
2019-03-09 15:09:06 +01:00
|
|
|
SAVE++;buts=MS;
|
2019-02-20 13:34:54 +01:00
|
|
|
}
|
|
|
|
if (digitalRead(SW)) bprocess=0;
|
|
|
|
|
|
|
|
encval = digitalRead(CLK); ////////////////////////////////////////////////////////////////// process encoder
|
|
|
|
if (encval != enclast && !LOCK) {
|
|
|
|
if(!encval){
|
2019-10-06 19:46:24 +02:00
|
|
|
|
2019-02-21 16:21:32 +01:00
|
|
|
if (digitalRead(DT) != encval) { // turn encoder clockwise
|
2019-10-08 14:17:10 +02:00
|
|
|
if (M==2) S++; // scroll menu
|
2019-03-09 15:09:06 +01:00
|
|
|
else {
|
2019-10-06 19:46:24 +02:00
|
|
|
if (S==0) v[M]=speedinc(v[M],1); // fan speed up
|
|
|
|
if (S==1) b[M]=speedinc(b[M],1); // boost speed up
|
|
|
|
if (S==2) btime[M]+=BINC; // boost time up
|
|
|
|
if (S==3) cat[M]++; // cat on/off
|
|
|
|
if (S==4) ctime[M]+=CINC; // cat time up
|
|
|
|
if (S==5) rtime[M]+=RINC; // rise time up
|
|
|
|
if (S==6) otime[M]+=OINC; // off time up
|
|
|
|
if (S==7) rnval[M]+=RNDINC; // random value
|
2019-10-08 14:17:10 +02:00
|
|
|
if (S==8 && M==0) C++; // increase config menu
|
2019-10-09 11:40:47 +02:00
|
|
|
|
|
|
|
if (S==8 && M==1) *P[C]=cut(*P[C]+Cinc[C],Cmin[C],Cmax[C]); // increase configuration value
|
2019-03-09 15:09:06 +01:00
|
|
|
}
|
2019-02-21 16:21:32 +01:00
|
|
|
} else { // turn encoder counterclockwise
|
2019-10-08 14:17:10 +02:00
|
|
|
if (M==2) S--; // scroll menu
|
2019-03-09 15:09:06 +01:00
|
|
|
else {
|
2019-10-06 19:46:24 +02:00
|
|
|
if (S==0) v[M]=speedinc(v[M],0); // fan speed down
|
|
|
|
if (S==1) b[M]=speedinc(b[M],0); // boost speed down
|
|
|
|
if (S==2) btime[M]-=BINC; // boost time down
|
|
|
|
if (S==3) cat[M]--; // cat on/off
|
|
|
|
if (S==4) ctime[M]-=CINC; // cat time down
|
|
|
|
if (S==5) rtime[M]-=RINC; // rise time down
|
|
|
|
if (S==6) otime[M]-=OINC; // off time down
|
|
|
|
if (S==7) rnval[M]-=RNDINC; // random value
|
2019-10-08 14:17:10 +02:00
|
|
|
if (S==8 && M==0) C--; // decrease config menu
|
2019-10-09 11:40:47 +02:00
|
|
|
|
|
|
|
if (S==8 && M==1) *P[C]=cut(*P[C]-Cinc[C],Cmin[C],Cmax[C]); // decrease configuration value
|
2019-03-09 15:09:06 +01:00
|
|
|
}
|
2019-02-20 13:34:54 +01:00
|
|
|
}
|
2019-02-25 19:20:47 +01:00
|
|
|
|
2019-03-09 15:09:06 +01:00
|
|
|
for (int i=0;i<2;i++) if (b[i]<v[i]) b[i]=v[i];
|
|
|
|
|
|
|
|
if (M!=2) {
|
2019-10-09 11:40:47 +02:00
|
|
|
if (S<=1) {;updatePWM();rts=MS+(RDELAY*100);} // apply (boost) speed change
|
2019-03-29 13:44:32 +01:00
|
|
|
if (S==2) btime[M]=cut(btime[M],0,99); // check boost time
|
2019-03-20 14:45:16 +01:00
|
|
|
if (S==3) {;cat[M]=cut(cat[M],0,1);catts[M]=MS;} // check cat
|
2019-03-11 13:40:37 +01:00
|
|
|
if (S==4) ctime[M]=cut(ctime[M],60,240); // check cat time
|
|
|
|
if (S==5) rtime[M]=cut(rtime[M],0,240); // check rise time
|
|
|
|
if (S==6) oset(M,otime[M]); // check off time
|
2019-06-02 14:20:59 +02:00
|
|
|
if (S==7) {;rnval[M]=cut(rnval[M],0,1000);updatePWM();} // apply random value change
|
2019-10-08 14:17:10 +02:00
|
|
|
if (S==8 && C==0) lset(); // set LCD brightness
|
2019-03-09 15:09:06 +01:00
|
|
|
}
|
2019-02-25 19:20:47 +01:00
|
|
|
|
2019-10-09 11:40:47 +02:00
|
|
|
C=cut(C,0,NP-1); // check configuration mode
|
2019-10-08 14:17:10 +02:00
|
|
|
|
2019-06-02 14:20:59 +02:00
|
|
|
if (M==2) S=cut(S,0,8); // check menu mode
|
2019-02-20 13:34:54 +01:00
|
|
|
|
2019-07-07 16:16:53 +02:00
|
|
|
SAVE++;updatelcd();delay(25);
|
2019-02-20 13:34:54 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
enclast=encval;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-03-09 19:38:55 +01:00
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////// SUPPORT
|
|
|
|
|
2019-10-08 14:17:10 +02:00
|
|
|
void defcon(int n, int inc, int min, int max) { ///////////////////////////////////////////// set config limits
|
|
|
|
Cinc[n]=inc; Cmin[n]=min; Cmax[n]=max;
|
|
|
|
}
|
|
|
|
|
2019-10-06 19:46:24 +02:00
|
|
|
int speedinc(int s,int mode) { ////////////////////////////////////////////////////// calculate speed increment
|
|
|
|
if (mode==0) {
|
|
|
|
if (s<=SPEEDSTEP1) return s-SPEEDINC1;
|
|
|
|
if (s<=SPEEDSTEP2) return s-SPEEDINC2;
|
|
|
|
return s-SPEEDINC3;
|
|
|
|
}
|
|
|
|
if (mode==1) {
|
|
|
|
if (s<SPEEDSTEP1) return s+SPEEDINC1;
|
|
|
|
if (s<SPEEDSTEP2) return s+SPEEDINC2;
|
|
|
|
return s+SPEEDINC3;
|
|
|
|
}
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
2019-03-29 13:44:32 +01:00
|
|
|
void lset() { ////////////////////////////////////////////////////////////////////////////// set LCD brightness
|
2019-10-08 14:17:10 +02:00
|
|
|
LGHT=cut(LGHT,0,9);
|
|
|
|
analogWrite(PWM2,LCDB[LGHT]);
|
2019-03-29 13:44:32 +01:00
|
|
|
}
|
|
|
|
|
2019-03-11 13:40:37 +01:00
|
|
|
void oset(int n,int t) { ///////////////////////////////////////////////////////////////// set switch off timer
|
|
|
|
otime[n]=cut(t,0,99);ots[n]=MS;ostate[n]=otime[n]?1:0;
|
2019-03-12 09:36:26 +01:00
|
|
|
SAVE++;
|
2019-03-11 13:40:37 +01:00
|
|
|
}
|
|
|
|
|
2019-03-09 15:09:06 +01:00
|
|
|
void fset(int n,int s) { /////////////////////////////////////////////////////////////// set fan state (on/off)
|
|
|
|
if (s==1) {
|
2019-10-09 11:40:47 +02:00
|
|
|
rts=MS+(RDELAY*100);F[n]=1;catts[n]=vts[n]=MS;r[n]=0;
|
2019-03-09 15:09:06 +01:00
|
|
|
} else {
|
|
|
|
F[n]=0;bstate[n]=0;
|
|
|
|
}
|
2019-03-29 13:44:32 +01:00
|
|
|
updatePWM();
|
2019-03-12 09:36:26 +01:00
|
|
|
SAVE++;
|
2019-03-09 15:09:06 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void bset(int n,int s) { ///////////////////////////////////////////////////////////// set boost state (on/off)
|
|
|
|
if (s==1) {
|
2019-10-09 11:40:47 +02:00
|
|
|
rts=MS+(RDELAY*100);bstate[n]=1;bts[n]=MS;F[n]=1;vts[n]=MS;
|
2019-03-09 15:09:06 +01:00
|
|
|
} else {
|
2019-10-09 11:40:47 +02:00
|
|
|
bstate[n]=0;rts=MS+(RDELAY*100);
|
2019-03-09 15:09:06 +01:00
|
|
|
}
|
2019-03-29 13:44:32 +01:00
|
|
|
updatePWM();
|
2019-03-12 09:36:26 +01:00
|
|
|
SAVE++;
|
2019-03-09 15:09:06 +01:00
|
|
|
}
|
|
|
|
|
2019-02-20 13:34:54 +01:00
|
|
|
void updatelcd() { ///////////////////////////////////////////////////////////////////////////////// update LCD
|
2019-10-08 14:17:10 +02:00
|
|
|
|
2019-03-09 15:09:06 +01:00
|
|
|
for (int i=0;i<2;i++) {
|
2019-10-09 11:40:47 +02:00
|
|
|
if (S==0) {;slcd(1,1,5,F("SPEED"));ilcd(7+i*5,1,-4,v[i]);}
|
|
|
|
if (S==1) {;slcd(1,1,5,F("BOOST"));ilcd(7+i*5,1,-4,int(b[i]));}
|
|
|
|
if (S==2) {;slcd(1,1,5,F("BTIME"));ilcd(7+i*5,1,-4,int(btime[i]));}
|
2019-03-09 15:09:06 +01:00
|
|
|
if (S==3) {
|
2019-10-09 11:40:47 +02:00
|
|
|
slcd(1,1,5,F("CATCH"));
|
|
|
|
if (cat[i]==0) slcd( 7+i*5,1,-4,F("OFF")); else slcd( 7+i*5,1,-3,F("ON"));
|
2019-03-09 15:09:06 +01:00
|
|
|
}
|
2019-10-09 11:40:47 +02:00
|
|
|
if (S==4) {;slcd(1,1,5,F("CTIME"));ilcd(7+i*5,1,-4,int(ctime[i]));}
|
|
|
|
if (S==5) {;slcd(1,1,5,F("RTIME"));ilcd(7+i*5,1,-4,int(rtime[i]));}
|
|
|
|
if (S==6) {;slcd(1,1,5,F("OTIME"));ilcd(7+i*5,1,-4,int(otime[i]));}
|
|
|
|
if (S==7) {;slcd(1,1,5,F("RNVAL"));ilcd(7+i*5,1,-4,int(rnval[i]));}
|
2019-02-20 13:34:54 +01:00
|
|
|
}
|
2019-10-09 11:40:47 +02:00
|
|
|
if (S==8) {;slcd(1,1,-5,F("CFG"));slcd(7,1,-4,CF[C]);ilcd(7+5,1,-4,*P[C]);}
|
2019-02-20 13:34:54 +01:00
|
|
|
}
|
2019-10-08 14:17:10 +02:00
|
|
|
|
2019-03-06 08:53:06 +01:00
|
|
|
void updatemarker() { ////////////////////////////////////////////////////////////////////// update menu marker
|
2019-10-09 11:40:47 +02:00
|
|
|
slcd(0,1,1,F(" "));slcd(6,1,1,F(" "));slcd(11,1,1,F(" "));
|
2019-03-09 15:09:06 +01:00
|
|
|
int m[]={6,11,0};if (!LOCK) clcd(m[M],1,0);
|
2019-02-20 13:34:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void updatespeed() { ///////////////////////////////////////////////////////////////////////// update fan speed
|
2019-10-09 11:40:47 +02:00
|
|
|
if (bclr) slcd(0,0,6,F(" "));
|
2019-03-09 15:09:06 +01:00
|
|
|
for (int i=0;i<2;i++) {
|
|
|
|
slcd(6+i*5,0,1," ");
|
2019-10-09 11:40:47 +02:00
|
|
|
if (cstate[i]) slcd(7+i*5,0,-4,F("CAT"));
|
2019-03-09 15:09:06 +01:00
|
|
|
else {
|
|
|
|
if (F[i]) {
|
2019-03-09 19:38:55 +01:00
|
|
|
if (bstate[i]) ilcd(1+i*3,0,-2, (((long)btime[i]*60000)-(MS-(long)bts[i]))/1000/60+1);
|
2019-03-11 13:40:37 +01:00
|
|
|
else if (ostate[i]) ilcd(1+i*3,0,-2, (((long)otime[i]*3600000)-(MS-(long)ots[i]))/1000/60/60+1);
|
2019-03-09 15:09:06 +01:00
|
|
|
ilcd(7+i*5,0,-4,round(xpm[i]));
|
|
|
|
if ((!bstate[i] && xv[i]<v[i]) || (bstate[i] && xb[i]<b[i])) clcd(6+i*5,0,1);
|
2019-06-02 14:20:59 +02:00
|
|
|
else {
|
|
|
|
if (xv[i]>=v[i] && rnval[i]>0 && !bstate[i]) clcd(6+i*5,0,2);
|
|
|
|
}
|
2019-10-09 11:40:47 +02:00
|
|
|
} else slcd(7+i*5,0,-4,F("OFF"));
|
2019-03-09 15:09:06 +01:00
|
|
|
}
|
2019-03-06 08:53:06 +01:00
|
|
|
}
|
2019-02-20 13:34:54 +01:00
|
|
|
}
|
|
|
|
|
2019-03-06 08:53:06 +01:00
|
|
|
void clcd(int x,int y, char v) { /////////////////////////////////////////////////////// write character to LCD
|
|
|
|
lcd.setCursor(x,y);lcd.write(v);
|
2019-02-20 13:34:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void ilcd(int x,int y, int l,int v) { //////////////////////////////////////////////////// write integer to LCD
|
2019-03-06 08:53:06 +01:00
|
|
|
sprintf(form,"%%%dd",l);sprintf(out,form,v);lcd.setCursor(x,y);lcd.print(out);
|
2019-02-20 13:34:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void slcd(int x,int y, int l,String s) { ////////////////////////////////////////////////// write string to LCD
|
2019-03-06 08:53:06 +01:00
|
|
|
sprintf(form,"%%%ds",l);sprintf(out,form,s.c_str());lcd.setCursor(x,y);lcd.print(out);
|
2019-02-20 13:34:54 +01:00
|
|
|
}
|
|
|
|
|
2019-03-09 15:09:06 +01:00
|
|
|
void calcramp(int i) { ///////////////////////////////////////////////////////////// calculate speed ramp value
|
2019-10-02 14:53:01 +02:00
|
|
|
xb[i]=b[i];
|
|
|
|
int rt=rtime[i]?rtime[i]:1;
|
|
|
|
if (bstate[i]) xb[i]=cut(((b[i]-v[i])/(rt*1000.0)*(MS-bts[i]))+v[i],v[i],b[i]);
|
|
|
|
xv[i]=v[i];
|
|
|
|
xv[i]=cut(((v[i]-FANMIN)/(rt*1000.0)*(MS-vts[i]))+FANMIN,FANMIN,v[i]);
|
2019-06-02 14:20:59 +02:00
|
|
|
if (rnval[i]>0 && xv[i]>=v[i]) xv[i]=cut(xv[i]+rnd[i],FANMIN,FANMAX);
|
2019-03-09 15:09:06 +01:00
|
|
|
}
|
|
|
|
|
2019-03-29 13:44:32 +01:00
|
|
|
void setPWM(int n,int v) { /////////////////////////////////////////// set value to OCR1x and states to off pin
|
2019-10-04 16:40:19 +02:00
|
|
|
if (n==0) OCR1A=v;
|
|
|
|
if (n==1) OCR1B=v;
|
2019-03-06 08:53:06 +01:00
|
|
|
}
|
2019-02-21 10:34:25 +01:00
|
|
|
|
2019-03-06 08:53:06 +01:00
|
|
|
void updatePWM() { ////////////////////////////////////////////////////////////// update PWM output (fan speed)
|
2019-03-09 15:09:06 +01:00
|
|
|
for (int i=0;i<2;i++) {
|
|
|
|
v[i]=cut(v[i],FANMIN,FANMAX);
|
|
|
|
b[i]=cut(b[i],FANMIN,FANMAX);
|
|
|
|
calcramp(i);
|
2019-10-04 16:40:19 +02:00
|
|
|
if (!F[i]) setPWM(i,0); else setPWM(i,cut((bstate[i]?xb[i]:xv[i])/(FANMAX/320.0)+r[i],1,320));
|
2019-03-09 15:09:06 +01:00
|
|
|
}
|
2019-10-04 16:40:19 +02:00
|
|
|
|
2019-11-05 14:49:48 +01:00
|
|
|
if ((bstate[0]?b[0]:v[0])>=RTHRES) digitalWrite(R0,LOW);
|
2019-10-04 16:40:19 +02:00
|
|
|
else digitalWrite(R0,HIGH);
|
|
|
|
|
2019-11-05 14:49:48 +01:00
|
|
|
if ((bstate[1]?b[1]:v[1])>=RTHRES) digitalWrite(R1,LOW);
|
2019-10-04 16:40:19 +02:00
|
|
|
else digitalWrite(R1,HIGH);
|
2019-02-20 13:34:54 +01:00
|
|
|
}
|
|
|
|
|
2019-03-09 15:09:06 +01:00
|
|
|
void rpmint0() {;ac[0]++;bc[0]++;} ///////////////////////////////////////////////////////////// rpm interrupts
|
|
|
|
void rpmint1() {;ac[1]++;bc[1]++;}
|
2019-02-20 13:34:54 +01:00
|
|
|
|
2019-02-21 10:34:25 +01:00
|
|
|
double cut(double v,double min,double max) {;return v>max?max:v<min?min:v>max?max:v;} ///// cut values to limit
|
2019-03-09 15:09:06 +01:00
|
|
|
|
2019-02-20 13:34:54 +01:00
|
|
|
int eer(int adr) {;return EEPROM.read(adr*2)+EEPROM.read(adr*2+1)*256;} /////////////////////////// read EEPROM
|
2019-03-09 15:09:06 +01:00
|
|
|
|
2019-02-20 13:34:54 +01:00
|
|
|
void eew(int adr, int val) {;EEPROM.write(adr*2,val%256);EEPROM.write(adr*2+1,val/256);} /////// save to EEPROM
|
|
|
|
|
|
|
|
void save() { /////////////////////////////////////////////////////////////////////////////////// save settings
|
2019-03-09 15:09:06 +01:00
|
|
|
for (int i=0;i<2;i++) {
|
|
|
|
eew(1+i,v[i]);eew(3+i,b[i]);eew(5+i,btime[i]);eew(7+i,cat[i]);
|
2019-06-02 14:20:59 +02:00
|
|
|
eew(9+i,ctime[i]);eew(11+i,F[i]);eew(13+i,rtime[i]);eew(15+i,rnval[i]);
|
2019-03-09 15:09:06 +01:00
|
|
|
}
|
2019-06-02 14:20:59 +02:00
|
|
|
eew(100,seed);
|
2019-10-08 14:17:10 +02:00
|
|
|
for (int i=0;i<NP;i++) eew(200+i,*P[i]);
|
2019-03-09 15:09:06 +01:00
|
|
|
}
|
|
|
|
|
2019-06-02 14:20:59 +02:00
|
|
|
/////////////////////////////////////////////////////////////////////////////////////////////////////////// END
|