Auto Hypot tester

Hello,

I'm trying to program an ATMega2560 to control a hypot tester for work. I've done things like this in the past but I haven't needed to do this many nested "if" statements and I think the logic is probably wrong somewhere.

I'd like the program to wait for a button press, "TB" before starting anything. Once it starts, I'd like it to go through the first set of relay commands. Once the program receives a "PASS" signal from the hypot tester, it is supposed to increment "PASSCounter" then proceed to the next set of relay commands.

Currently it is cycling through each of the "if" statements endlessly. It does this without a button being pressed, or even connected for that matter.

Any insight into this would be much appreciated.

/*
  This program is designed to automate an Associated Research Hypot tester (Model 3870).
  The user of the box need only to set the tester to the proper program, then press start on the box.
  The box will run the attached part through IR/DWV in "criss-cross", "row to row", and "pin to shell".
  If a failure occurs at any point during the testing, the tester will error out. The box will need to be reset
  using the reset button prior to restarting the test.
*/
  //These lines tell the controller the name of the variable and the pin it is assigned to. 
  //"Const int" are variables that do not change. "int" variables can change.
  
const int R2R = 44; //ROW TO ROW RELAY PIN 
const int CC = 45; //CRISS-CROSS RELAY PIN
const int SL = 46; //SHELL RELAY PIN
const int TR = 47; //TEST RELAY PIN
const int RR = 48; //RESET RELAY PIN
const int TB = 22; //TEST BUTTON PIN
const int RB = 23; //RESET BUTTON PIN
const int PASS = 24; // PASS OUTPUT FROM TESTER
const int FAIL = 25; // FAIL OUTPUT FROM TESTER


int TB_State = 0;
int RB_State = 0;
int PASSCounter = 0;
int PASSState = 0;
int FAILState = 0;

void setup() {
  // put your setup code here, to run once:
  //These lines of code tell the controller what type of communication to expect from each variable.
pinMode(R2R, OUTPUT);
pinMode(CC, OUTPUT);
pinMode(SL, OUTPUT);
pinMode(TR, OUTPUT);
pinMode(RR, OUTPUT);
pinMode(TB, INPUT); //Buttons and outputs from the tester are defined as "INPUT" to the controller.
pinMode(RB, INPUT);
pinMode(PASS, INPUT);
pinMode(FAIL, INPUT);
}

void loop() {
  // put your main code here, to run repeatedly:
  //these "states" are used to read the condition of the input variables
TB_State = digitalRead(TB);
RB_State = digitalRead(RB);
PASSState = digitalRead(PASS);
FAILState = digitalRead(FAIL);

//instructions to reset the hypot tester and turn off on test relays when "Reset" is pressed.
if (RB_State == LOW){
      digitalWrite(RR, HIGH);
      delay(100);
      digitalWrite(R2R, LOW);
      digitalWrite(CC, LOW);
      digitalWrite(SL, LOW);
      digitalWrite(TR, LOW);
      digitalWrite(RR, LOW);
      
}

//These "if" statements tell the controller what to do when the test button is pressed.
if (TB_State == HIGH){ 
    if (RB_State == HIGH){
      digitalWrite(RR, HIGH);
      delay(100);
      digitalWrite(R2R, LOW);
      digitalWrite(CC, LOW);
      digitalWrite(SL, LOW);
      digitalWrite(TR, LOW);
      digitalWrite(RR, LOW);
      }
//"PASSState" monitors how many times the hypot tester has passed. When the "PASSCounter"
//increases in count, it goes to the next "if" statement. This allows the controller to
//test Row to Row, Criss-cross, and shell automatically.
    if (PASSState = HIGH){
      PASSCounter++;
      }
    if (PASSCounter = 1){
  digitalWrite(R2R, HIGH);
  digitalWrite(CC, LOW);
  digitalWrite(SL, LOW);
  digitalWrite(RR, LOW);
  delay(100);
  digitalWrite(TR, HIGH);
  delay(500);
  digitalWrite(TR, LOW);
      }
   if (PASSCounter = 2){
  digitalWrite(R2R, LOW);
  digitalWrite(CC, HIGH);
  digitalWrite(SL, LOW);
  digitalWrite(RR, LOW);
  delay(100);
  digitalWrite(TR, HIGH);
 
  delay(500);
  digitalWrite(TR, LOW);
      }
   if (PASSCounter = 3){
  digitalWrite(R2R, LOW);
  digitalWrite(CC, LOW);
  digitalWrite(SL, HIGH);
  digitalWrite(RR, LOW);
  delay(100);
  digitalWrite(TR, HIGH);
  delay(500);
  digitalWrite(TR, LOW);    
      }
      
   if (PASSCounter = 4){
   digitalWrite(R2R, LOW);
   digitalWrite(CC, LOW);
   digitalWrite(SL, LOW);
   digitalWrite(TR, LOW);
   digitalWrite(RR, HIGH);
   delay(500);
   digitalWrite(RR, LOW);    
      }
//The controller will shut everything down if a "FAIL" is detected.      
    if (FAILState == HIGH){
      digitalWrite(R2R, LOW);
      digitalWrite(CC, LOW);
      digitalWrite(SL, LOW);
      digitalWrite(TR, LOW);
      digitalWrite(RR, HIGH);
      delay(500);
      digitalWrite(RR, LOW);
      }
      
    }

}

How are the button switches wired?

 if (PASSState = HIGH){

You have a bunch of these. = for assignment, == for compare.

From the if structure reference.

Beware of accidentally using the single equal sign (e.g. if (x = 10) ). The single equal sign is the assignment operator, and sets x to 10 (puts the value 10 into the variable x). Instead use the double equal sign (e.g. if (x == 10) ), which is the comparison operator, and tests whether x is equal to 10 or not. The latter statement is only true if x equals 10, but the former statement will always be true.

This is because C++ evaluates the statement if (x=10) as follows: 10 is assigned to x (remember that the single equal sign is the (assignment operator)), so x now contains 10. Then the 'if' conditional evaluates 10, which always evaluates to TRUE, since any non-zero number evaluates to TRUE. Consequently, if (x = 10) will always evaluate to TRUE, which is not the desired result when using an 'if' statement. Additionally, the variable x will be set to 10, which is also not a desired action.
if (PASSState = HIGH){

Every instance of "if( X = Y )" should be "if (X == Y)"; '=' is an assignment, '==' is a test of equality.

Thank you all for the help on "=" vs "==". I definitely missed several of those... :confused:

I don't have switches wired in yet, but my plan was to wire "TB" to pos 22 and 5V. and "RB" to pos 23 and 5V.

Here is my new code with all "==" inputted. It still cycles through without any switch being pressed. I also added a final "else" statement that I thought would keep everything off until the "if" statement was true.

/*
  This program is designed to automate an Associated Research Hypot tester (Model 3870).
  The user of the box need only to set the tester to the proper program, then press start on the box.
  The box will run the attached part through IR/DWV in "criss-cross", "row to row", and "pin to shell".
  If a failure occurs at any point during the testing, the tester will error out. The box will need to be reset
  using the reset button prior to restarting the test.
*/
  //These lines tell the controller the name of the variable and the pin it is assigned to. 
  //"Const int" are variables that do not change. "int" variables can change.
  
const int R2R = 44; //ROW TO ROW RELAY PIN 
const int CC = 45; //CRISS-CROSS RELAY PIN
const int SL = 46; //SHELL RELAY PIN
const int TR = 47; //TEST RELAY PIN
const int RR = 48; //RESET RELAY PIN
const int TB = 22; //TEST BUTTON PIN
const int RB = 23; //RESET BUTTON PIN
const int PASS = 24; // PASS OUTPUT FROM TESTER
const int FAIL = 25; // FAIL OUTPUT FROM TESTER


int TB_State = 0;
int RB_State = 0;
int PASSCounter = 0;
int PASSState = 0;
int FAILState = 0;

void setup() {
  // put your setup code here, to run once:
  //These lines of code tell the controller what type of communication to expect from each variable.
pinMode(R2R, OUTPUT);
pinMode(CC, OUTPUT);
pinMode(SL, OUTPUT);
pinMode(TR, OUTPUT);
pinMode(RR, OUTPUT);
pinMode(TB, INPUT); //Buttons and outputs from the tester are defined as "INPUT" to the controller.
pinMode(RB, INPUT);
pinMode(PASS, INPUT);
pinMode(FAIL, INPUT);
}

void loop() {
  // put your main code here, to run repeatedly:
  //these "states" are used to read the condition of the input variables
TB_State = digitalRead(TB);
RB_State = digitalRead(RB);
PASSState = digitalRead(PASS);
FAILState = digitalRead(FAIL);

//instructions to reset the hypot tester and turn off on test relays when "Reset" is pressed.
if (RB_State == HIGH){
      digitalWrite(RR, HIGH);
      delay(100);
      digitalWrite(R2R, LOW);
      digitalWrite(CC, LOW);
      digitalWrite(SL, LOW);
      digitalWrite(TR, LOW);
      digitalWrite(RR, LOW);
      
}

//These "if" statements tell the controller what to do when the test button is pressed.
if (TB_State == HIGH){ 
    if (RB_State == HIGH){
      digitalWrite(RR, HIGH);
      delay(100);
      digitalWrite(R2R, LOW);
      digitalWrite(CC, LOW);
      digitalWrite(SL, LOW);
      digitalWrite(TR, LOW);
      digitalWrite(RR, LOW);
      }
//"PASSState" monitors how many times the hypot tester has passed. When the "PASSCounter"
//increases in count, it goes to the next "if" statement. This allows the controller to
//test Row to Row, Criss-cross, and shell automatically.
    if (PASSState == HIGH){
      PASSCounter++;
      }
    if (PASSCounter == 1){
  digitalWrite(R2R, HIGH);
  digitalWrite(CC, LOW);
  digitalWrite(SL, LOW);
  digitalWrite(RR, LOW);
  delay(100);
  digitalWrite(TR, HIGH);
  delay(500);
  digitalWrite(TR, LOW);
      }
   if (PASSCounter == 2){
  digitalWrite(R2R, LOW);
  digitalWrite(CC, HIGH);
  digitalWrite(SL, LOW);
  digitalWrite(RR, LOW);
  delay(100);
  digitalWrite(TR, HIGH);
 
  delay(500);
  digitalWrite(TR, LOW);
      }
   if (PASSCounter == 3){
  digitalWrite(R2R, LOW);
  digitalWrite(CC, LOW);
  digitalWrite(SL, HIGH);
  digitalWrite(RR, LOW);
  delay(100);
  digitalWrite(TR, HIGH);
  delay(500);
  digitalWrite(TR, LOW);    
      }
      
   if (PASSCounter == 4){
   digitalWrite(R2R, LOW);
   digitalWrite(CC, LOW);
   digitalWrite(SL, LOW);
   digitalWrite(TR, LOW);
   digitalWrite(RR, HIGH);
   delay(500);
   digitalWrite(RR, LOW);    
      }
//The controller will shut everything down if a "FAIL" is detected.      
    if (FAILState == HIGH){
      digitalWrite(R2R, LOW);
      digitalWrite(CC, LOW);
      digitalWrite(SL, LOW);
      digitalWrite(TR, LOW);
      digitalWrite(RR, HIGH);
      delay(500);
      digitalWrite(RR, LOW);
      }
      
    }
else{
  digitalWrite(R2R, LOW);
  digitalWrite(CC, LOW);
  digitalWrite(SL, LOW);
  digitalWrite(TR, LOW);
  digitalWrite(RR, LOW);
}
}

With the button switch inputs unconnected or "floating" the states of the inputs are undefined so the behavior of the code is undefined.

The best way, in most cases, to wire a switch is one side of the switch to ground and the other side of the switch to an input with the pinMode set to INPUT_PULLUP. The input will read HIGH when the switch is not pressed and LOW when the switch is pressed. Adjust the logic in the code accordingly.

Also, I suggest that you initialize the Serial port so that you can do debug prints to follow program flow and monitor variable values.

Thank you for that! I wired in a button and changed them to INPUT_PULLUP. They now work every time they are pressed

I realized I needed to add a line in the final "if" section that resets the PASSCounter to 0 once the sequence was complete. Otherwise it was sitting in the last if loop forever.

So the button is fixed, and I think it'll increment the "PASSCounter" when I hook up the tester.

The last thing I need to figure out (I'm sure there will be other things...) is how to tell the controller to keep the "RR" input on while the test is being conducted and to only turn off after the PASS input is detected. Would this be a "while" command?

A little convoluted I guess. Basically I'm connecting certain positions using the RR relay that need to stay on until it passes.

In microcontroller programming we try to avoid while and for loops unless the execute very quickly (tens or hundreds of microseconds). See Several things at a time..

Is there a better way to achieve what I'm trying to do then?

I'd like R2R to be high during the entire test and only turn off when the PASSState ==HIGH. But I also need TR to turn on for 500 to tell the hypot tester to start testing.

 if (PASSCounter == 0){
  digitalWrite(R2R, HIGH);
  digitalWrite(CC, LOW);
  digitalWrite(SL, LOW);
  digitalWrite(RR, LOW);
  delay(100);
  digitalWrite(TR, HIGH);
  delay(500);
  digitalWrite(TR, LOW);
      }

Google"Arduino state machine".

A state machine approach might look something like this, which is based on your earlier code.

Note that this is intended to look for the test & reset buttons changing from not-pressed to pressed rather than being pressed.

Buttons are checked every 50mS.

'HIGH' on PASS or FAIL is assumed to be that condition "asserted" (as was the case in your code.)

Compiles, not tested, YMMV, etc...

/*
  This program is designed to automate an Associated Research Hypot tester (Model 3870).
  The user of the box need only to set the tester to the proper program, then press start on the box.
  The box will run the attached part through IR/DWV in "criss-cross", "row to row", and "pin to shell".
  If a failure occurs at any point during the testing, the tester will error out. The box will need to be reset
  using the reset button prior to restarting the test.
*/
  //These lines tell the controller the name of the variable and the pin it is assigned to.
  //"Const int" are variables that do not change. "int" variables can change.


//states
#define ST_IDLE_INIT        0
#define ST_IDLE             1
#define ST_TESTING          2
#define ST_CHKPASSFAIL      3
#define ST_RESETREQUIRED    4

//tests
#define NUM_HYPOT_TESTS     3
//
#define ST_TEST_ROWTOROW    0
#define ST_TEST_CRISSCROSS  1
#define ST_TEST_SHELL       2

 
const uint8_t R2R = 44; //ROW TO ROW RELAY PIN
const uint8_t CC = 45; //CRISS-CROSS RELAY PIN
const uint8_t SL = 46; //SHELL RELAY PIN
const uint8_t TR = 47; //TEST RELAY PIN
const uint8_t RR = 48; //RESET RELAY PIN
const uint8_t TB = 22; //TEST BUTTON PIN
const uint8_t RB = 23; //RESET BUTTON PIN
const uint8_t PASS = 24; // PASS OUTPUT FROM TESTER
const uint8_t FAIL = 25; // FAIL OUTPUT FROM TESTER

uint8_t
    stateTest,
    testIdx,
    lastRB,
    lastTB;

void setup() 
{
    // put your setup code here, to run once:
    //These lines of code tell the controller what type of communication to expect from each variable.
    pinMode(R2R, OUTPUT);
    pinMode(CC, OUTPUT);
    pinMode(SL, OUTPUT);
    pinMode(TR, OUTPUT);
    pinMode(RR, OUTPUT);
    pinMode(TB, INPUT_PULLUP); //Buttons and outputs from the tester are defined as "INPUT" to the controller.
    pinMode(RB, INPUT_PULLUP);
    pinMode(PASS, INPUT_PULLUP);
    pinMode(FAIL, INPUT_PULLUP);

    lastRB = digitalRead( RB );     //get current state of reset button
    lastTB = digitalRead( TB );     //get current state of test button   
    stateTest = ST_IDLE_INIT;
    testIdx = 0;
    
}//setup

bool ReadResetButton( void )
{
    static uint32_t
        timeRRB;
    uint32_t
        timeNow = millis();
    uint8_t
        nowRB = digitalRead( RB );

    if( timeNow - timeRRB < 50ul )
        return false;

    timeRRB = timeNow;
    
    if( nowRB != lastRB )
    {
        lastRB = nowRB;
        if( nowRB == LOW )
            return true;
    }//if

    return false;
    
}//ReadResetButton

bool ReadTestButton( void )
{
    static uint32_t
        timeRTB;
    uint32_t
        timeNow = millis();
    uint8_t
        nowTB = digitalRead( TB );

    if( timeNow - timeRTB < 50ul )
        return false;

    timeRTB = timeNow;
        
    if( nowTB != lastTB )
    {
        lastTB = nowTB;
        if( nowTB == LOW )
            return true;
    }

    return false;
    
}//ReadResetButton

void loop() 
{
    switch( stateTest )
    {
        case    ST_IDLE_INIT:
            //idle state; test button not hit yet
            digitalWrite(R2R, LOW);
            digitalWrite(CC, LOW);
            digitalWrite(SL, LOW);
            digitalWrite(TR, LOW);
            digitalWrite(RR, LOW);        
            
            stateTest = ST_IDLE;
            
        break;
        
        case    ST_IDLE:            
            if( ReadTestButton() )
            {
                testIdx = 0;
                stateTest = ST_TESTING;
                
            }//if
            
        break;

        case    ST_TESTING:            
            switch( testIdx )
            {
                case    ST_TEST_ROWTOROW:
                    digitalWrite(R2R, HIGH);
                    digitalWrite(CC, LOW);
                    digitalWrite(SL, LOW);
                    digitalWrite(RR, LOW);
                    delay(100);
                    digitalWrite(TR, HIGH);
                    delay(500);
                    digitalWrite(TR, LOW);
                    
                    stateTest = ST_CHKPASSFAIL;                    
                
                break;

                case    ST_TEST_CRISSCROSS:
                    digitalWrite(R2R, LOW);
                    digitalWrite(CC, HIGH);
                    digitalWrite(SL, LOW);
                    digitalWrite(RR, LOW);
                    delay(100);
                    digitalWrite(TR, HIGH);                    
                    delay(500);
                    digitalWrite(TR, LOW);
                    
                    stateTest = ST_CHKPASSFAIL;
                               
                break;                                

                case    ST_TEST_SHELL:
                    digitalWrite(R2R, LOW);
                    digitalWrite(CC, LOW);
                    digitalWrite(SL, HIGH);
                    digitalWrite(RR, LOW);
                    delay(100);
                    digitalWrite(TR, HIGH);
                    delay(500);
                    digitalWrite(TR, LOW); 
                      
                    stateTest = ST_CHKPASSFAIL;
                
                break;
                
            }//switch
            
        break;  

        case    ST_CHKPASSFAIL:
        
            if( digitalRead( PASS ) == HIGH )
            {
                testIdx++;
                if( testIdx == NUM_HYPOT_TESTS )
                    stateTest = ST_IDLE_INIT;       //all tests passed; back to init state
                else
                    stateTest = ST_TESTING;         //set up for next test

            }//if
            else if( digitalRead( FAIL ) == HIGH )
                stateTest = ST_RESETREQUIRED;       //fail; require reset to be pressed
            else
                return;
            
        break;   

        case    ST_RESETREQUIRED:
            //wait for reset to be pressed
            if( ReadResetButton() )
            {
                //reset
                digitalWrite(RR, HIGH);
                delay(100);
                digitalWrite(R2R, LOW);
                digitalWrite(CC, LOW);
                digitalWrite(SL, LOW);
                digitalWrite(TR, LOW);
                digitalWrite(RR, LOW);
                      
                stateTest = ST_IDLE_INIT;
                        
            }//if
        
        break;        
                
    }//switch
    
}//loop

Thank you for the code. I'm going to wire up the tester's RS232 ports and give it a go. A lot of this syntax is beyond my current knowledge of coding, but I'm going to look at the functions of each to try and piece the logic together.

I Googled "Arduino state machine", looks like I have some "light" reading to do on this topic.

I'll update after I get it all wired up and tested.

Edit:

I need to order a few more relays for the PASS/FAIL signal to communicate with the microcontroller. Putting in an order today.

This topic was automatically closed 120 days after the last reply. New replies are no longer allowed.