various changes and additions

This commit is contained in:
Michael Wesemann 2019-02-25 19:20:47 +01:00
parent 44db8b9e68
commit 8be8fc23db
5 changed files with 81 additions and 56 deletions

View File

@ -10,7 +10,7 @@ This is the Arduino sketch to build a double magnetic stirrer based on 2 fans, a
In order to put the stirrer into operation you have to change the settings in stir.ino according to your setup. In order to put the stirrer into operation you have to change the settings in stir.ino according to your setup.
## Functions ## Overview of Functions
All functions are controlled by the KY-040 encoder: All functions are controlled by the KY-040 encoder:
@ -36,12 +36,15 @@ All functions are controlled by the KY-040 encoder:
|Value|Description| |Value|Description|
|:----|:----------| |:----|:----------|
|SPEEDINC|increment of speed values when turning the encoder| |SPEEDINC|increment of speed values when turning the encoder|
|FANMIN|fan minimum speed (should be a value at which the fan runs safely)| |FANMIN|fan minimum speed (should be a value at which the fan runs safely) (rpm)|
|FANMAX|maximum speed of the fan (it is important that this is the real maximum value of the fan)| |FANMAX|maximum speed of the fan (it is important that this is the real maximum value of the fan) (rpm)|
|RINTERVAL|regulation interval (ms)| |RINTERVAL|regulation interval (ms)|
|RDELAY|extra regulation delay when value changes (ms)| |RDELAY|extra regulation delay when value changes (ms)|
|RTOL|regulation tolerance| |RTOL|regulation tolerance (rpm)|
|CATCHSTOP|stop interval for stir fish catch function (ms)| |CATCHSTOP|stop interval for stir fish catch function (ms)|
|BOOSTRAMP|rise time for boost speed (ms)|
|SINTERVAL|speed measurement interval (ms)|
|SAVERAGE|speed measurement average|
|PWM0, PWN1|PWM output pins| |PWM0, PWN1|PWM output pins|
|I0, I1|interrupts for rpm measurement (2 and 3 for Leonardo and ProMicro / 0 and 1 for Uno)| |I0, I1|interrupts for rpm measurement (2 and 3 for Leonardo and ProMicro / 0 and 1 for Uno)|
|CLK, DT, SW|pins for KY-040 encoder| |CLK, DT, SW|pins for KY-040 encoder|
@ -50,6 +53,5 @@ All functions are controlled by the KY-040 encoder:
<p align="center"> <p align="center">
<img src="https://github.com/micworg/stir/blob/master/images/schematic_leonardo.png" width=500> <img src="https://github.com/micworg/stir/blob/master/images/schematic_leonardo.png" width=500>
<img src="https://github.com/micworg/stir/blob/master/images/schematic_promicro.png" width=500>
<img src="https://github.com/micworg/stir/blob/master/images/schematic_uno.png" width=500> <img src="https://github.com/micworg/stir/blob/master/images/schematic_uno.png" width=500>
</p> </p>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 117 KiB

After

Width:  |  Height:  |  Size: 125 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 119 KiB

After

Width:  |  Height:  |  Size: 128 KiB

125
stir.ino
View File

@ -1,4 +1,4 @@
/////////////////////////////////////////////////////////////////////////////// Stir Control (mwx'2019, v1.2.6) /////////////////////////////////////////////////////////////////////////////// Stir Control (mwx'2019, v1.3.0)
#include <EEPROM.h> #include <EEPROM.h>
#include <LiquidCrystal_I2C.h> #include <LiquidCrystal_I2C.h>
@ -6,12 +6,13 @@
#define SXN Serial.println #define SXN Serial.println
#define MS (long)millis() #define MS (long)millis()
int SPEEDINC = 50; // speed increment int SPEEDINC = 50; // speed increment (rpm)
int FANMIN = 200; // fan minimum speed int FANMIN = 200; // fan minimum speed (rpm)
int FANMAX = 1600; // fan maximum speed int FANMAX = 1000; // fan maximum speed (rpm)
int CATCHSTOP = 20000; // catch stop period int CATCHSTOP = 20000; // catch stop period (ms)
double BOOSTRAMP = 60000; // rise time for boost speed (ms)
int PWM0 = 9; // PWM pin for 1. fan int PWM0 = 9; // PWM pin for 1. fan
int PWM1 = 10; // PWM pin for 2. fan int PWM1 = 10; // PWM pin for 2. fan
@ -23,30 +24,33 @@ int CLK = 5;
int DT = 6; // dt on KY-040 encoder int DT = 6; // dt on KY-040 encoder
int SW = 4; // sw on KY-040 encoder int SW = 4; // sw on KY-040 encoder
int RINTERVAL = 5000; // regulation interval int RINTERVAL = 5000; // regulation interval (ms)
int RDELAY = 2000; // regulation delay on changes int RDELAY = 3000; // regulation delay on changes (ms)
int RTOL = 8; // regulation tolerance int RTOL = 8; // regulation tolerance (rpm)
int SAVETAG = 1004; // save tag int SINTERVAL = 2000; // speed measurement interval
int SAVERAGE = 4; // speed measurement average
int SAVETAG = 1006; // save tag
LiquidCrystal_I2C lcd(0x27,16,2); // LCD display (connect to SDA/SCL) LiquidCrystal_I2C lcd(0x27,16,2); // LCD display (connect to SDA/SCL)
int v0,b0,r0,v1,b1,r1,fanstate0,fanstate1; // speed and regulation int i,v0,b0,r0,v1,b1,r1,fanstate0,fanstate1; // speed and regulation
long rpmcount0,rpmcount1; // rpm counter long rpmcount0,rpmcount1,speedcount0,speedcount1; // rpm counter
double rpm0,rpm1; // rpm double r,rx,rpm0,rpm1,xpm0,xpm1,xb0,xb1; // rpm
long sts,rts,swts,bts,ox,savets,catchts0,catchts1,stop0,stop1,b0ts,b1ts; // timing long xts,sts,rts,swts,bts,ox,savets,catchts0,catchts1,stop0,stop1,b0ts,b1ts; // timing
int bdelay,bprocess,enclast,encval,swmode,mode; // button/encoder processing int bdelay,bprocess,enclast,encval,swmode,mode; // button/encoder processing
int OK,SAVE,LOCK,bstate0,bstate1,btime0,btime1,catch0,catch1,ctime0,ctime1; // operation state int OK,SAVE,LOCK,bstate0,bstate1,btime0,btime1,catch0,catch1,ctime0,ctime1; // operation state
char form[8],out[16];String str; // string buffer char form[8],out[128];String str; // string buffer
void setup() { ////////////////////////////////////////////////////////////////////////////////////////// SETUP void setup() { ////////////////////////////////////////////////////////////////////////////////////////// SETUP
rpmcount0=0;rpmcount1=0;rpm0=0;rpm1=0;bprocess=0;r0=0;r1=0;swmode=2; rpmcount0=0;rpmcount1=0;speedcount0=0;speedcount1=0;rpm0=0;rpm1=0;xpm0=0;xpm1=0;bprocess=0;r0=0;r1=0;swmode=2;
Serial.begin(9600); // start serial Serial.begin(9600); // start serial
lcd.init();lcd.backlight();lcd.clear(); // initialize lcd lcd.init();lcd.clear();lcd.backlight(); // initialize lcd
pinMode(PWM0,OUTPUT);pinMode(PWM1,OUTPUT); // set PWM pins pinMode(PWM0,OUTPUT);pinMode(PWM1,OUTPUT); // set PWM pins
pinMode(CLK,INPUT);pinMode(DT,INPUT);pinMode(SW,INPUT); // set KY-040 pins pinMode(CLK,INPUT);pinMode(DT,INPUT);pinMode(SW,INPUT); // set KY-040 pins
@ -60,16 +64,18 @@ void setup() { /////////////////////////////////////////////////////////////////
SAVE=0; // load/initialize settings SAVE=0; // load/initialize settings
if (eer(0)!=SAVETAG) { if (eer(0)!=SAVETAG) {
v0=300;v1=300;b0=700;b1=700;btime0=30;btime1=30;catch0=0;catch1=0;ctime0=120;ctime1=120; v0=300;v1=300;b0=700;b1=700;btime0=30;btime1=30;catch0=0;catch1=0;ctime0=120;ctime1=120;
fanstate0=0;fanstate1=0;
eew(0,SAVETAG);save(); eew(0,SAVETAG);save();
} else { } else {
v0=eer(1);v1=eer(2);b0=eer(3);b1=eer(4);btime0=eer(5);btime1=eer(6); v0=eer(1);v1=eer(2);b0=eer(3);b1=eer(4);btime0=eer(5);btime1=eer(6);
catch0=eer(7);catch1=eer(8);ctime0=eer(9);ctime1=eer(10); catch0=eer(7);catch1=eer(8);ctime0=eer(9);ctime1=eer(10);fanstate0=eer(11);fanstate1=eer(12);
} }
enclast=digitalRead(CLK); // get encoder state enclast=digitalRead(CLK); // get encoder state
fanstate0=0;fanstate1=0;OCR1A=0;OCR1B=0; // turn fans off
sts=MS;rts=MS;swts=MS;bts=MS;savets=MS;catchts0=MS;catchts1=MS;stop0=MS;stop1=MS; // set timer xts=MS;sts=MS;rts=MS;swts=MS;bts=MS;savets=MS;catchts0=MS;catchts1=MS;stop0=MS;stop1=MS; // set timer
bstate0=0;bstate1=0;mode=0;updatelcd();updatespeed();updatemarker();LOCK=0; // set initial states bstate0=0;bstate1=0;mode=0;updatePWM();updatelcd();updatespeed();updatemarker();LOCK=0; // set initial states
} }
@ -135,24 +141,40 @@ void loop() { //////////////////////////////////////////////////////////////////
SAVE++;OK=1;updatelcd();updatespeed();serinfo(); SAVE++;OK=1;updatelcd();updatespeed();serinfo();
} }
if (!OK) SXN("ERROR"); if (!OK) SXN("error");
} }
if (MS-rts>RINTERVAL) { ////////////////////////////////////////////////////////////////////////// regulation if (MS-xts>SINTERVAL) { /////////////////////////////////////////////////////////////////// speed measurement
xpm0=xpm0*(SAVERAGE-1)/SAVERAGE+(speedcount0/((MS-xts)/1000.0)*30.0)/SAVERAGE;
xpm1=xpm1*(SAVERAGE-1)/SAVERAGE+(speedcount1/((MS-xts)/1000.0)*30.0)/SAVERAGE;
updatespeed();xts=MS;speedcount0=0;speedcount1=0;
}
if (MS-rts>RINTERVAL) { //////////////////////////////////////////////////////////////////// speed regulation
rpm0=rpmcount0/((MS-sts)/1000.0)*30.0; rpm0=rpmcount0/((MS-sts)/1000.0)*30.0;
rpm1=rpmcount1/((MS-sts)/1000.0)*30.0; rpm1=rpmcount1/((MS-sts)/1000.0)*30.0;
sts=MS;rpmcount0=0;rpmcount1=0; sts=MS;rpmcount0=0;rpmcount1=0;
if (!fanstate0) r0=0; xb0=b0;if (bstate0) xb0=cut((((double)b0-(double)v0)/BOOSTRAMP*(MS-b0ts))+v0,v0,b0);
else if (abs((bstate0?b0:v0)-rpm0)>RTOL) r0+=((bstate0?b0:v0)-rpm0)/10.0+1.0; xb1=b1;if (bstate1) xb1=cut((((double)b1-(double)v1)/BOOSTRAMP*(MS-b1ts))+v1,v1,b1);
if (!fanstate1) r1=0;
else if (abs((bstate1?b1:v1)-rpm1)>RTOL) r1+=((bstate1?b1:v1)-rpm1)/10.0+1.0;
if (MS>=stop0+20000) {
if (!fanstate0) r0=0;
else {
r=(bstate0?xb0:v0)-rpm0;
if (abs(r)>RTOL) r0=r<0?r0-1-abs(r)/10:r0+1+abs(r)/10;
}
}
if (MS>=stop1+20000) {
if (!fanstate1) r1=0;
else {
r=(bstate1?b1:v1)-rpm1;
if (abs(r)>RTOL) r1=r<0?r1-1-abs(r)/10:r1+1+abs(r)/10;
}
}
updatePWM();updatespeed();rts=MS; updatePWM();updatespeed();rts=MS;
} }
bdelay=0; //////////////////////////////////////////////////////////////////////////////////// process switch bdelay=0; //////////////////////////////////////////////////////////////////////////////////// process switch
if (!bprocess) { if (!bprocess) {
@ -180,14 +202,14 @@ void loop() { //////////////////////////////////////////////////////////////////
if (swmode==0 && mode==1 && !LOCK) { // boost fan 0 on/off if (swmode==0 && mode==1 && !LOCK) { // boost fan 0 on/off
if (bstate0==0) { if (bstate0==0) {
rts=MS+RDELAY;bstate0=1;b0ts=MS;fanstate0=1;r0=0;updatePWM(); rts=MS+RDELAY;bstate0=1;b0ts=MS;fanstate0=1;
} else {;bstate0=0;} } else {;bstate0=0;rts=MS+RDELAY+2000;updatePWM();}
updatespeed(); updatespeed();
} }
if (swmode==1 && mode==1 && !LOCK) { // boost fan 1 on/off if (swmode==1 && mode==1 && !LOCK) { // boost fan 1 on/off
if (bstate1==0) { if (bstate1==0) {
rts=MS+RDELAY;bstate1=1;b1ts=MS;fanstate1=1;r1=0;updatePWM(); rts=MS+RDELAY;bstate1=1;b1ts=MS;fanstate1=1;
} else {;bstate1=0;} } else {;bstate1=0;rts=MS+RDELAY+2000;updatePWM();}
updatespeed(); updatespeed();
} }
@ -195,11 +217,12 @@ void loop() { //////////////////////////////////////////////////////////////////
if (LOCK==0) LOCK=1; if (LOCK==0) LOCK=1;
else LOCK=0; else LOCK=0;
updatemarker(); updatemarker();
save();
} }
bdelay=0; bdelay=0;
} else if (bdelay>0 && bdelay<20 && !LOCK) { // short button press: switch menu -> fan 0 -> fan 1 } else if (bdelay>0 && bdelay<20 && !LOCK) { // short button press, switch: menu -> fan 0 -> fan 1
swmode++;if (swmode>2) swmode=0; swmode++;if (swmode>2) swmode=0;
updatemarker(); updatemarker();
bdelay=0; bdelay=0;
@ -239,11 +262,11 @@ void loop() { //////////////////////////////////////////////////////////////////
if (swmode==2) mode--; // scroll menu if (swmode==2) mode--; // scroll menu
} }
if (swmode==0 && mode==0) {;updatePWM();r0=0;rts=MS+RDELAY;} // apply speed change fan 0 if (swmode==0 && mode<=1) {;updatePWM();rts=MS+RDELAY;} // apply (boost) speed change fan 0
if (swmode==1 && mode==0) {;updatePWM();r1=0;rts=MS+RDELAY;} // apply speed change fan 1 if (swmode==1 && mode<=1) {;updatePWM();rts=MS+RDELAY;} // apply (boost) speed change fan 1
if (swmode==0 && mode==1) {;updatePWM();r0=0;rts=MS+RDELAY;} // aply boost speed change fan 0
if (swmode==1 && mode==1) {;updatePWM();r1=0;rts=MS+RDELAY;} // aply boost speed change fan 1 if (b0<v0) b0=v0;
if (swmode==0 && mode==2) btime0=cut(btime0,0,60); // check boost time fan 0 if (swmode==0 && mode==2) btime0=cut(btime0,0,60); // check boost time fan 0
if (swmode==1 && mode==2) btime1=cut(btime1,0,60); // check boost time fan 1 if (swmode==1 && mode==2) btime1=cut(btime1,0,60); // check boost time fan 1
@ -253,7 +276,7 @@ void loop() { //////////////////////////////////////////////////////////////////
if (swmode==0 && mode==4) ctime0=cut(ctime0,60,240); // check catch time fan 0 if (swmode==0 && mode==4) ctime0=cut(ctime0,60,240); // check catch time fan 0
if (swmode==1 && mode==4) ctime1=cut(ctime1,60,240); // check catch time fan 1 if (swmode==1 && mode==4) ctime1=cut(ctime1,60,240); // check catch time fan 1
if (swmode==2) {;if (mode<0) mode=4;if (mode>4) mode=0;} // check menu mode if (swmode==2) mode=cut(mode,0,4); // check menu mode
SAVE++;updatelcd();delay(50); SAVE++;updatelcd();delay(50);
} }
@ -300,7 +323,7 @@ void updatespeed() { ///////////////////////////////////////////////////////////
else { else {
if (bstate0) ilcd(1,0,2, (((long)btime0*60000)-(MS-(long)b0ts))/1000/60+1); if (bstate0) ilcd(1,0,2, (((long)btime0*60000)-(MS-(long)b0ts))/1000/60+1);
else slcd(7,0,1," "); else slcd(7,0,1," ");
ilcd(7,0,-4,round(rpm0)); ilcd(7,0,-4,round(xpm0));
} }
} else slcd(7,0,-4,"OFF"); } else slcd(7,0,-4,"OFF");
@ -309,7 +332,7 @@ void updatespeed() { ///////////////////////////////////////////////////////////
else { else {
if (bstate1) ilcd(4,0,2, (((long)btime1*60000)-(MS-(long)b1ts))/1000/60+1); if (bstate1) ilcd(4,0,2, (((long)btime1*60000)-(MS-(long)b1ts))/1000/60+1);
else slcd(12,0,1," "); else slcd(12,0,1," ");
ilcd(12,0,-4,round(rpm1)); ilcd(12,0,-4,round(xpm1));
} }
} else slcd(12,0,-4,"OFF"); } else slcd(12,0,-4,"OFF");
} }
@ -334,19 +357,19 @@ void slcd(int x,int y, int l,String s) { ///////////////////////////////////////
lcd.setCursor(x,y);lcd.print(out); lcd.setCursor(x,y);lcd.print(out);
} }
void updatePWM() { ///////////////////////////////////////////////////////////////////// update PWM (fan speed) void updatePWM() { ////////////////////////////////////////////////////////////// update PWM output (fan speed)
v0=cut(v0,FANMIN,FANMAX);v1=cut(v1,FANMIN,FANMAX); v0=cut(v0,FANMIN,FANMAX);v1=cut(v1,FANMIN,FANMAX);
b0=cut(b0,FANMIN,FANMAX);b1=cut(b1,FANMIN,FANMAX); b0=cut(b0,FANMIN,FANMAX);b1=cut(b1,FANMIN,FANMAX);
if (!fanstate0 || MS<stop0) OCR1A=0; if (!fanstate0 || MS<stop0) OCR1A=0;
else OCR1A=cut((bstate0?b0:v0)/(FANMAX/320.0)+r0,0,320); else OCR1A=cut((bstate0?xb0:v0)/(FANMAX/320.0)+r0,0,320);
if (!fanstate1 || MS<stop1) OCR1B=0; if (!fanstate1 || MS<stop1) OCR1B=0;
else OCR1B=cut((bstate1?b1:v1)/(FANMAX/320.0)+r1,0,320); else OCR1B=cut((bstate1?xb1:v1)/(FANMAX/320.0)+r1,0,320);
} }
void rpmint0() {;rpmcount0++;} ///////////////////////////////////////////////////////////////// rpm interrupts void rpmint0() {;rpmcount0++;speedcount0++;} /////////////////////////////////////////////////// rpm interrupts
void rpmint1() {;rpmcount1++;} void rpmint1() {;rpmcount1++;speedcount1++;}
double cut(double v,double min,double max) {;return v>max?max:v<min?min:v>max?max:v;} ///// cut values to limit double cut(double v,double min,double max) {;return v>max?max:v<min?min:v>max?max:v;} ///// cut values to limit
int eer(int adr) {;return EEPROM.read(adr*2)+EEPROM.read(adr*2+1)*256;} /////////////////////////// read EEPROM int eer(int adr) {;return EEPROM.read(adr*2)+EEPROM.read(adr*2+1)*256;} /////////////////////////// read EEPROM
@ -354,7 +377,7 @@ void eew(int adr, int val) {;EEPROM.write(adr*2,val%256);EEPROM.write(adr*2+1,va
void save() { /////////////////////////////////////////////////////////////////////////////////// save settings void save() { /////////////////////////////////////////////////////////////////////////////////// save settings
eew(1,v0);eew(2,v1);eew(3,b0);eew(4,b1);eew(5,btime0);eew(6,btime1); eew(1,v0);eew(2,v1);eew(3,b0);eew(4,b1);eew(5,btime0);eew(6,btime1);
eew(7,catch0);eew(8,catch1);eew(9,ctime0);eew(10,ctime1); eew(7,catch0);eew(8,catch1);eew(9,ctime0);eew(10,ctime1);eew(11,fanstate0);eew(12,fanstate1);
} }
String sstr(String data, char sep, int idx) { ///////////////////////////////////////// get saperated substring String sstr(String data, char sep, int idx) { ///////////////////////////////////////// get saperated substring