Coding Style
|
Read this, it'll make the code easier to follow.
When you write a large or complex piece of code then years later something needs adding, changing, or your CEO heard about a new language from one of his golfing buddies and he just must have it (this used to happen a lot).
Please see the Example code below.
I like top down coding.
BTW: you'll often see the word demon spelled daemon, its still pronounced demon.
A lot of the guys who wrote Unix were from the UK.
In Europe, when a long vowel sound is needed, they use double vowels with the second vowel having the long sound.
This was seen mostly in proper nouns, but I also seee it in other words.
Like the proper noun Diesel (long 'E' sound, you don't sound the 'I'>
Header Comment Block | |
I usually put a header comment at the top of the listing, before the includes. For Arduino sketches, I note what sensors or peripheral chips the program is using. Use a distinctive function block at the beginning of the function code, again, makes it easy to spot. Put the funcion name on the next line after the function type. | |
#defines | |
ALL CAPS | |
Global Variables | |
Start with UPPER CASE, local variables start with lower case | |
Comments | |
ALL CAPS, right justified | |
Indents | |
Two chars is too little, 8 too much, 4 is just about right. | |
Left curley brace | |
Should be at beginning of a line (with correct indent), and is a great place for a comment stating what the enclosed block does. | |
Wrap a line | |
Make sure the 1st char on the wrapped line is punctuation. It is easier to understand if you don't jam it together, your looking for the logic flow. | |
I don't like to type the word 'unsigned' | |
typedef it away to 'ulong' for instance. | |
main (or setup & loop) | |
Always 1st in the listing, followed by the fuctions it calls, thats why God invented PROTOTYPES. | |
Defines, Global Variables, & Prototypes | |
Should be at the beginning of the listing. That way you know were to look when you encounter a reference to one down in the code. Note: If you need to build a Global variable with function pointers swap the variables and prototype sections. | |
Function calls. | |
I always put the left parin next to the function name, followed by a space. It makes the call easier to spot when you're trying to figure out whats going on in the code. Like: if( barf > 16 ) | |
case statements | |
follow with the left curley under the 's' in switch with a comment. Indent the case, then indent again for each line in the case till the break; All cases should be at the same indent, all lines within the case should be at the same indent (one more than the case itself). |
/*********************************************************************** DUST COLLECTION AUTOMATION: PARTS TAKEN FROM BOB CLAGETT ON I LIKE TO MAKE STUFF (ILIKETOMAKESTUFF.COM) I/O DEVICE: LCDKEYPAD (DATA TERM) HDW: PCA9685 I2C PWM Servo driver, MG996R Servos, 74HC4051 Analog Mux, CURRENT SENSOR: ACS712-30A (66Ms/A), AND A SOLID STATE RELAY TOOLS NUMBERED 1 - 8, NO ZERO ***********************************************************************/ #include <Wire.h> #include <Adafruit_PWMServoDriver.h> #include <SoftwareSerial.h> /************************** DEFINES ************************************/ #define AUTODLY 20000 // AUTO MODE LOCK TIME #define DCRUN 11 // DUST COLLECTOR GO PIN #define DSPDLY 1000 // DELAY BETWEEN VOLT READING DISPLAYS #define DUSTAVGCNT 5 // MUST HAVE DUSTAVGCNT RDNGS TO AVERAGE #define DUSTBADS 3 // MUST HAVE DUSTBADS DUSTMINS TO HALT #define DUSTCHK 1000 // TIME BETWEEN DUST REQUESTS #define DUSTWAT 100 // TIME WAIT FOR DUST DTCTR #define DUSTMIN 8 // DUST BIN MUST HAVE MORE THAN 8" SPACE #define ESC 92 // BACKSLASH, IDE, Serial DOESN'T SEND CNTRL CHRS #define INSTRMAX 32 // INSTRING SIZE #define MITERSAW 6 // MITERSAW NBR #define MUXS0 7 // LSB // ANALOG MUX SELECT 0 #define MUXS1 6 // ANALOG MUX SELECT 1 #define MUXS2 5 // MSB // ANALOG MUX SELECT 2 #define NBRTOOLS 8 // NUMBER OF TOOLS #define NBRVALVES 8 // NUMBER OF VALVES #define PWM_ADDR 0X40 // SERVO CONTOROL ADDRESS #define V8WAT 5000 // PLANER VALVE WAIT TIME 5 SEC #define RDGTHLD 200 // DIGITAL READING THRESHOLD @ 4.887 MV/INCR #define DDRX 3 // SOFTWARE SERIAL RX #define DDTX 4 // SOFTWARE SERIAL TX #define V8RX 8 // VALVE-8 SERIAL RX #define V8TX 9 // VALVE-8 SERIAL TX #define SNSRDLY 20 // SAMPLE TIME 20MS #define SRVODLY 525 // MG996R MVS 60deg in .17 SEC, SERVO ACT DELAY #define SPINUP 1000 // DC SPIN UP TIME MS #define SPINDOWN 3000 // DUST COLLECTOR SPIN DOWN TIME #define SRVOBUMP 5 // VALVE SERVO INCR OR DECR #define NL 10 #define OPN 0 // VALVE CCW #define CLOS 1 // VALVE CW #define ZIN A7 // SENSOR IN enum Modes { IDLE, MANUAL, DSPRDG, AUTO, SETSRVO, MULTVLV, DUSTBINHALT }; typedef unsigned long ulong; #define ssL(str,ndx) for( byte x = 0; x < ndx +1; x++ ) str[x] = str[x +1]; /************************** VARIABLES ************************************/ Adafruit_PWMServoDriver Servo = Adafruit_PWMServoDriver(); SoftwareSerial Dust( DDRX, DDTX ); // DUST DETECTOR SERIAL RX, TX SoftwareSerial V8( V8RX, V8TX ); // PlanerValve (V8) SERIAL RX, TX bool DcOnFlg = false, Rs232 = false, DstOnScrn = false; bool V8Req = false; char *ToolNam[NBRTOOLS+1] = { "0","Sander","BandSaw","Free-1","TableSaw" ,"Free-2","MiterSaw","Router","Planer" }; // TOOL NAMES ARRAY short BasVal[NBRTOOLS +1], RdgTool = 0, VlvOc = CLOS; int DustSpc, DustCnt =0, DustAcc =0, DustBads =0; // DUST RELATED VARS int VlvVals[NBRVALVES +1][2] = {{0,0}, // OPN,CLOS VALVE, NO VALVE ZERO {160,480}, {150,445}, {160,450}, {180,425}, {160,450},{125,435},{150,440} // SANDER BANDSAW FREE-1 tableSAW FREE-2 MITERSAW ROUTER ,{190,465}, }; // MITERSAW ulong NxtDsp =0, AutoTime =0, DustTim = 0; char CurPos[8] = { ESC,'[','0',';','0','0','f',0}; // POSIT CURSOR, ROW,COL char ClrScrn[6] = { ESC,'[','2','j',0}; // CLEAR SCREEN char Hdr[] = {" Dust Collector\n"}, DstChrs[18]; char InStr[INSTRMAX], *VlvPos[2] = {"Open","Close"}; byte InNdx =0, Mode = IDLE, ActvTool = 0, ActVlv = 0, SsNdx =0; /************************** PROTOTYPES ************************************/ void cancel( byte noPnt ); // CANCEL ALL OPERATIONS bool chkAmpChg( int tool ); // CHECK FOR CURRENT CHANGE void chkDustBin(); // PROCESS DUST BIN DEPTHS void chkTools(); // CHECK FOR ACTIVE TOOL void clrScrn(); // CLEAR DATA TERMINAL SCRN void cycVlvs(); // CYCLE ALL VALVES void dcOn(),dcOff(); // DUST COLLECTOR ON OFF void dspDust( int dust ); // DISPLAY DUST STATUS void dspIRdg( char chr ), dspIRdgSu(); // DISPLAY ISNSR READINGS void doChrs(); // PROCESS KBD CHARS void dustHalt( byte row, byte col, char* msg); // DUST HALT char getChr(); // GET A CHAR FROM INSTR int getDust(); // SOFTWARE SERIAL INTERRUPT SERVICE ROUTINE void multVlv( char chr ), multVlvSu(); // OPEN MULTIPLE VALVES short opnVlv( uint8_t num), clsVlv( uint8_t num, byte prnt); // OPN/CLOS VLV void posCur( byte row, byte col ); // SET CURSOR POSTION short reqV8( char cmd ); // SEND REQUEST TO PLANER VALVE int rdSnsr( short snsr); // READ A SENSOR void runTool( char chr ); // START A TOOL void serialEvent(); // RS232 INTERRUPT ROUTINE void setSrvo( char chr), setSrvoSu(); // SET SERVO VALUES short v8Fail(); /*F****************************************************************** * **********************************************************************/ void setup() { int ndx; Serial.begin( 9600 ); // START SERIAL I/O FROM DATA TERMINAL Serial.print( Hdr ); // PRINT HEADER ON DATA TERM Dust.begin( 9600 ); // START SFTW SERIAL I/O FROM DUST BIN V8.begin( 9600 ); // START SFTW SERIAL I/O WITH VALVE 8 pinMode( DCRUN, OUTPUT); // I/O PIN OUTPUT FOR STARTING 2HP DUST BLOWER Servo.begin(); Servo.setPWMFreq( 50 ); // SET PWM FREQ = 50HZ delay( 1000 ); pinMode( MUXS2, OUTPUT ); // DEFINE ANALOG OUTPUT TO MUX pinMode( MUXS1, OUTPUT ); // DEFINE ANALOG OUTPUT TO MUX pinMode( MUXS0, OUTPUT ); // DEFINE ANALOG OUTPUT TO MUX for( ndx =1; ndx <= NBRTOOLS; ndx++) BasVal[ndx] = rdSnsr( ndx ); // SAVE BASE SNSR RDGS, FOR VOLT CMPRSN for( ndx =1; ndx <= NBRVALVES; ndx++) clsVlv( ndx, 0 ); // CLOSE ALL VALVES } /*F****************************************************************** * **********************************************************************/ void loop() { if( Rs232 == true ) doChrs(); // CHAR ARRIVED ON SERIAL I/O FROM DATA TERM if( millis() > DustTim ) chkDustBin(); // CHECK DUST BIN DEPTH if( Mode == DUSTBINHALT ) return; // DUST BIN FULL, ONLY CANCEL WILL RESTART chkTools(); // SEE IF ANY TOOL'S MOTOR IS RUNNING if( (Mode == DSPRDG) ) dspIRdg( 9 ); // PASS CHAR TO DISPLAY ISNSR VOLTAGE if( (Mode == SETSRVO) ) setSrvo( 9 ); // PASS CHAR TO ADJUST SERVO } /*F****************************************************************** * DUSTBIN DEPTH MESSAGE PROCESSING, AFTER DUSTAVGCNT **********************************************************************/ void chkDustBin() { int dust; if((Mode == DSPRDG) || (Mode == SETSRVO)) return; if( (dust = getDust()) < 0 ) return( dustHalt( 3, 0, " No Dust ")); if( (DustAcc > 0) && (DustCnt >= DUSTAVGCNT) ) { // AVERAGE DUST DEPTH REPORTS FROM DETECTOR DustSpc = DustAcc / DustCnt; // UPDATE DUST SPACE dspDust( DustSpc ); DustCnt = DustAcc = 0; // RESET ACCUMULATOR AND COUNT if( (DustSpc <= DUSTMIN) && (DustSpc > 0) && (DcOnFlg == true) ) { if( (Mode == DUSTBINHALT) || (++DustBads < DUSTBADS) ) return; // ALREADY HALT MODE, OR NOT ENOUGH BAD DEPTHS dustHalt( 0, 3, "Dust Bin Halt"); // DC RUNING & DUST BIN FULL } else DustBads = 0; // ONE GOOD DUST READING RESETS DUSTBADS } } /*F****************************************************************** * CHECK FOR TOOL MOTOR RUNNING **********************************************************************/ void chkTools() { int ndx, tool =0; ulong now; if( (Mode != AUTO) && (Mode != IDLE) ) return; // DO NOT CHECK FOR I FLOW UNLESS IN AUTO OR IDLE now = millis(); for( ndx =1; ndx <= NBRTOOLS; ndx++) { // SCAN THROUGH TOOLS & CHECK FOR INCREASED CUR FLOW if( chkAmpChg( ndx )) { // TOOL ON tool = ndx; Mode = AUTO; if( tool == MITERSAW ) AutoTime = millis() + AUTODLY; // MITERSAW RUNNING break; // FOUND ONE } } if( (ActvTool == MITERSAW) && (now < AutoTime) ) return; // TOOL STARTED, WAIT AUTODLY B4 CHANGING if( ActvTool == tool ) return; // SAME TOOL STILL RUNNING if( ActvTool && !tool ) cancel( 0 ); // NO ACTIVE TOOL AND DC IS ON else if( (tool != 0) && (tool != ActvTool) ) runTool( tool ); // START TOOL } /*F****************************************************************** * PROCESS KBD CHRS * 0 CANCEL ALL * 1-8 OPEN VALVE N, TURN BLOWER ON * A CYCLE ALL VALVES * #n TEST ISNSRS * *n SET SERVOS **********************************************************************/ void doChrs() { char chr; while( (chr = getChr()) != 0 ) // READ A CHAR FROM InStr, IF AVAIL { Rs232 = false; // CLEAR SERIAL I/O FLAG if( (Mode == DSPRDG) && (chr != '0')) return( dspIRdg( chr ) ); // PASS CHR TO DSPLY ISENSOR VOLTS if( (Mode == SETSRVO) && (chr != '0')) return( setSrvo( chr )); // PASS CHR TO SERVO SETUP if( (Mode == MULTVLV) && (chr != '0')) return( multVlv( chr )); // PASS CHR TO MULTI VALVE SETUP switch( chr ) { case '0': // CANCEL CURRENT OPERATION cancel( 0 ); break; case 'A': // CYCLE ALL VALVES cycVlvs(); break; case 'B': multVlvSu(); // OPEN MULTIPLE VALVES break; case '1' ... '8': // MANUAL MODE, OPEN VALVE & RUN DC Mode = MANUAL; runTool( chr ); break; case '*': // SPLAT, DISPLAY ISENSOR VOLTAGE READING dspIRdgSu(); break; case '#': // CRUNCH, SETUP SERVOS setSrvoSu(); break; case NL: // GOT NEWLINE break; // DISCARD NEWLINE default: Mode = IDLE; break; } } } /*F****************************************************************** * SETUP FOR DISPLAY ISNSR VOLTAGE READINGS, CALLED FROM doChrs() **********************************************************************/ void dspIRdgSu() { if( DcOnFlg ) dcOff(); // DC IS RUNNING, STOP IT Mode = DSPRDG; // SET DISPLAY READING MODE AutoTime =0; ActVlv = 0; VlvOc = CLOS; clrScrn(); posCur( 0, 2 ); Serial.print("Read Sensor"); posCur( 1, 0 ); Serial.print("Enter Tool Number"); } /*F****************************************************************** * SETUP SERVO SETUP **********************************************************************/ void setSrvoSu() { if( DcOnFlg ) dcOff(); Mode = SETSRVO; clrScrn(); delay( 200 ); posCur( 0, 0 ); Serial.print(" SERVO SETUP"); posCur( 1, 0 ); Serial.print("Enter Servo Number"); } /*F****************************************************************** * RUN A MACHINE **********************************************************************/ void runTool( char chr ) { byte tool; clrScrn(); tool = (chr & 15); // STRIP OFF UPPER BITS OF CHR 0X3n posCur( 0, 6 ); Serial.println( (String)ToolNam[tool] ); // ROW: 0, PRINT TOOL NAME if( (ActvTool > 0) && (ActvTool != tool)) { // NEW ACTIVE TOOL if( DcOnFlg ) dcOff(); clsVlv( ActvTool, 1 ); } ActvTool = tool; opnVlv( ActvTool ); dcOn(); } /*F****************************************************************** * CANCEL CURRENT OPERATION **********************************************************************/ void cancel( byte noPnt ) { short ndx; if( !noPnt ) { clrScrn(); Serial.println(" Cancel Operation"); } if( DcOnFlg ) dcOff(); // DC IS ON, STOP IT for( ndx = 1; ndx <= NBRVALVES; ndx++ ) clsVlv( ndx, 1 ); // CLOSE ALL VALVES Mode = IDLE; AutoTime =0; // CANCEL ANY TOOL RUNNING IN AUTO MODE RdgTool = ActvTool = 0; if( noPnt ) return; clrScrn(); Serial.print((String)Hdr ); } /*F****************************************************************** * DISPLAY ISNSR VOLTAGE READINGS, CALLED FROM loop(), or doChrs() **********************************************************************/ void dspIRdg( char chr ) { short tool, val; int32_t now; if( (chr >= '1' ) && (chr <= '8' )) { // SET NEW TOOL RdgTool = (chr & 0X0F); // STRIP OFF 0X3n posCur( 1, 0 ); // CLEARS ROW 1 Serial.print( (String)ToolNam[RdgTool] + " = " ); NxtDsp = 0; // FORCE IMMEDIATE DISPLAY } now = millis(); // GET CURRENT TIME if((now > NxtDsp) && (RdgTool != 0)) { // TIME TO DISPLAY A CURRENT READING NxtDsp = (now + DSPDLY); // SAVE TIME OF CURRENT DISPLAY val = rdSnsr( RdgTool ); posCur( 1, 10 ); // ROW 1, COL 10 Serial.println( val ); // 4.88MV / INCR } } /*F****************************************************************** * CYCLE ALL VALVES TO REMOVE ANY LARGE SPLINTERS ETC. **********************************************************************/ void cycVlvs() { char tool, chr, buf[24]; clrScrn(); Serial.println(" Cycling Valves "); if( DcOnFlg ) dcOff(); for( tool = 1; tool <= NBRVALVES; tool++ ) { // FLAP ALL VALVES posCur( 1, 0 ); // ROW 2, COL 0 Serial.println((String)ToolNam[tool] ); opnVlv( tool ); delay( SRVODLY ); // WAIT FOR THE SERVO TO ACT clsVlv( tool, 1 ); delay( SRVODLY ); // WAIT FOR THE SERVO TO ACT } ActvTool = 0; clrScrn(); Serial.print( Hdr ); } /*F****************************************************************** * SERVO SETUP **********************************************************************/ void setSrvo( char chr ) { short tool, val, rtn; int32_t now; if( !ActVlv && (chr == 9)) return; // CALLED FROM LOOP, NO ACTIVE VALVE if( !ActVlv && ((chr >= '1') && (chr <='8'))) { // NEW SERVO NMBR ActVlv = chr & 15; // SET NEW ACTIVE VALVE NBR posCur( 1, 0 ); // CLEARS ROW 1 Serial.print( (String)ToolNam[ActVlv] + "-" ); // LIKE "TableSaw-" NxtDsp = 0; // FORCE IMMEDIATE DISPLAY } else if( (chr >= '1') && (chr <= '8') ) { switch( chr ) { case '2': // VAL UP VlvVals[ActVlv][VlvOc] += SRVOBUMP; break; case '4': // OPEN VALVE VlvOc = OPN; // VlvOc: VALVE SHOULD BE OPEN OR CLOSED break; case '6': // CLOSE VALVE VlvOc = CLOS; // VlvOc: VALVE SHOULD BE OPEN OR CLOSED break; case '8': // VAL DN VlvVals[ActVlv][VlvOc] -= SRVOBUMP; break; default: break; } if( (ActVlv == 8) && (VlvOc == OPN) && ((rtn =reqV8( 'O' )) <0)) v8Fail(); else if( (ActVlv == 8) && (VlvOc== CLOS) && ((rtn =reqV8( 'C' )) <0)) v8Fail(); else { Servo.setPWM( ActVlv, 0, VlvVals[ActVlv][VlvOc]); // SET SERVO delay( SRVODLY ); // WAIT FOR SERVO TO ACT } NxtDsp = 0; // FORCE IMMEDIATE DISPLAY } now = millis(); // GET CURRENT TIME if((now > NxtDsp) && (ActVlv != 0)) { NxtDsp = (now + DSPDLY); // SAVE TIME OF NEXT DISPLAY posCur( 1, 10 ); // ROW 1, COL 10 val = VlvVals[ActVlv][VlvOc]; Serial.println( (String)VlvPos[VlvOc] + ":" +val ); // "Close: 450" } } /*F****************************************************************** * TURN DUST COLLECTOR ON **********************************************************************/ void dcOn() { if( Mode == DUSTBINHALT ) return; digitalWrite( DCRUN, 1); posCur( 1, 13 ); Serial.println("DC On "); DcOnFlg = true; DustCnt = DustAcc = 0; // RESET DUST ACCUM & CNT delay( SPINUP ); } /*F****************************************************************** * TURN DUST COLLECTOR OFF **********************************************************************/ void dcOff() { posCur( 1, 3 ); Serial.println("Stopping DC "); delay( 2000 ); // WAIT FOR PLENUM/HOSE TO EMPTY digitalWrite( DCRUN, 0); delay( SPINDOWN ); // WAIT FOR DC SPINDOWN posCur( 1, 0 ); // ERASE ROW 1 TO END OF LINE DcOnFlg = false; } /*F****************************************************************** * SAMPLING CURRENT SENSOR 1-7 (LO NIBBLE 0X0001 - 0X0111), SNSR 8 =0 **********************************************************************/ int rdSnsr( short snsr ) // SNSR: 1 - 8 { int rdVal, cnt, pin, msk =1, rtn; ulong end, tmp; // S0:D7(LSB), S1:D6, S2:D5(MSB) pin scans 7 - 5 for( pin = MUXS0, msk = 1; pin > 4; --pin, msk <<=1 ) { // SET SENSOR # INTO MUX SEL0-SEL2 INPUTS, LSB to MSB, SNSR 8 = 0 if( msk & snsr ) digitalWrite( pin, HIGH ); // WT HI PINS MUXS0,MUXS1,MUXS2 else digitalWrite( pin, LOW ); // WT LOW PINS MUXS0,MUXS1,MUXS2 } delay( 2 ); // WAIT 2MS FOR SEL TO INP TIME end = millis() + SNSRDLY; // SAVE CURRENT TIME + SAMPLE TIME for( cnt = tmp =0; millis() < end; cnt++ ) { // NOISY SIGNAL, AVERAGE FOR SAMPLE TIME rdVal = analogRead( ZIN ); // 0-1023 DIGITAL RDG tmp += rdVal; } // 175 - 180 samples IN 20 MS rtn = tmp / cnt; return( rtn ); } /*F****************************************************************** * CHECK FOR AMPERAGE CHANGE ON A TOOL **********************************************************************/ bool chkAmpChg( int tool) { int rdg; rdg = rdSnsr( tool ); // READINGS RUN FROM OFF: 52-81, ON: 364-461 if( rdg > RDGTHLD ) // NEW SENSOR IGNORE BASE (BasVal[tool] + RDGTHLD)) return( true ); // RETURN TOOL ON else return( false ); // RETURN TOOL OFF } /*F****************************************************************** * GET CHAR FROM INSTR **********************************************************************/ char getChr() { char chr; if( InNdx == 0 ) return( 0 ); chr = InStr[--InNdx]; ssL( InStr, InNdx ); // SHIFT INSTR LEFT if( InNdx == 0 ) Rs232 = false; // INSTR EMPTY return( chr ); } /*F****************************************************************** * CLOSE A VALVE **********************************************************************/ short clsVlv( uint8_t num, byte prnt ) { short rtn = 1; if( DcOnFlg ) dcOff(); VlvOc = CLOS; // SET CURRENT VALVE POSTION = CLOSED if( prnt ) { posCur( 1, 0 ); Serial.println((String)"Vlv "+num+" Clos" ); } if( num == 8 ) rtn = reqV8( 'C' ); // REQUEST VALVE 8 CLOSE else { Servo.setPWM( num, 0, VlvVals[num][CLOS]); // CLOSE VALVE delay( SRVODLY ); // WAIT FOR SERVO TO ACT } Servo.setPWM( 15, 0, 400 ); // DISTRACT PCA9685 TO SERVO 15 ActVlv = 0; if( prnt ) posCur( 1, 0 ); // CLEAR ROW 1 } /*F****************************************************************** * OPEN A VALVE **********************************************************************/ short opnVlv( uint8_t num ) { int rtn = 1; if( DcOnFlg ) dcOff(); VlvOc = OPN; posCur( 1, 0 ); Serial.println((String)"Vlv "+num+" Opn"); if( num == 8 ) rtn = reqV8( 'O' ); // REQUEST VALVE 8 OPEN else { Servo.setPWM( num, 0, VlvVals[num][OPN]); // OPEN VALVE delay( SRVODLY ); } ActVlv = num; } /*F****************************************************************** * RS-232 INTERRUPT SERVICE ROUTINE, DO NOT TARRY HERE **********************************************************************/ void serialEvent() { // RUNS EACH TIME (AFTER) LOOP RUNS int val; char chr; while( Serial.available()) // INTERRUPT SERVICE ROUTINE, DON'T TARRY HERE { chr = (char)Serial.read(); // GET NEW CHAR if( chr < 32 ) continue; // DISCARD NON_PRINtable CHAR if( InNdx >= INSTRMAX ) { // IN STR NDX TOO LARGE, RESET IT Serial.println("Overrun"); break; } val = chr & 15; InStr[InNdx++] = chr; // ADD NEW CHAR TO InStr[] Rs232 = true; // SET FLAG SO MAIN LOOP CAN DO SOMETHING ABOUT IT } } /*F****************************************************************** * REQUEST DEPTH FROM DUST DETECTOR, WAIT FOR RESPONSE * DATA FROM THIS MAKES SERIOUS DECISIONS ABOUT SHUTING DOWN DC **********************************************************************/ int getDust() { // @ 9600 CHARS ARRIVE EVERY 1Ms int val, dstVal; char chr; ulong end; // Serial.println((String)"getDust: Bgn"); Dust.listen(); Dust.print( "D\n" ); // SEND DUST DEPTH REQUEST TO DUST DET DustSpc = 0; DustTim = millis() + DUSTCHK; // SET TIME OF NEXT DUST DEPTH REQUEST val = dstVal =0; // BELOW: < DustTim IN CASE DUSTDET DOESN'T RESPOND end = millis() + DUSTWAT; // SET TIMER FOR DUST DET RESONSE while( millis() < end ) { // LOOP HERE WHILE DUSTREQ & NOT DUSTTIME if( Dust.available() ) { // KEEP READING TIL FIND NEWLINE chr = Dust.read(); // GET NEW CHAR // Serial.println((String)"GotChr: "+chr); if( chr == '\n' ) { // END OF TRANSMISSION DustAcc += dstVal; // ACCUMULATE DUST DEPTH DustCnt++; // BUMP DUST READING COUNTER break; } if( (chr < '0') || (chr > '9')) continue; // DISCARD NON NUMERIC CHAR val = (chr & 15); // CONVERT ASCII TO BIN: '2' (0X32) & 0X0F = 2 dstVal = (dstVal * 10) + val; // ACCUM DEC DUST DEPTH VALS } } // Serial.println((String)"getDust: End, dstVal: "+dstVal); if( millis() > end ) return( -1 ); return( dstVal ); } /*F****************************************************************** * DUST HALT **********************************************************************/ void dustHalt( byte row, byte col, char *msg) { // DC RUNING & DUST BIN FULL, STOP EVERYTHING Mode = DUSTBINHALT; // ADVERTISE WHY WE'RE SHUTDOWN clrScrn(); posCur( row, col ); // SET CURSOR POSTION Serial.println( (String)msg ); cancel( 1 ); // STOP EVERYTHING } /*F****************************************************************** * OPEN MULTIPLE VALVE SETUP **********************************************************************/ void multVlvSu() { if( DcOnFlg ) dcOff(); Mode = MULTVLV; clrScrn(); delay( 200 ); // posCur( 0, 0 ); // Serial.print("OPEN ANOTHER VALVE"); posCur( 1, 0 ); Serial.print("Enter Valve Number"); dcOff(); } /*F****************************************************************** * OPEN MULTIPLE VALVES **********************************************************************/ void multVlv( char chr ) // OPEN MULTIPLE VALVES { short tool; if( (chr >= '1' ) && (chr <= '8' )) { // SET NEW TOOL Mode = MANUAL; tool = (chr & 0X0F); // STRIP OFF 0X3n posCur( 1, 0 ); // CLEARS ROW 1 Serial.print( (String)"+ "+ToolNam[tool] ); opnVlv( tool ); dcOn(); } else cancel( 0 ); } /*F****************************************************************** * POSITION CURSOR Esc[r;ccf SET CURSOR TO ROW COL **********************************************************************/ void posCur( byte row, byte col ) { char str[8]; strcpy( str, CurPos ); sprintf( &str[2], "%1d;%02df", row, col ); Serial.print( str ); delayMicroseconds( 200 ); } /*F****************************************************************** * CLEAR SCREEN **********************************************************************/ void clrScrn() { Serial.print( ClrScrn ); delay( 200 ); DstOnScrn = false; } /*F****************************************************************** * RUN A MACHINE **********************************************************************/ void dspDust( int dustSpc ) { char buf[32]; if( !DstOnScrn ) { // NEED TO REPRINT "Dust Space" posCur( 3, 0 ); // SET CURSOR POSTION Serial.print( (String)"Dust Space: "); DstOnScrn = true; } posCur( 3, 12 ); sprintf( buf, "%02u\"", dustSpc ); Serial.print( (String)buf ); } /*F****************************************************************** * SEND PLANER VALVE (V8) OPEN/CLOSE REQUEST RETURN: 1 = OK, else -1 **********************************************************************/ short reqV8( char req ) // REQ IS UC LETTER 'O' or 'C' { ulong end; char chr, resp =0; short rtn = 1; V8.listen(); V8.println((String)req ); // SEND PLANER VALVE REQUEST end = millis() + V8WAT; // SET TIMER FOR PLANER VALVE RESONSE while( millis() < end ) { // LOOP HERE WHILE PLANER VALVE MOVES if( V8.available() ) { // KEEP READING TIL FIND NEWLINE chr = V8.read(); // GET RESPONSE: 'O' =OK, 'F' =FAIL if( chr == NL ) return( rtn ); // END OF RESPONSE if( (chr != 'O') && (chr != 'K') ) rtn = -1; } } return( -1 ); // TIMEOUT OR FAILED REQ } /*F****************************************************************** * **********************************************************************/ short v8Fail() { posCur( 2, 0 ); Serial.println((String)"V 8 Failed"); cancel( 0 ); return( -1 ); }/*********************************************************************** DUST COLLECTION AUTOMATION: PARTS TAKEN FROM BOB CLAGETT ON I LIKE TO MAKE STUFF (ILIKETOMAKESTUFF.COM) I/O DEVICE: LCDKEYPAD (DATA TERM) HDW: PCA9685 I2C PWM Servo driver, MG996R Servos, 74HC4051 Analog Mux, CURRENT SENSOR: ACS712-30A (66Ms/A), AND A SOLID STATE RELAY TOOLS NUMBERED 1 - 8, NO ZERO ***********************************************************************/ #include#include #include /************************** DEFINES ************************************/ #define AUTODLY 20000 // AUTO MODE LOCK TIME #define DCRUN 11 // DUST COLLECTOR GO PIN #define DSPDLY 1000 // DELAY BETWEEN VOLT READING DISPLAYS #define DUSTAVGCNT 5 // MUST HAVE DUSTAVGCNT RDNGS TO AVERAGE #define DUSTBADS 3 // MUST HAVE DUSTBADS DUSTMINS TO HALT #define DUSTCHK 1000 // TIME BETWEEN DUST REQUESTS #define DUSTWAT 100 // TIME WAIT FOR DUST DTCTR #define DUSTMIN 8 // DUST BIN MUST HAVE MORE THAN 8" SPACE #define ESC 92 // BACKSLASH, IDE, Serial DOESN'T SEND CNTRL CHRS #define INSTRMAX 32 // INSTRING SIZE #define MITERSAW 6 // MITERSAW NBR #define MUXS0 7 // LSB // ANALOG MUX SELECT 0 #define MUXS1 6 // ANALOG MUX SELECT 1 #define MUXS2 5 // MSB // ANALOG MUX SELECT 2 #define NBRTOOLS 8 // NUMBER OF TOOLS #define NBRVALVES 8 // NUMBER OF VALVES #define PWM_ADDR 0X40 // SERVO CONTOROL ADDRESS #define V8WAT 5000 // PLANER VALVE WAIT TIME 5 SEC #define RDGTHLD 200 // DIGITAL READING THRESHOLD @ 4.887 MV/INCR #define DDRX 3 // SOFTWARE SERIAL RX #define DDTX 4 // SOFTWARE SERIAL TX #define V8RX 8 // VALVE-8 SERIAL RX #define V8TX 9 // VALVE-8 SERIAL TX #define SNSRDLY 20 // SAMPLE TIME 20MS #define SRVODLY 525 // MG996R MVS 60deg in .17 SEC, SERVO ACT DELAY #define SPINUP 1000 // DC SPIN UP TIME MS #define SPINDOWN 3000 // DUST COLLECTOR SPIN DOWN TIME #define SRVOBUMP 5 // VALVE SERVO INCR OR DECR #define NL 10 #define OPN 0 // VALVE CCW #define CLOS 1 // VALVE CW #define ZIN A7 // SENSOR IN enum Modes { IDLE, MANUAL, DSPRDG, AUTO, SETSRVO, MULTVLV, DUSTBINHALT }; typedef unsigned long ulong; #define ssL(str,ndx) for( byte x = 0; x < ndx +1; x++ ) str[x] = str[x +1]; /************************** VARIABLES ************************************/ Adafruit_PWMServoDriver Servo = Adafruit_PWMServoDriver(); SoftwareSerial Dust( DDRX, DDTX ); // DUST DETECTOR SERIAL RX, TX SoftwareSerial V8( V8RX, V8TX ); // PlanerValve (V8) SERIAL RX, TX bool DcOnFlg = false, Rs232 = false, DstOnScrn = false; bool V8Req = false; char *ToolNam[NBRTOOLS+1] = { "0","Sander","BandSaw","Free-1","TableSaw" ,"Free-2","MiterSaw","Router","Planer" }; // TOOL NAMES ARRAY short BasVal[NBRTOOLS +1], RdgTool = 0, VlvOc = CLOS; int DustSpc, DustCnt =0, DustAcc =0, DustBads =0; // DUST RELATED VARS int VlvVals[NBRVALVES +1][2] = {{0,0}, // OPN,CLOS VALVE, NO VALVE ZERO {160,480}, {150,445}, {160,450}, {180,425}, {160,450},{125,435},{150,440} // SANDER BANDSAW FREE-1 tableSAW FREE-2 MITERSAW ROUTER ,{190,465}, }; // MITERSAW ulong NxtDsp =0, AutoTime =0, DustTim = 0; char CurPos[8] = { ESC,'[','0',';','0','0','f',0}; // POSIT CURSOR, ROW,COL char ClrScrn[6] = { ESC,'[','2','j',0}; // CLEAR SCREEN char Hdr[] = {" Dust Collector\n"}, DstChrs[18]; char InStr[INSTRMAX], *VlvPos[2] = {"Open","Close"}; byte InNdx =0, Mode = IDLE, ActvTool = 0, ActVlv = 0, SsNdx =0; /************************** PROTOTYPES ************************************/ void cancel( byte noPnt ); // CANCEL ALL OPERATIONS bool chkAmpChg( int tool ); // CHECK FOR CURRENT CHANGE void chkDustBin(); // PROCESS DUST BIN DEPTHS void chkTools(); // CHECK FOR ACTIVE TOOL void clrScrn(); // CLEAR DATA TERMINAL SCRN void cycVlvs(); // CYCLE ALL VALVES void dcOn(),dcOff(); // DUST COLLECTOR ON OFF void dspDust( int dust ); // DISPLAY DUST STATUS void dspIRdg( char chr ), dspIRdgSu(); // DISPLAY ISNSR READINGS void doChrs(); // PROCESS KBD CHARS void dustHalt( byte row, byte col, char* msg); // DUST HALT char getChr(); // GET A CHAR FROM INSTR int getDust(); // SOFTWARE SERIAL INTERRUPT SERVICE ROUTINE void multVlv( char chr ), multVlvSu(); // OPEN MULTIPLE VALVES short opnVlv( uint8_t num), clsVlv( uint8_t num, byte prnt); // OPN/CLOS VLV void posCur( byte row, byte col ); // SET CURSOR POSTION short reqV8( char cmd ); // SEND REQUEST TO PLANER VALVE int rdSnsr( short snsr); // READ A SENSOR void runTool( char chr ); // START A TOOL void serialEvent(); // RS232 INTERRUPT ROUTINE void setSrvo( char chr), setSrvoSu(); // SET SERVO VALUES short v8Fail(); /*F****************************************************************** * **********************************************************************/ void setup() { int ndx; Serial.begin( 9600 ); // START SERIAL I/O FROM DATA TERMINAL Serial.print( Hdr ); // PRINT HEADER ON DATA TERM Dust.begin( 9600 ); // START SFTW SERIAL I/O FROM DUST BIN V8.begin( 9600 ); // START SFTW SERIAL I/O FROM DUST BIN pinMode( DCRUN, OUTPUT); // I/O PIN OUTPUT FOR RUNNING DUST COLLECTOR Servo.begin(); Servo.setPWMFreq( 50 ); // SET PWM FREQ = 50HZ delay( 1000 ); pinMode( MUXS2, OUTPUT ); // DEFINE ANALOG OUTPUT TO MUX pinMode( MUXS1, OUTPUT ); // DEFINE ANALOG OUTPUT TO MUX pinMode( MUXS0, OUTPUT ); // DEFINE ANALOG OUTPUT TO MUX for( ndx =1; ndx <= NBRTOOLS; ndx++) BasVal[ndx] = rdSnsr( ndx ); // SAVE BASE SNSR RDGS, FOR VOLT CMPRSN for( ndx =1; ndx <= NBRVALVES; ndx++) clsVlv( ndx, 0 ); // CLOSE ALL VALVES } /*F****************************************************************** * **********************************************************************/ void loop() { if( Rs232 == true ) doChrs(); // CHAR ARRIVED ON THE SERIAL I/O FROM DATA TERM if( millis() > DustTim ) chkDustBin(); // CHECK DUST BIN DEPTH if( Mode == DUSTBINHALT ) return; // DUST BIN FULL, ONLY CANCEL WILL RESTART chkTools(); // SEE IF ANY TOOL'S MOTOR IS RUNNING if( (Mode == DSPRDG) ) dspIRdg( 9 ); // PASS CHAR TO DISPLAY ISNSR VOLTAGE if( (Mode == SETSRVO) ) setSrvo( 9 ); // PASS CHAR TO ADJUST SERVO } /*F****************************************************************** * DUSTBIN DEPTH MESSAGE PROCESSING, AFTER DUSTAVGCNT **********************************************************************/ void chkDustBin() { int dust; if((Mode == DSPRDG) || (Mode == SETSRVO)) return; if( (dust = getDust()) < 0 ) return( dustHalt( 3, 0, " No Dust ")); if( (DustAcc > 0) && (DustCnt >= DUSTAVGCNT) ) { // AVERAGE DUST DEPTH REPORTS FROM DETECTOR DustSpc = DustAcc / DustCnt; // UPDATE DUST SPACE dspDust( DustSpc ); DustCnt = DustAcc = 0; // RESET ACCUMULATOR AND COUNT if( (DustSpc <= DUSTMIN) && (DustSpc > 0) && (DcOnFlg == true) ) { if( (Mode == DUSTBINHALT) || (++DustBads < DUSTBADS) ) return; // ALREADY HALT MODE, OR NOT ENOUGH BAD DEPTHS dustHalt( 0, 3, "Dust Bin Halt"); // DC RUNING & DUST BIN FULL } else DustBads = 0; // ONE GOOD DUST READING RESETS DUSTBADS } } /*F****************************************************************** * CHECK FOR TOOL MOTOR RUNNING **********************************************************************/ void chkTools() { int ndx, tool =0; ulong now; if( (Mode != AUTO) && (Mode != IDLE) ) return; // DO NOT CHECK FOR I FLOW UNLESS IN AUTO OR IDLE now = millis(); for( ndx =1; ndx <= NBRTOOLS; ndx++) { // SCAN THROUGH TOOLS & CHECK FOR INCREASED CUR FLOW if( chkAmpChg( ndx )) { // TOOL ON tool = ndx; Mode = AUTO; if( tool == MITERSAW ) AutoTime = millis() + AUTODLY; // MITERSAW RUNNING break; // FOUND ONE } } if( (ActvTool == MITERSAW) && (now < AutoTime) ) return; // TOOL STARTED, WAIT AUTODLY B4 CHANGING if( ActvTool == tool ) return; // SAME TOOL STILL RUNNING if( ActvTool && !tool ) cancel( 0 ); // NO ACTIVE TOOL AND DC IS ON else if( (tool != 0) && (tool != ActvTool) ) runTool( tool ); // START TOOL } /*F****************************************************************** * PROCESS KBD CHRS * 0 CANCEL ALL * 1-8 OPEN VALVE N, BLOWER ON * A CYCLE ALL VALVES * #n TEST ISNSRS * *n SET SERVOS **********************************************************************/ void doChrs() { char chr; while( (chr = getChr()) != 0 ) // READ A CHAR FROM InStr, IF AVAIL { Rs232 = false; // CLEAR SERIAL I/O FLAG if( (Mode == DSPRDG) && (chr != '0')) return( dspIRdg( chr ) ); // PASS CHR TO DSPLY ISENSOR VOLTS if( (Mode == SETSRVO) && (chr != '0')) return( setSrvo( chr )); // PASS CHR TO SERVO SETUP if( (Mode == MULTVLV) && (chr != '0')) return( multVlv( chr )); // PASS CHR TO MULTI VALVE SETUP switch( chr ) { case '0': // CANCEL CURRENT OPERATION cancel( 0 ); break; case 'A': // CYCLE ALL VALVES cycVlvs(); break; case 'B': multVlvSu(); // OPEN MULTIPLE VALVES break; case '1' ... '8': // MANUAL MODE, OPEN VALVE & RUN DC Mode = MANUAL; runTool( chr ); break; case '*': // SPLAT, DISPLAY ISENSOR VOLTAGE READING dspIRdgSu(); break; case '#': // CRUNCH, SETUP SERVOS setSrvoSu(); break; case NL: // GOT NEWLINE break; // DISCARD NEWLINE default: Mode = IDLE; break; } } } /*F****************************************************************** * SETUP FOR DISPLAY ISNSR VOLTAGE READINGS, CALLED FROM doChrs() **********************************************************************/ void dspIRdgSu() { if( DcOnFlg ) dcOff(); // DC IS RUNNING, STOP IT Mode = DSPRDG; // SET DISPLAY READING MODE AutoTime =0; ActVlv = 0; VlvOc = CLOS; clrScrn(); posCur( 0, 2 ); Serial.print("Read Sensor"); posCur( 1, 0 ); Serial.print("Enter Tool Number"); } /*F****************************************************************** * SETUP SERVO SETUP **********************************************************************/ void setSrvoSu() { if( DcOnFlg ) dcOff(); Mode = SETSRVO; clrScrn(); delay( 200 ); posCur( 0, 0 ); Serial.print(" SERVO SETUP"); posCur( 1, 0 ); Serial.print("Enter Servo Number"); } /*F****************************************************************** * RUN A MACHINE **********************************************************************/ void runTool( char chr ) { byte tool; clrScrn(); tool = (chr & 15); // STRIP OFF UPPER BITS OF CHR 0X3n posCur( 0, 6 ); Serial.println( (String)ToolNam[tool] ); // ROW: 0, PRINT TOOL NAME if( (ActvTool > 0) && (ActvTool != tool)) { // NEW ACTIVE TOOL if( DcOnFlg ) dcOff(); clsVlv( ActvTool, 1 ); } ActvTool = tool; opnVlv( ActvTool ); dcOn(); } /*F****************************************************************** * CANCEL CURRENT OPERATION **********************************************************************/ void cancel( byte noPnt ) { short ndx; if( !noPnt ) { clrScrn(); Serial.println(" Cancel Operation"); } if( DcOnFlg ) dcOff(); // DC IS ON, STOP IT for( ndx = 1; ndx <= NBRVALVES; ndx++ ) clsVlv( ndx, 1 ); // CLOSE ALL VALVES Mode = IDLE; AutoTime =0; // CANCEL ANY TOOL RUNNING IN AUTO MODE RdgTool = ActvTool = 0; if( noPnt ) return; clrScrn(); Serial.print((String)Hdr ); } /*F****************************************************************** * DISPLAY ISNSR VOLTAGE READINGS, CALLED FROM loop(), or doChrs() **********************************************************************/ void dspIRdg( char chr ) { short tool, val; int32_t now; if( (chr >= '1' ) && (chr <= '8' )) { // SET NEW TOOL RdgTool = (chr & 0X0F); // STRIP OFF 0X3n posCur( 1, 0 ); // CLEARS ROW 1 Serial.print( (String)ToolNam[RdgTool] + " = " ); NxtDsp = 0; // FORCE IMMEDIATE DISPLAY } now = millis(); // GET CURRENT TIME if((now > NxtDsp) && (RdgTool != 0)) { // TIME TO DISPLAY A CURRENT READING NxtDsp = (now + DSPDLY); // SAVE TIME OF CURRENT DISPLAY val = rdSnsr( RdgTool ); posCur( 1, 10 ); // ROW 1, COL 10 Serial.println( val ); // 4.88MV / INCR } } /*F****************************************************************** * CYCLE ALL VALVES TO REMOVE ANY LARGE SPLINTERS ETC. **********************************************************************/ void cycVlvs() { char tool, chr, buf[24]; clrScrn(); Serial.println(" Cycling Valves "); if( DcOnFlg ) dcOff(); for( tool = 1; tool <= NBRVALVES; tool++ ) { // FLAP ALL VALVES posCur( 1, 0 ); // ROW 2, COL 0 Serial.println((String)ToolNam[tool] ); opnVlv( tool ); delay( SRVODLY ); // WAIT FOR THE SERVO TO ACT clsVlv( tool, 1 ); delay( SRVODLY ); // WAIT FOR THE SERVO TO ACT } ActvTool = 0; clrScrn(); Serial.print( Hdr ); } /*F****************************************************************** * SERVO SETUP **********************************************************************/ void setSrvo( char chr ) { short tool, val, rtn; int32_t now; if( !ActVlv && (chr == 9)) return; // CALLED FROM LOOP, NO ACTIVE VALVE if( !ActVlv && ((chr >= '1') && (chr <='8'))) { // NEW SERVO NMBR ActVlv = chr & 15; // SET NEW ACTIVE VALVE NBR posCur( 1, 0 ); // CLEARS ROW 1 Serial.print( (String)ToolNam[ActVlv] + "-" ); // LIKE "TableSaw-" NxtDsp = 0; // FORCE IMMEDIATE DISPLAY } else if( (chr >= '1') && (chr <= '8') ) { switch( chr ) { case '2': // VAL UP VlvVals[ActVlv][VlvOc] += SRVOBUMP; break; case '4': // OPEN VALVE VlvOc = OPN; // VlvOc: VALVE SHOULD BE OPEN OR CLOSED break; case '6': // CLOSE VALVE VlvOc = CLOS; // VlvOc: VALVE SHOULD BE OPEN OR CLOSED break; case '8': // VAL DN VlvVals[ActVlv][VlvOc] -= SRVOBUMP; break; default: break; } if( (ActVlv == 8) && (VlvOc == OPN) && ((rtn =reqV8( 'O' )) <0)) v8Fail(); else if( (ActVlv == 8) && (VlvOc== CLOS) && ((rtn =reqV8( 'C' )) <0)) v8Fail(); else { Servo.setPWM( ActVlv, 0, VlvVals[ActVlv][VlvOc]); // SET SERVO delay( SRVODLY ); // WAIT FOR SERVO TO ACT } NxtDsp = 0; // FORCE IMMEDIATE DISPLAY } now = millis(); // GET CURRENT TIME if((now > NxtDsp) && (ActVlv != 0)) { NxtDsp = (now + DSPDLY); // SAVE TIME OF NEXT DISPLAY posCur( 1, 10 ); // ROW 1, COL 10 val = VlvVals[ActVlv][VlvOc]; Serial.println( (String)VlvPos[VlvOc] + ":" +val ); // "Close: 450" } } /*F****************************************************************** * TURN DUST COLLECTOR ON **********************************************************************/ void dcOn() { if( Mode == DUSTBINHALT ) return; digitalWrite( DCRUN, 1); posCur( 1, 13 ); Serial.println("DC On "); DcOnFlg = true; DustCnt = DustAcc = 0; // RESET DUST ACCUM & CNT delay( SPINUP ); } /*F****************************************************************** * TURN DUST COLLECTOR OFF **********************************************************************/ void dcOff() { posCur( 1, 3 ); Serial.println("Stopping DC "); delay( 2000 ); // WAIT FOR PLENUM/HOSE TO EMPTY digitalWrite( DCRUN, 0); delay( SPINDOWN ); // WAIT FOR DC SPINDOWN posCur( 1, 0 ); // ERASE ROW 1 TO END OF LINE DcOnFlg = false; } /*F****************************************************************** * SAMPLING CURRENT SENSOR 1-7 (LO NIBBLE 0X0001 - 0X0111), SNSR 8 =0 **********************************************************************/ int rdSnsr( short snsr ) // SNSR: 1 - 8 { int rdVal, cnt, pin, msk =1, rtn; ulong end, tmp; // S0:D7(LSB), S1:D6, S2:D5(MSB) pin scans 7 - 5 for( pin = MUXS0, msk = 1; pin > 4; --pin, msk <<=1 ) { // SET SENSOR # INTO MUX SEL0-SEL2 INPUTS, LSB to MSB, SNSR 8 = 0 if( msk & snsr ) digitalWrite( pin, HIGH ); // WT HI PINS MUXS0,MUXS1,MUXS2 else digitalWrite( pin, LOW ); // WT LOW PINS MUXS0,MUXS1,MUXS2 } delay( 2 ); // WAIT 2MS FOR SEL TO INP TIME end = millis() + SNSRDLY; // SAVE CURRENT TIME + SAMPLE TIME for( cnt = tmp =0; millis() < end; cnt++ ) { // NOISY SIGNAL, AVERAGE FOR SAMPLE TIME rdVal = analogRead( ZIN ); // 0-1023 DIGITAL RDG tmp += rdVal; } // 175 - 180 samples IN 20 MS rtn = tmp / cnt; return( rtn ); } /*F****************************************************************** * CHECK FOR AMPERAGE CHANGE ON A TOOL **********************************************************************/ bool chkAmpChg( int tool) { int rdg; rdg = rdSnsr( tool ); // READINGS RUN FROM OFF: 52-81, ON: 364-461 if( rdg > RDGTHLD ) // NEW SENSOR IGNORE BASE (BasVal[tool] + RDGTHLD)) return( true ); // RETURN TOOL ON else return( false ); // RETURN TOOL OFF } /*F****************************************************************** * GET CHAR FROM INSTR **********************************************************************/ char getChr() { char chr; if( InNdx == 0 ) return( 0 ); chr = InStr[--InNdx]; ssL( InStr, InNdx ); // SHIFT INSTR LEFT if( InNdx == 0 ) Rs232 = false; // INSTR EMPTY return( chr ); } /*F****************************************************************** * CLOSE A VALVE **********************************************************************/ short clsVlv( uint8_t num, byte prnt ) { short rtn = 1; if( DcOnFlg ) dcOff(); VlvOc = CLOS; // SET CURRENT VALVE POSTION = CLOSED if( prnt ) { posCur( 1, 0 ); Serial.println((String)"Vlv "+num+" Clos" ); } if( num == 8 ) rtn = reqV8( 'C' ); // REQUEST VALVE 8 CLOSE else { Servo.setPWM( num, 0, VlvVals[num][CLOS]); // CLOSE VALVE delay( SRVODLY ); // WAIT FOR SERVO TO ACT } Servo.setPWM( 15, 0, 400 ); // DISTRACT PCA9685 TO SERVO 15 ActVlv = 0; if( prnt ) posCur( 1, 0 ); // CLEAR ROW 1 } /*F****************************************************************** * OPEN A VALVE **********************************************************************/ short opnVlv( uint8_t num ) { int rtn = 1; if( DcOnFlg ) dcOff(); VlvOc = OPN; posCur( 1, 0 ); Serial.println((String)"Vlv "+num+" Opn"); if( num == 8 ) rtn = reqV8( 'O' ); // REQUEST VALVE 8 OPEN else { Servo.setPWM( num, 0, VlvVals[num][OPN]); // OPEN VALVE delay( SRVODLY ); } ActVlv = num; } /*F****************************************************************** * RS-232 INTERRUPT SERVICE ROUTINE, DO NOT TARRY HERE **********************************************************************/ void serialEvent() { // RUNS EACH TIME (AFTER) LOOP RUNS int val; char chr; while( Serial.available()) // INTERRUPT SERVICE ROUTINE, DON'T TARRY HERE { chr = (char)Serial.read(); // GET NEW CHAR if( chr < 32 ) continue; // DISCARD NON_PRINtable CHAR if( InNdx >= INSTRMAX ) { // IN STR NDX TOO LARGE, RESET IT Serial.println("Overrun"); break; } val = chr & 15; InStr[InNdx++] = chr; // ADD NEW CHAR TO InStr[] Rs232 = true; // SET FLAG SO MAIN LOOP CAN DO SOMETHING ABOUT IT } } /*F****************************************************************** * REQUEST DEPTH FROM DUST DETECTOR, WAIT FOR RESPONSE * DATA FROM THIS MAKES SERIOUS DECISIONS ABOUT SHUTING DOWN DC **********************************************************************/ int getDust() { // @ 9600 CHARS ARRIVE EVERY 1Ms int val, dstVal; char chr; ulong end; // Serial.println((String)"getDust: Bgn"); Dust.listen(); Dust.print( "D\n" ); // SEND DUST DEPTH REQUEST TO DUST DET DustSpc = 0; DustTim = millis() + DUSTCHK; // SET TIME OF NEXT DUST DEPTH REQUEST val = dstVal =0; // BELOW: < DustTim IN CASE DUSTDET DOESN'T RESPOND end = millis() + DUSTWAT; // SET TIMER FOR DUST DET RESONSE while( millis() < end ) { // LOOP HERE WHILE DUSTREQ & NOT DUSTTIME if( Dust.available() ) { // KEEP READING TIL FIND NEWLINE chr = Dust.read(); // GET NEW CHAR // Serial.println((String)"GotChr: "+chr); if( chr == '\n' ) { // END OF TRANSMISSION DustAcc += dstVal; // ACCUMULATE DUST DEPTH DustCnt++; // BUMP DUST READING COUNTER break; } if( (chr < '0') || (chr > '9')) continue; // DISCARD NON NUMERIC CHAR val = (chr & 15); // CONVERT ASCII TO BIN: '2' (0X32) & 0X0F = 2 dstVal = (dstVal * 10) + val; // ACCUM DEC DUST DEPTH VALS } } // Serial.println((String)"getDust: End, dstVal: "+dstVal); if( millis() > end ) return( -1 ); return( dstVal ); } /*F****************************************************************** * DUST HALT **********************************************************************/ void dustHalt( byte row, byte col, char *msg) { // DC RUNING & DUST BIN FULL, STOP EVERYTHING Mode = DUSTBINHALT; // ADVERTISE WHY WE'RE SHUTDOWN clrScrn(); posCur( row, col ); // SET CURSOR POSTION Serial.println( (String)msg ); cancel( 1 ); // STOP EVERYTHING } /*F****************************************************************** * OPEN MULTIPLE VALVE SETUP **********************************************************************/ void multVlvSu() { if( DcOnFlg ) dcOff(); Mode = MULTVLV; clrScrn(); delay( 200 ); // posCur( 0, 0 ); // Serial.print("OPEN ANOTHER VALVE"); posCur( 1, 0 ); Serial.print("Enter Valve Number"); dcOff(); } /*F****************************************************************** * OPEN MULTIPLE VALVES **********************************************************************/ void multVlv( char chr ) // OPEN MULTIPLE VALVES { short tool; if( (chr >= '1' ) && (chr <= '8' )) { // SET NEW TOOL Mode = MANUAL; tool = (chr & 0X0F); // STRIP OFF 0X3n posCur( 1, 0 ); // CLEARS ROW 1 Serial.print( (String)"+ "+ToolNam[tool] ); opnVlv( tool ); dcOn(); } else cancel( 0 ); } /*F****************************************************************** * POSITION CURSOR Esc[r;ccf SET CURSOR TO ROW COL **********************************************************************/ void posCur( byte row, byte col ) { char str[8]; strcpy( str, CurPos ); sprintf( &str[2], "%1d;%02df", row, col ); Serial.print( str ); delayMicroseconds( 200 ); } /*F****************************************************************** * CLEAR SCREEN **********************************************************************/ void clrScrn() { Serial.print( ClrScrn ); delay( 200 ); DstOnScrn = false; } /*F****************************************************************** * RUN A MACHINE **********************************************************************/ void dspDust( int dustSpc ) { char buf[32]; if( !DstOnScrn ) { // NEED TO REPRINT "Dust Space" posCur( 3, 0 ); // SET CURSOR POSTION Serial.print( (String)"Dust Space: "); DstOnScrn = true; } posCur( 3, 12 ); sprintf( buf, "%02u\"", dustSpc ); Serial.print( (String)buf ); } /*F****************************************************************** * SEND PLANER VALVE (V8) OPEN/CLOSE REQUEST RETURN: 1 = OK, else -1 **********************************************************************/ short reqV8( char req ) // REQ IS UC LETTER 'O' or 'C' { ulong end; char chr, resp =0; short rtn = 1; V8.listen(); V8.println((String)req ); // SEND PLANER VALVE REQUEST end = millis() + V8WAT; // SET TIMER FOR PLANER VALVE RESONSE while( millis() < end ) { // LOOP HERE WHILE PLANER VALVE MOVES if( V8.available() ) { // KEEP READING TIL FIND NEWLINE chr = V8.read(); // GET RESPONSE: 'O' =OK, 'F' =FAIL if( chr == NL ) return( rtn ); // END OF RESPONSE if( (chr != 'O') && (chr != 'K') ) rtn = -1; } } return( -1 ); // TIMEOUT } /*F****************************************************************** * **********************************************************************/ short v8Fail() { posCur( 2, 0 ); Serial.println((String)"V 8 Failed"); cancel( 0 ); return( -1 ); }