XLR Cable Pin Tester

Hi I am trying to make a general pin tester for a audio cable, XLR (3 pinned connector and have written some code to test the first pin only so far to try and make it work and my code only prints the first line of the if statement back.
Any help please!

int sxlrp = 22;    //Sending XLR +
int sxlrm = 24;    //Sending XLR -
int sxlrg = 26;    //Sending XLR GND
int sxlrc = 28;    //Sending XLR Casing

int rxlrp = 23;    //Return XLR +
int rxlrm = 25;    //Return XLR 
int rxlrg = 27;    //Return XLR GND
int rxlrc = 29;    //Sending XLR Casing

void setup() {
  Serial.begin(9600);
  
  pinMode(sxlrp, OUTPUT);
  pinMode(sxlrm, OUTPUT);
  pinMode(sxlrg, OUTPUT);

  pinMode(rxlrp, INPUT);
  pinMode(rxlrm, INPUT);
  pinMode(rxlrg, INPUT);
}

void loop() {
  digitalWrite(sxlrp, HIGH);

  int result = digitalRead(rxlrp);

  if(result = HIGH) {
    Serial.println("XLR Positive PASS");
  }else if (result = LOW){
    Serial.println("XLR Positive FAIL");
  }else {
    Serial.println("Error");
  }

  delay(1000);
}

Oops.

  if(result = HIGH) {
    Serial.println("XLR Positive PASS");
  }else if (result = LOW){
    Serial.println("XLR Positive FAIL");
  }else {
    Serial.println("Error");
  }

better and shorter because digital values only have two states

void loop() {
  digitalWrite(sxlrp, HIGH);

  int result = digitalRead(rxlrp);

  if(result) {
    Serial.println(F("XLR Positive PASS"));
  }else {
    Serial.println(F("XLR Positive FAIL"));
  }

  delay(1000);
}

Hi Whandall,

That works however takes a couple of repeats of the code to work if the circuit is broken, any ideas why?

Are you saying that it always indicates a pass, even when you are expecting a "fail"?

I think the problem is that once you have taken the input HIGH, then it stays in that condition, because you are leaving it floating. Subsequent readings will indicate the input being HIGH when you don't think it aught to be.

The solution is to fit pull down resistors to all your inputs, to ensure that the inputs really are low when they are not being pulled high.

An even easier solution with be to use the internal pull-ups on the inputs, and to invert your logic, i.e. take the output low to conduct the test.

Whandall's solution returns the correct results however when I break the circuit to test to see if it produces the FAIL response then it does produce the FAIL response however it takes a couple of loops of the code while still printing PASS before printing FAIL.

i.e.

XLR Positive PASS
XLR Positive PASS
XLR Positive PASS
XLR Positive PASS
**I Break Circuit
XLR Positive PASS
XLR Positive PASS
XLR Positive PASS
XLR Positive FAIL
XLR Positive FAIL
XLR Positive FAIL
**I Fix Circuit
XLR Positive PASS

I Hope that makes sense!

I think JohnLincoln answered you question already.

Please note that you main error was using '=' as a (tried) comparison.
It is an assignment, and has the boolean value of the assigned value.
But you should always use '==' if you want to compare something for equality.
I rarely compare boolean values, because the result of a comparison is a boolean value too.

Please be aware of my updated code below:

int sxlrp = 22;    //Sending XLR +
int sxlrm = 24;    //Sending XLR -
int sxlrg = 26;    //Sending XLR GND
int sxlrc = 28;    //Sending XLR Casing

int rxlrp = 23;    //Return XLR +
int rxlrm = 25;    //Return XLR 
int rxlrg = 27;    //Return XLR GND
int rxlrc = 29;    //Sending XLR Casing

int result1 = LOW;
int result2 = LOW;
int result3 = LOW;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  
  pinMode(sxlrp, OUTPUT);
  pinMode(sxlrm, OUTPUT);
  pinMode(sxlrg, OUTPUT);

  pinMode(rxlrp, INPUT);
  pinMode(rxlrm, INPUT);
  pinMode(rxlrg, INPUT);
}

void loop() {

  test();
  
}

void test() {
  digitalWrite(sxlrp, HIGH);

  result1 = digitalRead(rxlrp);

  if(result1) {
    Serial.println(F("XLR + PASS"));
  }else {
    Serial.println(F("XLR + FAIL"));
  }

  digitalWrite(sxlrp, LOW);

  delay(1500);

  digitalWrite(sxlrm, HIGH);

  result2 = digitalRead(rxlrm);

  if(result2) {
    Serial.println(F("XLR - PASS"));
  }else {
    Serial.println(F("XLR - FAIL"));
  }

  digitalWrite(sxlrm, LOW);

  delay(1500);

  digitalWrite(sxlrg, HIGH);

  result3 = digitalRead(rxlrg);

  if(result3) {
    Serial.println(F("XLR Gnd PASS"));
  }else {
    Serial.println(F("XLR Gnd FAIL"));
  }

  digitalWrite(sxlrg, LOW);

  delay(1500);

  Serial.println("");
}

And see attached my the breadboard schematic to represent what I have plugged in to represent an XLR. When I say break the circuit, I am just removing the negative wire to emulate a break in a cable.

How do you like a shorter form ? (which is by far better to change/fix/extend/understand IMHO)

const byte drivePlusPin = 22;
const byte driveMinusPin = 24;
const byte driveGNDPin = 26;
const byte driveCasingPin = 28;

const byte sensePlusPin = 23;
const byte senseMinusPin = 25;
const byte senseGNDPin = 27;
const byte senseCasingPin = 29;

const unsigned int testAllMillis = 1000;
unsigned long lastTest;

void setup()
{
  Serial.begin(115200);

  pinMode(drivePlusPin, OUTPUT);
  pinMode(driveMinusPin, OUTPUT);
  pinMode(driveGNDPin, OUTPUT);
  pinMode(driveCasingPin, OUTPUT);

  pinMode(sensePlusPin, INPUT_PULLUP);
  pinMode(senseMinusPin, INPUT_PULLUP);
  pinMode(senseGNDPin, INPUT_PULLUP);
  pinMode(senseCasingPin, INPUT_PULLUP);
}

void loop()
{
  unsigned long topLoop = millis();
  if (topLoop - lastTest >= testAllMillis) {
    lastTest = topLoop;
    oneTest('+', drivePlusPin, sensePlusPin);
    oneTest('-', driveMinusPin, senseMinusPin);
    oneTest('G', driveGNDPin, senseGNDPin);
    oneTest('C', driveCasingPin, senseCasingPin);
    Serial.println("");
  }
}

void oneTest(byte tag, byte outPin, byte inPin)
{
  digitalWrite(outPin, LOW); // sense is pulled high, so try to drive it low
  Serial.print(F("XLR "));
  Serial.write(tag);
  if (digitalRead(inPin)) { // if it stays high, there is no connection
    Serial.println(F(" FAIL"));
  } else { // was low as expected
    Serial.println(F(" PASS"));
  }
  digitalWrite(outPin, HIGH); // release pin
}

Whandall that is great, how would it be best to implement an LCD into as I would be unsure to work the same function Serial.print(F…

Below is the code you suggested with the LCD setup included.

#include <LiquidCrystal.h>
LiquidCrystal lcd(1, 2, 4, 5, 6, 7);

const byte drivePlusPin = 22;
const byte driveMinusPin = 24;
const byte driveGNDPin = 26;
const byte driveCasingPin = 28;

const byte sensePlusPin = 23;
const byte senseMinusPin = 25;
const byte senseGNDPin = 27;
const byte senseCasingPin = 29;

const unsigned int testAllMillis = 1000;
unsigned long lastTest;

const int button = 36;

void setup()
{
  lcd.begin(16,2);
  Serial.begin(9600);

  pinMode(drivePlusPin, OUTPUT);
  pinMode(driveMinusPin, OUTPUT);
  pinMode(driveGNDPin, OUTPUT);
  pinMode(driveCasingPin, OUTPUT);

  pinMode(sensePlusPin, INPUT_PULLUP);
  pinMode(senseMinusPin, INPUT_PULLUP);
  pinMode(senseGNDPin, INPUT_PULLUP);
  pinMode(senseCasingPin, INPUT_PULLUP);
}

void loop()
{
  if (digitalRead(button)){
  unsigned long topLoop = millis();
  if (topLoop - lastTest >= testAllMillis) {
    lastTest = topLoop;
    oneTest('+', drivePlusPin, sensePlusPin);
    oneTest('-', driveMinusPin, senseMinusPin);
    oneTest('G', driveGNDPin, senseGNDPin);
    oneTest('C', driveCasingPin, senseCasingPin);
    Serial.println("");
  }
  }
}

void oneTest(byte tag, byte outPin, byte inPin)
{
  digitalWrite(outPin, LOW); // sense is pulled high, so try to drive it low
  Serial.print(F("XLR "));
  Serial.write(tag);
  if (digitalRead(inPin)) { // if it stays high, there is no connection
    Serial.println(F(" FAIL"));
  } else { // was low as expected
    Serial.println(F(" PASS"));
  }
  digitalWrite(outPin, HIGH); // release pin
}

It could work this way (I tested it on my I2C display), maybe you have to change somthing for yours.

#include <LiquidCrystal.h>
LiquidCrystal lcd(1, 2, 4, 5, 6, 7);

const byte drivePlusPin = 22;
const byte driveMinusPin = 24;
const byte driveGNDPin = 26;
const byte driveCasingPin = 28;

const byte sensePlusPin = 23;
const byte senseMinusPin = 25;
const byte senseGNDPin = 27;
const byte senseCasingPin = 29;

const unsigned int testAllMillis = 1000;
unsigned long lastTest;

const int button = 36;

void setup()
{
  lcd.begin(16,2);
  Serial.begin(9600);
  lcd.backlight();
  lcd.print(F("XLR Test"));
  Serial.begin(115200);

  pinMode(drivePlusPin, OUTPUT);
  pinMode(driveMinusPin, OUTPUT);
  pinMode(driveGNDPin, OUTPUT);
  pinMode(driveCasingPin, OUTPUT);

  pinMode(sensePlusPin, INPUT_PULLUP);
  pinMode(senseMinusPin, INPUT_PULLUP);
  pinMode(senseGNDPin, INPUT_PULLUP);
  pinMode(senseCasingPin, INPUT_PULLUP);
  delay(1000);
  lcd.clear();
}

void loop()
{
  unsigned long topLoop = millis();
  if (topLoop - lastTest >= testAllMillis) {
    lastTest = topLoop;
    oneTest(PSTR("POS"), drivePlusPin, sensePlusPin, 0, 0);
    oneTest(PSTR("NEG"), driveMinusPin, senseMinusPin, 0, 8);
    oneTest(PSTR("GND"), driveGNDPin, senseGNDPin, 1, 0);
    oneTest(PSTR("CAS"), driveCasingPin, senseCasingPin, 1, 8);
    Serial.println("");
  }
}

void oneTest(const char* name, byte outPin, byte inPin, byte row, byte col)
{
  digitalWrite(outPin, LOW); // sense is pulled high, so try to drive it low
  Serial.print(F("XLR "));
  Serial.print((__FlashStringHelper*)name);
  lcd.setCursor(col, row);
  lcd.print((__FlashStringHelper*)name);
  lcd.setCursor(col + 4, row);
  if (digitalRead(inPin)) { // if it stays high, there is no connection
    Serial.println(F(" FAIL"));
    lcd.print(F("err"));
  } else {
    Serial.println(F(" PASS"));
    lcd.print(F("ok "));
  }
  digitalWrite(outPin, HIGH); // release pin
}

Having some strange results on the LCD (Mainly LCD not clearing properly and unwanted characters being printed), have tried multiple approaches to resolve it however can't quite find something to work.
Any suggestions? Also I have inserted an if statement in the loop to make it run by a button

if (digitalRead(button)){
  lcd.clear();
  unsigned long topLoop = millis();
  if (topLoop - lastTest >= testAllMillis) {
    lastTest = topLoop;
    oneTest(PSTR("POS"), drivePlusPin, sensePlusPin, 0, 0);
    oneTest(PSTR("NEG"), driveMinusPin, senseMinusPin, 8, 0);
    oneTest(PSTR("GND"), driveGNDPin, senseGNDPin, 0, 1);
    oneTest(PSTR("CAS"), driveCasingPin, senseCasingPin, 8, 1);
    Serial.println("");
  }
}

Only performing the test after a button press is not very ergonomic IMHO.

If you want to use timings via millis, you should leaveunsigned long topLoop = millis();outside any if. Its update should be independent from any button presses or the like. Whith this simple code there is no real difference (because the if is the only action in your loop), but if you expand the functionality there will be differences

My posted code works, clears the display as neccessary and does not display any strange characters.

Your code does not, but you have choosen to hide it.

l_clarke:
Any suggestions?

Always post all of the code.

So I have used your code which is why i didn’t post it last time as I hadn’t changed anything apart from the code I added to the post.
Now I have put the

unsigned long topLoop = millis();

outside the if statement and created an int for the reading of the button press
I am still getting weird results from the display when pressing the button (and if the button is removed and just the original code is run).

PFB

#include <LiquidCrystal.h>
LiquidCrystal lcd(1, 2, 4, 5, 6, 7);

const byte drivePlusPin = 22;
const byte driveMinusPin = 24;
const byte driveGNDPin = 26;
const byte driveCasingPin = 28;

const byte sensePlusPin = 23;
const byte senseMinusPin = 25;
const byte senseGNDPin = 27;
const byte senseCasingPin = 29;

const unsigned int testAllMillis = 1000;
unsigned long lastTest;

const int button = 36;

void setup()
{
  lcd.begin(16,2);
  Serial.begin(9600);
  lcd.print(F("XLR Test"));
  Serial.begin(115200);

  pinMode(drivePlusPin, OUTPUT);
  pinMode(driveMinusPin, OUTPUT);
  pinMode(driveGNDPin, OUTPUT);
  pinMode(driveCasingPin, OUTPUT);

  pinMode(sensePlusPin, INPUT_PULLUP);
  pinMode(senseMinusPin, INPUT_PULLUP);
  pinMode(senseGNDPin, INPUT_PULLUP);
  pinMode(senseCasingPin, INPUT_PULLUP);
  delay(1000);
  lcd.clear();
}

void loop()
{
  unsigned long topLoop = millis();
  int buttonpress = digitalRead(button);
  if (buttonpress){
  if (topLoop - lastTest >= testAllMillis) {
    lastTest = topLoop;
    oneTest(PSTR("POS"), drivePlusPin, sensePlusPin, 0, 0);
    oneTest(PSTR("NEG"), driveMinusPin, senseMinusPin, 0, 8);
    oneTest(PSTR("GND"), driveGNDPin, senseGNDPin, 1, 0);
    oneTest(PSTR("CAS"), driveCasingPin, senseCasingPin, 1, 8);
    Serial.println("");
  }
  }
}

void oneTest(const char* name, byte outPin, byte inPin, byte row, byte col)
{
  digitalWrite(outPin, LOW); // sense is pulled high, so try to drive it low
  Serial.print(F("XLR "));
  Serial.print((__FlashStringHelper*)name);
  lcd.setCursor(col, row);
  lcd.print((__FlashStringHelper*)name);
  lcd.setCursor(col + 4, row);
  if (digitalRead(inPin)) { // if it stays high, there is no connection
    Serial.println(F(" FAIL"));
    lcd.print(F("err"));
  } else {
    Serial.println(F(" PASS"));
    lcd.print(F("ok "));
  }
  digitalWrite(outPin, HIGH); // release pin
}

I don’t know how your button is wired, I enable INPUT_PULLUP and close the button to GND,
resulting in this code, that I can not bring to display anything unexpected (on my I2C variant, different pins, on a Nano).

#include <LiquidCrystal.h>
LiquidCrystal lcd(1, 2, 4, 5, 6, 7);

const byte drivePlusPin = 22;
const byte driveMinusPin = 24;
const byte driveGNDPin = 26;
const byte driveCasingPin = 28;

const byte sensePlusPin = 23;
const byte senseMinusPin = 25;
const byte senseGNDPin = 27;
const byte senseCasingPin = 29;

const unsigned int testAllMillis = 1000;
unsigned long lastTest;

const byte buttonPin = 36;

void setup()
{
  lcd.begin(16, 2);
  lcd.print(F("XLR Test"));
  Serial.begin(115200);

  pinMode(drivePlusPin, OUTPUT);
  pinMode(driveMinusPin, OUTPUT);
  pinMode(driveGNDPin, OUTPUT);
  pinMode(driveCasingPin, OUTPUT);

  pinMode(sensePlusPin, INPUT_PULLUP);
  pinMode(senseMinusPin, INPUT_PULLUP);
  pinMode(senseGNDPin, INPUT_PULLUP);
  pinMode(senseCasingPin, INPUT_PULLUP);

  pinMode(buttonPin, INPUT_PULLUP);

  delay(1000);
  lcd.clear();
}

void loop()
{
  unsigned long topLoop = millis();

  bool buttonDown = !digitalRead(buttonPin);
  if (buttonDown) {
    if (topLoop - lastTest >= testAllMillis) {
      lastTest = topLoop;
      oneTest(PSTR("POS"), drivePlusPin, sensePlusPin, 0, 0);
      oneTest(PSTR("NEG"), driveMinusPin, senseMinusPin, 0, 8);
      oneTest(PSTR("GND"), driveGNDPin, senseGNDPin, 1, 0);
      oneTest(PSTR("CAS"), driveCasingPin, senseCasingPin, 1, 8);
      Serial.println("");
    }
  }
}

void oneTest(const char* name, byte outPin, byte inPin, byte row, byte col)
{
  digitalWrite(outPin, LOW); // sense is pulled high, so try to drive it low
  Serial.print(F("XLR "));
  Serial.print((__FlashStringHelper*)name);
  lcd.setCursor(col, row);
  lcd.print((__FlashStringHelper*)name);
  lcd.setCursor(col + 4, row);
  if (digitalRead(inPin)) { // if it stays high, there is no connection
    Serial.println(F(" FAIL"));
    lcd.print(F("err"));
  } else {
    Serial.println(F(" PASS"));
    lcd.print(F("ok "));
  }
  digitalWrite(outPin, HIGH); // release pin
}

A debouncing of the button is not neccessary, because the triggered action can only be started again after a second.
Normally you would have to use debouncing code and more key-was-pressed vs key-is-pressed.
For the debouncing you can use a library, I like Bounce2.

Updated the code to use the same that you have in the previous post, the only thing I can think is that I have wired the lcd in 4 bit mode, do you think this would make a difference, I didn’t think it would and always print fine to it in 4 bit mode.

Other programs using the LCD work fine with the wiring I currently have. Below is a diagram of the wiring for the whole project. As before the resistors are just representing an XLR cable as I haven’t yet put together the components to actually test the cable yet!

I think you should not use pin 1. It is used by Serial.

Great, that works by moving the LCD over to pins 2 onwards, it was the serial causing an issue.

Below is the code you sent a few posts back, can you explain in the oneTest how setting the output (drive) to low makes the test functional, I am probably missing something however it seems counterintuitive.

I understand that if the sense is set to high and receives a low signal it will change but I don’t see where this would happen.

#include <LiquidCrystal.h>
LiquidCrystal lcd(1, 2, 4, 5, 6, 7);

const byte drivePlusPin = 22;
const byte driveMinusPin = 24;
const byte driveGNDPin = 26;
const byte driveCasingPin = 28;

const byte sensePlusPin = 23;
const byte senseMinusPin = 25;
const byte senseGNDPin = 27;
const byte senseCasingPin = 29;

const unsigned int testAllMillis = 1000;
unsigned long lastTest;

const byte buttonPin = 36;

void setup()
{
  lcd.begin(16, 2);
  lcd.print(F("XLR Test"));
  Serial.begin(115200);

  pinMode(drivePlusPin, OUTPUT);
  pinMode(driveMinusPin, OUTPUT);
  pinMode(driveGNDPin, OUTPUT);
  pinMode(driveCasingPin, OUTPUT);

  pinMode(sensePlusPin, INPUT_PULLUP);
  pinMode(senseMinusPin, INPUT_PULLUP);
  pinMode(senseGNDPin, INPUT_PULLUP);
  pinMode(senseCasingPin, INPUT_PULLUP);

  pinMode(buttonPin, INPUT_PULLUP);

  delay(1000);
  lcd.clear();
}

void loop()
{
  unsigned long topLoop = millis();

  bool buttonDown = !digitalRead(buttonPin);
  if (buttonDown) {
    if (topLoop - lastTest >= testAllMillis) {
      lastTest = topLoop;
      oneTest(PSTR("POS"), drivePlusPin, sensePlusPin, 0, 0);
      oneTest(PSTR("NEG"), driveMinusPin, senseMinusPin, 0, 8);
      oneTest(PSTR("GND"), driveGNDPin, senseGNDPin, 1, 0);
      oneTest(PSTR("CAS"), driveCasingPin, senseCasingPin, 1, 8);
      Serial.println("");
    }
  }
}

void oneTest(const char* name, byte outPin, byte inPin, byte row, byte col)
{
  digitalWrite(outPin, LOW); // sense is pulled high, so try to drive it low
  Serial.print(F("XLR "));
  Serial.print((__FlashStringHelper*)name);
  lcd.setCursor(col, row);
  lcd.print((__FlashStringHelper*)name);
  lcd.setCursor(col + 4, row);
  if (digitalRead(inPin)) { // if it stays high, there is no connection
    Serial.println(F(" FAIL"));
    lcd.print(F("err"));
  } else {
    Serial.println(F(" PASS"));
    lcd.print(F("ok "));
  }
  digitalWrite(outPin, HIGH); // release pin
}

I used the internal pullups for the sensing side, so pulling the line low test for a connection.

Thank you for a great solution and much needed help!

I'm quite a newbie. Curious how to add code that would illuminate 3 led's that correspond with the PASS result (and in turn not illuminate with a FAIL result).

I'm sure this is very elementary. Thanks in advance for any guidance.