NerdKits - electronics education for a digital generation

You are not logged in. [log in]

NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.

Project Help and Ideas » Multi Wire Tester

June 21, 2012
by live4the1
live4the1's Avatar

I am wanting to put together a wire/cable tester and need a little help with that. Just to stay on the simpler side, let's say that all I am testing is three wires and the tester will have a button that will start the test (PD4) and a button that will stop the test (PD5) along with an alarm (PD0) if there is a failure. I plan on using Port B for my outputs and Port C for my inputs. Wire #1 would be connected to PB1 on one end and PC1 on the other with wire #2 at PB2 and PC2 and so on. I know that I need to output at one end of the wire and check for the input at the other end so I will need to check to make sure the the output is read from the correct input and only that input. If that wire passes, I want to light an led (PD1-PD3) and go to the next wire and then continue that so that I can wiggle and manipulate the cable to check for intermittent failures. If there is a failure, I want to activate the alarm and be able to look at the leds and see where the last pass was thus indicating where the failure occurred. The stop button would force the program to stop looping the wire test procedure so that I could disconnect one cable and connect another. This seems like it should be simple but being at the "hey I made an led blink" stage, it's a little intimidating. From several examples that I have worked with, it looks like I need to force the inputs high or low so as not to have them floating and then change the state from the inputs. What is the best way to do that in this little project? I am also curious as to how I would stop the test loop on a wire failure but still have the last pass indicating led stay on and the alarm on? I'm not asking anyone to write the code for me (yet ;) ) but I need some direction.

June 21, 2012
by Ralphxyz
Ralphxyz's Avatar

Hi live4the1, the led blink and tempsensor project will give you most of what you are looking for.

I fact that will give you continuity and conductivity.

If you blink your led (wire) at 5volt (PBoutput) you should see 1024 ADC you'd have to allow for voltage drop per length of cable.

Won't you need a multiplexer as there are only 6 pins for the ADC?

For some ideas on how to cycle through the wires search for Knight Rider.

Ralph

June 21, 2012
by live4the1
live4the1's Avatar

Ralph, actually, I didn't think that I would need to use the analog functions since I am just sending out a high on the output and checking the inputs.

June 21, 2012
by pcbolt
pcbolt's Avatar

@ live4the1

I think I would try setting up the input pins with the pull-up resistors on and set the output pins high (the Nerdkit guide will show you how to do this). To test the cable, just set your output pin low and check the value of the input pin to make sure it is low as well. You can have flag variables for starting and stopping the test procedure like this:

uint8_t ok_to_test = 0;

while(1){
  if (ok_to_test){
    // do your testing here
  }
  if (PIND & (1<<PD4)) ok_to_test = 1;    // allow testing
  if (PIND & (1<<PD5)) ok_to_test = 0;    // skip testing
June 25, 2012
by live4the1
live4the1's Avatar

I decided to start simple and test one wire but for some reason the program will not compile. I'm sure that there are some logic mistakes that I have made in the program that I want to figure out by testing the program but I can't even get the program to compile. Can you see where I have gone wrong? It seems that I have all of my curly brackets in place but the error I get leads me to believe that I may have missed something. The errors are indicated at lines 39, 50, and 51. Here is my code:

#define F_CPU 14745600

#include <stdio.h>

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <inttypes.h>

#include "../libnerdkits/delay.h"
#include "../libnerdkits/uart.h"

int main(){

DDRB |= (1<<PB1); // WIRE 1 OUT

DDRC &= ~(1<<PC1); // WIRE 1 IN
PORTC |= (1<<PC1); // TURN ON PULL UP RESISTOR

DDRD |= (1<<PD2); // PASS LED
DDRD |= (1<<PD5); // FAIL LED

DDRD &= ~(1<<PD6); // START TEST BUTTON
DDRD &= ~(1<<PD7); // STOP TEST BUTTON
PORTD |= (1<<PD6); // TURN ON PULL UP RESISTOR
PORTD |= (1<<PD7); // TURN ON PULL UP RESISTOR

uint8_t start_test = 0;

while(1)
    {
    if (start_test)
        {
        PORTB |= (1<<PB1); // Turn on PB1   
            if (PINC &= 0010); // Check to see if PC1 is high
            {
            PORTD |= (1<<PD2); // Turn on pass led
            }
            else{
                PORTD &= ~(1<<PD2); // Make sure pass led is off                
                PORTD |= (1<<PD5);  // Turn on fail alarm           
                }
        PORTB &= ~(1<<PB1); // Turn off PB1

    if (PIND & (1<<PD4)) start_test = 1;    // allow testing
    if (PIND & (1<<PD5)) start_test = 0;    // skip testing
        }

    }
    return 0;
}
June 25, 2012
by dvdsnyd
dvdsnyd's Avatar

live4the1,

I quickly looked at your while loop. I think you were missing a few brackets to start and end your if statements Especially, if you look at your lines 45 and 46, you don't have any brackets. I am not sure how to do inline functions. Here is how I would write your while loop

while(1)
    {
        if (start_test)
        {
            PORTB |= (1<<PB1); // Turn on PB1 
        } 
        if (PINC &= 0010); // Check to see if PC1 is high
        {
            PORTD |= (1<<PD2); // Turn on pass led
        }
        else
        {
            PORTD &= ~(1<<PD2); // Make sure pass led is off               
            PORTD |= (1<<PD5);  // Turn on fail alarm          
        }
            PORTB &= ~(1<<PB1); // Turn off PB1
        if (PIND & (1<<PD4))
        {
            start_test = 1;    // allow testing
        }
        if (PIND & (1<<PD5)) 
        {
            start_test = 0;    // skip testing
        }

    }

Like I said, I think it is correct syntax-wise now. I didn't look at your logic. Hopefully this helps.

David

June 25, 2012
by live4the1
live4the1's Avatar

Thanks David, I actually got it to compile after messing around with it a bit. Why would I read 5V from a pin that I set as an input? Pin PC1 reads 5V with and with out the pull up resistors. My PD5 and PD6 don't do this. Is it because PC0 - PC5 are have to be changed from ADC to digital I/O? If that is the case, what do I need to do to make the change?

June 25, 2012
by pcbolt
pcbolt's Avatar

@live4the1

I think there are a few problems with the code as it is posted. The statements you use for starting/stopping the tests should be outside the "if(start_test){" code block. Also, you setup pins PD6 and PD7 (LCD pins?) as start/stop pins but you're testing PD4 and PD5. Your pin setup looks good but the "while(1)" loop should look something like:

uint8_t start_test = 0;

while(1){
    if (start_test){
        PORTB |= (1<<PB1); // Turn on PB1  
        if (PINC &= 0010){  // Check to see if PC1 is high ** removed ; **
            PORTD |= (1<<PD2); // Turn on pass led
        }
        else{
            PORTD &= ~(1<<PD2); // Make sure pass led is off               
            PORTD |= (1<<PD5);  // Turn on fail alarm          
        }
        PORTB &= ~(1<<PB1); // Turn off PB1
    }
    if (PIND & (1<<PD6)) start_test = 1;    // allow testing  ** change pin **
    if (PIND & (1<<PD7)) start_test = 0;    // skip testing   ** change pin **
}
return 0;
}

As far as the voltage on PC1, once you enable the pullups, you should read 5v since the resistor is pulling it up to that value. If you turn off the pullups, you are essentially "floating" the pin so it can have just about any value from 0 to 5v when you test it. Not sure why PD6 doesn't act that way but PD5 is an output pin.

June 25, 2012
by live4the1
live4the1's Avatar

Thanks pcbolt, I've learned a bit since I've started working on this little project. I have had to change a few of my initial pin assignments because some were being used by the comms connection and the programming pin. I did not recognize that the start/stop instructions were inside the if statement. That expains why that part didn't work but I was stuck on other issues and had not gotten to figuring that one out yet. I actually meant PD7 instead of PD5. So what would be the best way to program this so that when the correct connections are made between an input and output is made, the pass led is turned on? If I turn off the pull up resistors and just input high from the output pin the input pin will float when the output is low but if I enable the pull up resistors the input stays high. If the input is high with the pur enabled how do I bring it low when my output is active?

June 25, 2012
by pcbolt
pcbolt's Avatar

Try using "low" as the test condition. If your output pin is high and you connect a wire to your input pin with pullups enabled you should get 5v or a "one" on your input pin. (You will also get "one" if no wire is connected.) If you then "test" the wire by pulling the output low (i.e. writing zero to the output pin), your input pin will read "zero" unless the wire is broken.

June 25, 2012
by pcbolt
pcbolt's Avatar

Oh and there is something I just noticed in your code, the line:

if (PINC &= 0010)

...will change all the other pins in PORT C, since it is an assignment operator. For an "if" test you just need:

if (PINC & 0010)     // no equal sign

For testing if the pin is low use:

if ((PINC & 0010) == 0)
// or to make it more readable use...
if ((PINC & (1<<PC1) == 0)
June 25, 2012
by pcbolt
pcbolt's Avatar

Oops - that last code line should be:

if ((PINC & (1<<PC1)) == 0)
June 26, 2012
by live4the1
live4the1's Avatar

Wow, that is good stuff. Thanks!

June 26, 2012
by live4the1
live4the1's Avatar

What I will actually need to do in the test is look to see if the wire in test is is only connected to where it is suppose to be connected and it is not shorted somewhere. What I thought that

if (PINC &= 0010)

did was it would check to make sure that only PC1 changed state. What would be the best way to check multiple conditions? I would be checking PC1, PC2, and PC3 so that the output from the correct pin is only going to the correct input.

June 26, 2012
by live4the1
live4the1's Avatar

This is what I have now:

#define F_CPU 14745600
#include <stdio.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <inttypes.h>
#include "../libnerdkits/delay.h"
#include "../libnerdkits/uart.h"

int main(){

DDRB |= (1<<PB1); // WIRE 1 (OUTPUT)

DDRC &= ~(1<<PC1); // WIRE 1 (INPUT)
PORTC |= (1<<PC1); // TURN ON PULL UP RESISTOR

DDRD |= (1<<PD2); // PASS LED (OUTPUT)
DDRD |= (1<<PD5); // FAIL LED (OUTPUT)
DDRD &= ~(1<<PD6); // START TEST BUTTON (INPUT)
DDRD &= ~(1<<PD7); // STOP TEST BUTTON (INPUT)
PORTD |= (1<<PD6); // TURN ON PULL UP RESISTOR
PORTD |= (1<<PD7); // TURN ON PULL UP RESISTOR

uint8_t start_test = 0;

    while(1)
    {
        if (start_test);
        {
        PORTB |= (1<<PB1); // Make PB1 high
        PORTB &= ~(1<<PB1); // Make PB1 low
                if (PINC & (1<<PC1)==0) // Check to see if PC1 is low
                {
                PORTD |= (1<<PD2); // Turn on pass led
                }
                else // Failed
                {
                PORTD &= ~(1<<PD2); // Make sure pass led is off                
                PORTD |= (1<<PD5);  // Turn on fail alarm           
                }
            //delay_ms(500);
            PORTB |= (1<<PB1); // Make PB1 high
        }

        if (PIND & (1<<PD6)==0)
        {
        start_test = 1;    // allow testing
        }
        if (PIND & (1<<PD7)==0)
        {
        start_test = 0;     // stop testing
        PORTD &= ~(1<<PD2);
        PORTD &= ~(1<<PD5);
        }
    }

}

As soon as I turn on the power, the fail led comes on and there is now response seen from the start or stop test buttons. If I put a meter on the pins, I see the expected state change. What am I missing?

June 26, 2012
by live4the1
live4the1's Avatar

Ok, I changed

if ((PINC & (1<<PC1)) == 0)

to

if (PINC & ~(1<<PC1))

and the pass/fail seems to work like expected. Now the buttons don't seem to work. I don't want anything visible to happen until the start button is pushed and when the stop is pushed I want the test to stop but as it is now the program starts at power on and continues to loop regardless of button push. The code is now:

#define F_CPU 14745600
#include <stdio.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <inttypes.h>
#include "../libnerdkits/delay.h"
#include "../libnerdkits/uart.h"

int main(){

DDRB |= (1<<PB1); // WIRE 1 (OUTPUT)

DDRC &= ~(1<<PC1); // WIRE 1 (INPUT)
PORTC |= (1<<PC1); // TURN ON PULL UP RESISTOR

DDRD |= (1<<PD2); // PASS LED (OUTPUT)
DDRD |= (1<<PD5); // FAIL LED (OUTPUT)
DDRD &= ~(1<<PD6); // START TEST BUTTON (INPUT)
DDRD &= ~(1<<PD7); // STOP TEST BUTTON (INPUT)
PORTD |= (1<<PD6); // TURN ON PULL UP RESISTOR
PORTD |= (1<<PD7); // TURN ON PULL UP RESISTOR

uint8_t start_test = 0;

    while(1)
    {
        if (start_test);
        {
        PORTB |= (1<<PB1); // Make PB1 high
        delay_ms(100);
        PORTB &= ~(1<<PB1); // Make PB1 low
                if (PINC & ~(1<<PC1)) // Check to see if PC1 is low
                {
                PORTD |= (1<<PD2); // Turn on pass led
                }
                else // Failed
                {
                PORTD &= ~(1<<PD2); // Make sure pass led is off                
                PORTD |= (1<<PD5);  // Turn on fail alarm           
                }
            delay_ms(100);
            PORTB |= (1<<PB1); // Make PB1 high
        }

        if (PIND & ~(1<<PD6))
        {
        start_test = 1;    // allow testing
        }
        if (PIND & ~(1<<PD7))
        {
        start_test = 0;     // stop testing
        PORTD &= ~(1<<PD2);
        PORTD &= ~(1<<PD5);
        }
    }

}
June 26, 2012
by pcbolt
pcbolt's Avatar

OK I think I see the problem. In the code you listed two posts ago, you used this for the test statement:

if (PINC & (1<<PC1)==0)

I think you need an extra set of parenthesis, like this:

if ((PINC & (1<<PC1))==0)

The '~' (negation) operator won't do what you want if you use more than 1 pin on that port. Go through the code and change all your tests so each statement has 3 sets of parenthesis in them (lines 32,45,49 from 2 posts ago) and don't use the '~' in these cases.

If this works, you just need to add PC2 and PC3 the same way. You can test them all at once, but I think you mentioned earlier you wanted to know which wire went bad so test them one at a time by copying the PC1 test code and paste it inside the "if(start_test)" block (right after the PC1 test code would work). Just change PC1 to PC2 in the pasted code (and PB1 to PB2 as well).

Oh and another reason the start/stop pins won't work is because on line 28 you have :

if(start_test);

This will make your code execute no matter what the value of "start_test" is. Just get rid of the semicolon at the end.

June 27, 2012
by live4the1
live4the1's Avatar

pcbolt, now we're cooking! Now I want to make sure that the pass led will not come on after there is a intermittent failure. Right now, if I break the connection, my fail led comes on as it is suppose to but when I reconnect the connection, the pass led comes back on. What I would like to see is that at the event of a failure, the fail led comes on and the pass led will go off and stay off even if the connection is recovered. That way I can trace down broken wires or solder joints easily. This is not a big deal for just a few wires but if I expand this to more wires it could be very handy.

June 27, 2012
by live4the1
live4the1's Avatar

I added

start_test=0;

in the fail condition and that seems to have done the trick. Now to add more test circuits and see how that goes.

June 27, 2012
by pcbolt
pcbolt's Avatar

I would try using another flag variable to store if it is OK to light PD2. You can declare it on the same line as the "start_test" variable...

uint8_t start_test = 0, pd2_led_ok = 1;

Then change the line...

PORTD |= (1<<PD2); // Turn on pass led

To...

if (pd2_led_ok) PORTD |= (1<<PD2); // Turn on pass led

You'll have to set "pd2_led_ok" to 0 when it fails so just add code to the fail block...

PORTD &= ~(1<<PD2); // Make sure pass led is off
PORTD |= (1<<PD5);  // Turn on fail alarm 
pd2_led_ok = 0;

Now you will have to re-enable PD2 (i.e. set pd2_led_ok = 1) somewhere. I'm not sure what you have in mind here but you could enable it when you push the "start test" button. If so, just add it on to...

start_test = 1;    // allow testing
pd2_led_ok = 1;    // reset PD2 led
June 27, 2012
by live4the1
live4the1's Avatar

I have now added another circuit to be tested. But since I have added the second condition in the test if statements the test fails even when the wires are correctly connected. Do you see the problem?

while(1)
    {
        PORTB |= (1<<PB1); // Make PB1 high
        PORTB |= (1<<PB2); // MAKE PB2 HIGH

        if (run_test)
        {
        delay_ms(50);
        PORTB &= ~(1<<PB1); // Make PB1 low
        delay_ms(50);
            if (((PINC & (1<<PC1))==0) && ((PINC & (1<<PC2))==1)) // Check to see if PC1 is low and PC2 is high
                {
                PORTD |= (1<<PD2); // Turn on pass led
                }
                else // Failed
                {
                PORTD &= ~(1<<PD2); // Make sure pass led is off
                PORTD |= (1<<PD5);  // Turn on fail alarm
                run_test=0;
                }
        PORTB |= (1<<PB1); // Make PB1 high

        delay_ms(50);
        PORTB &= ~(1<<PB2); // Make PB2 low
        delay_ms(50);
            if (((PINC & (1<<PC2))==0) && ((PINC & (1<<PC1))==1)) // Check to see if PC2 is low and PC1 is high
                {
                PORTD |= (1<<PD3); // Turn on pass led
                }
                else // Failed
                {
                PORTD &= ~(1<<PD3); // Make sure pass led is off
                PORTD |= (1<<PD5);  // Turn on fail alarm
                run_test=0;
                }
        PORTB |= (1<<PB2); // Make PB2 high
        }

        if ((PIND & (1<<PD6))==0)
        {
        run_test = 1; // allow testing
        }
        if ((PIND & (1<<PD7))==0)
        {
        run_test = 0;   // stop testing
        PORTD &= ~(1<<PD2);
        PORTD &= ~(1<<PD3);
        PORTD &= ~(1<<PD5);
June 27, 2012
by pcbolt
pcbolt's Avatar

Ah yes...I do see the problem (took a while tho :-). It will take a bit of explaining. First, to fix the "if" statements change...

if (((PINC & (1<<PC1))==0) && ((PINC & (1<<PC2))==1))

To...

if (((PINC & (1<<PC1))==0) && (PINC & (1<<PC2)))  // remove =1 and a set of ()'s

The result of "PINC & (1<<PC2)" will equal 4 and when you ask if it equals 1 the program will say NO. The result of "PINC & (1<<PC1)" will equal 2. By not asking if it is equal to anything, you are telling it to return true if the result of the '&' calculation is anything EXCEPT zero.

June 27, 2012
by live4the1
live4the1's Avatar

Wow, I guess that makes since but I never would have figured that out. Thanks!!!

June 27, 2012
by pcbolt
pcbolt's Avatar

Glad to help. Can't wait to see the "if" tests when you add a third wire tester :p

This is a good "next step" project since it will firm up what you learn from the Nerdkits sample programs. If you expand to more and more wire tests, you might want to look into the code for the "trafficlight.c" project (download section). That code may be somewhat confusing because it is complicated but it does introduce the concept of "state machines". What that means in your wire tester project would be setting one of the output pins low then testing the "state" of the 3 input pins all at the same time and making decisions based on those two pieces of information,

Post a Reply

Please log in to post a reply.

Did you know that you can follow NerdKits on Facebook, YouTube, and Twitter? Learn more...