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 );
}