My Code's Inefficiency

Hi there,

I'm brand new to the forum, but have been using Arduinos for a couple of years and typically can get what I need done wih enough trial and error/research. I was hoping those more experienced could have a look over my code and see how I could (no doubt) improve it to be more efficient.

It currently functions as I would like, but despite my reseach into understanding exactly how some of the functions operate (!, &&, ||, ==, and boolean), I have been unable to remove any of the else if statements ("Neutral") without breaking the functionality. It seems to me I should be able to write this code so that the else if is the ongoing state, and only varies from that when a magnet is present at one of the hall effect sensors - otherwise it seems bloated.

Aside from this, the serial monitor output for gears one-three gives me a single line/instance, however gears 4, 5 & reverse gives me endless lines of output until the magnet is removed. Doesn't affect the functionality as such, but certainly seems resource intensive.

Gracious for any help offered, thankyou.


// Arduino Nano-based manual gear shifter detector & display using the TM1637 7-Segment LED module.
// 3x A3144 Hall Effect Sensors are connected via pins 2, 3 & 12, and when a magnet/s is present, 
// will display gear One (pin 2), Gear Two (pin 3), Gear Three (pin 12), Gear Four (Pins 2 & 12), 
// Gear Five (Pins 3 & 12), and Reverse (pins 2 & 3) - otherwise Neutral is displayed.

#include Arduino.h
#include TM1637Display.h

const int CLK = 5;                                 // Set the CLK pin connection to the display
const int DIO = 4;                                 // Set the DIO pin connection to the display
const uint8_t blank[] = {0x00, 0x00, 0x00, 0x00};  // Declares the value of "blank"
const uint8_t data[] = {0xff, 0xff, 0xff, 0xff};   // Declares "data" as all segments on
const uint8_t n[] = {                              // Required segments to display the character "n"
  SEG_C | SEG_E | SEG_G
};
const uint8_t r[] = {
  SEG_E | SEG_G
};                                    // Required segments to display the character "r"

TM1637Display display(CLK, DIO);                 //set up the 4-Digit Display.

int TM1637Display(CLK, DIO);
int sensorPin2 = 2;
int sensorPin3 = 3;
int sensorPin12 = 12;
int ledPin7 = 7;
int ledPin8 = 8;
int ledPin9 = 9;
int counter = 0;
boolean sensorState2 = true;
boolean sensorState3 = true;
boolean sensorState12 = true;

void setup()
{
  Serial.begin(9600);                              // Setup serial monitor
  pinMode(sensorPin2, INPUT);
  pinMode(sensorPin3, INPUT);
  pinMode(sensorPin12, INPUT);
  pinMode(ledPin7, OUTPUT);
  pinMode(ledPin8, OUTPUT);
  pinMode(ledPin9, OUTPUT);
  display.clear();
  display.setBrightness(7);                        // Set the diplay to maximum brightness
  display.setSegments(blank);                      // Clear display

}

void loop()
{
  //display.setBrightness(7);
  //display.setSegments(blank);
  
  // Gear One
  if (magnetPresent(sensorPin2) && !sensorState2)
  {
    sensorState2 = true;
    printMessage("Gear One (Sensor Pin 2, Led Pin 7)");
    digitalWrite(ledPin7, HIGH);
    digitalWrite(ledPin8, LOW);
    digitalWrite(ledPin9, LOW);
    display.showNumberDec(1, false, 4);
  }
  
  // Neutral
  else if (!magnetPresent(sensorPin2) && sensorState2)
  {
    sensorState2 = false;
    sensorState3 = false;
    sensorState12 = false;
    printMessage("Neutral");
    digitalWrite(ledPin7, LOW);
    digitalWrite(ledPin8, LOW);
    digitalWrite(ledPin9, LOW);
    display.clear();
    display.setSegments(n, 1, 3);
  }
  
  // Gear Two
  if (magnetPresent(sensorPin3) && !sensorState3)
  {
    sensorState3 = true;
    printMessage("Gear Two (Sensor Pin 3, Led Pin 8)");
    digitalWrite(ledPin7, LOW);
    digitalWrite(ledPin8, HIGH);
    digitalWrite(ledPin9, LOW);
    display.showNumberDec(2, false, 4);
  }
  
  // Neutral
  else if (!magnetPresent(sensorPin3) && sensorState3)
  {
    sensorState2 = false;
    sensorState3 = false;
    sensorState12 = false;
    printMessage("Neutral");
    digitalWrite(ledPin7, LOW);
    digitalWrite(ledPin8, LOW);
    digitalWrite(ledPin9, LOW);
    display.clear();
    display.setSegments(n, 1, 3);
  }
  
  // Gear Three
  if (magnetPresent(sensorPin12) && !sensorState12)
  {
    sensorState12 = true;
    printMessage("Gear Three (Sensor Pin 12, Led Pin 9)");
    digitalWrite(ledPin7, LOW);
    digitalWrite(ledPin8, LOW);
    digitalWrite(ledPin9, HIGH);
    display.showNumberDec(3, false, 4);
  }
  
  // Neutral
  else if (!magnetPresent(sensorPin12) && sensorState12)
  {
    sensorState2 = false;
    sensorState3 = false;
    sensorState12 = false;
    printMessage("Neutral");
    digitalWrite(ledPin7, LOW);
    digitalWrite(ledPin8, LOW);
    digitalWrite(ledPin9, LOW);
    display.clear();
    display.setSegments(n, 1, 3);
  }

  // Gear Four
  if ((magnetPresent(sensorPin2) && sensorState2) && (magnetPresent(sensorPin12) && sensorState12) || (magnetPresent(sensorPin12) && sensorState12) && (magnetPresent(sensorPin2) && sensorState2))
  {
    sensorState2 = true;
    sensorState12 = true;
    printMessage("Gear Four (Sensor Pin 2 & 12, Led Pin 7 & 9)");
    digitalWrite(ledPin7, HIGH);
    digitalWrite(ledPin8, LOW);
    digitalWrite(ledPin9, HIGH);
    display.showNumberDec(4, false, 4);
  }
  
  // Neutral
  else if ((!magnetPresent(sensorPin2) && sensorState2) && (!magnetPresent(sensorPin12) && sensorState12))
  {
    sensorState2 = false;
    sensorState3 = false;
    sensorState12 = false;
    printMessage("Neutral");
    digitalWrite(ledPin7, LOW);
    digitalWrite(ledPin8, LOW);
    digitalWrite(ledPin9, LOW);
    display.clear();
    display.setSegments(n, 1, 3);
  }

  // Gear Five
  if ((magnetPresent(sensorPin3) && sensorState3) && (magnetPresent(sensorPin12) && sensorState12) || (magnetPresent(sensorPin12) && sensorState12) && (magnetPresent(sensorPin3) && sensorState3))
  {
    sensorState3 = true;
    sensorState12 = true;
    printMessage("Gear Five (Sensor Pin 3 & 12, Led Pin 8 & 9)");
    digitalWrite(ledPin7, LOW);
    digitalWrite(ledPin8, HIGH);
    digitalWrite(ledPin9, HIGH);
    display.showNumberDec(5, false, 4);
  }

  // Neutral
  else if ((!magnetPresent(sensorPin3) && sensorState3) && (!magnetPresent(sensorPin12) && sensorState12))
  {
    sensorState2 = false;
    sensorState3 = false;
    sensorState12 = false;
    printMessage("Neutral");
    digitalWrite(ledPin7, LOW);
    digitalWrite(ledPin8, LOW);
    digitalWrite(ledPin9, LOW);
    display.clear();
    display.setSegments(n, 1, 3);
  }
  
  // Gear Reverse
  if ((magnetPresent(sensorPin2) && sensorState2) && (magnetPresent(sensorPin3) && sensorState3) || (magnetPresent(sensorPin3) && sensorState3) && (magnetPresent(sensorPin2) && sensorState2))
  {
    sensorState2 = true;
    sensorState3 = true;
    printMessage("Gear Reverse (Sensor Pin 2 & 3, Led Pin 7 & 8)");
    digitalWrite(ledPin7, HIGH);
    digitalWrite(ledPin8, HIGH);
    digitalWrite(ledPin9, LOW);
    display.setSegments(r, 1, 3);
  }
  
  // Neutral
  else if ((!magnetPresent(sensorPin2) && sensorState2) && (!magnetPresent(sensorPin3) && sensorState3))
  {
    sensorState2 = false;
    sensorState3 = false;
    sensorState12 = false;
    printMessage("Neutral");
    digitalWrite(ledPin7, LOW);
    digitalWrite(ledPin8, LOW);
    digitalWrite(ledPin9, LOW);
    display.clear();
    display.setSegments(n, 1, 3);
  }

}

void printMessage(String message) {
  counter++;
  Serial.print(counter);
  Serial.print(" ");
  Serial.println(message);
  //delay(200);
}

boolean magnetPresent(int pin) {
  return digitalRead(pin) == LOW;
}

Could be done a bit simpler, take a look here for ideas:

You could get rid of the Booleans (Sensorstates) completely, from the looks of things they are unnecessary.

EG.

//first gear 
if (magnetPresent(sensorPin2)==true && magnetPresent(sensorPin3)==false && magnetPresent(sensorPin12)==false
)
  {

    digitalWrite(ledPin7, HIGH);
    digitalWrite(ledPin8, LOW);
    digitalWrite(ledPin9, LOW);
}

Thanks a lot mickymik, appreciate your response. Good to see another fellow gear head making fun car projects! Had a quick look over your project, very nice. :racing_car:

I've re-jigged my code with your suggestions for the full gearset and it works perfectly, with the exception of the serial monitor getting absolutely blasted with output. I guess the sensorState variable had the purpose of awaiting change, as opposed to constantly reading the pin?

(please bear in mind this code is a work in progress, so some areas are commented out)


// Arduino Nano-based manual gear shifter detector & display using the TM1637 7-Segment LED module.
// 3x A3144 Hall Effect Sensors are connected via pins 2, 3 & 12, and when a magnet/s is present, 
// will display gear One (pin 2), Gear Two (pin 3), Gear Three (pin 12), Gear Four (Pins 2 & 12), 
// Gear Five (Pins 3 & 12), and Reverse (pins 2 & 3) - otherwise Neutral is displayed.

#include Arduino.h
#include TM1637Display.h

const int CLK = 5;                                 // Set the CLK pin connection to the display
const int DIO = 4;                                 // Set the DIO pin connection to the display
const uint8_t blank[] = {0x00, 0x00, 0x00, 0x00};  // Declares the value of "blank"
const uint8_t data[] = {0xff, 0xff, 0xff, 0xff};   // Declares "data" as all segments on
const uint8_t n[] = {                              // Required segments to display the character "n"
  SEG_C | SEG_E | SEG_G
};
const uint8_t r[] = {
  SEG_E | SEG_G
};                                    // Required segments to display the character "r"

TM1637Display display(CLK, DIO);                 //set up the 4-Digit Display.

int TM1637Display(CLK, DIO);
int sensorPin2 = 2;
int sensorPin3 = 3;
int sensorPin12 = 12;
int ledPin7 = 7;
int ledPin8 = 8;
int ledPin9 = 9;
int counter = 0;
boolean magnetPresent(int pin);
//boolean sensorState2 = true;
//boolean sensorState3 = true;
//boolean sensorState12 = true;

void setup()
{
  Serial.begin(9600);                              // Setup serial monitor
  pinMode(sensorPin2, INPUT);
  pinMode(sensorPin3, INPUT);
  pinMode(sensorPin12, INPUT);
  pinMode(ledPin7, OUTPUT);
  pinMode(ledPin8, OUTPUT);
  pinMode(ledPin9, OUTPUT);
  display.clear();
  display.setBrightness(7);                        // Set the diplay to maximum brightness
  display.setSegments(blank);                      // Clear display

}

void loop()
{
  //display.setBrightness(7);
  //display.setSegments(blank);
  
  // Gear One
if (magnetPresent(sensorPin2)==true && magnetPresent(sensorPin3)==false && magnetPresent(sensorPin12)==false)
  {
    Serial.print("Gear One (2)");
    digitalWrite(ledPin7, HIGH);
    digitalWrite(ledPin8, LOW);
    digitalWrite(ledPin9, LOW);
    display.showNumberDec(1, false, 4);
  }
   // Gear Two
if (magnetPresent(sensorPin2)==false && magnetPresent(sensorPin3)==true && magnetPresent(sensorPin12)==false)
  {
    Serial.print("Gear Two (3)");
    digitalWrite(ledPin7, LOW);
    digitalWrite(ledPin8, HIGH);
    digitalWrite(ledPin9, LOW);
    display.showNumberDec(2, false, 4);
  }
  // Gear Three
if (magnetPresent(sensorPin2)==false && magnetPresent(sensorPin3)==false && magnetPresent(sensorPin12)==true)
  {
    Serial.print("Gear Three (12)");
    digitalWrite(ledPin7, LOW);
    digitalWrite(ledPin8, LOW);
    digitalWrite(ledPin9, HIGH);
    display.showNumberDec(3, false, 4);
  }
  // Gear Four
if (magnetPresent(sensorPin2)==true && magnetPresent(sensorPin3)==true && magnetPresent(sensorPin12)==false)
  {
    Serial.print("Gear Four (2 & 3)");
    digitalWrite(ledPin7, HIGH);
    digitalWrite(ledPin8, HIGH);
    digitalWrite(ledPin9, LOW);
    display.showNumberDec(4, false, 4);
  }
   // Gear Five
if (magnetPresent(sensorPin2)==false && magnetPresent(sensorPin3)==true && magnetPresent(sensorPin12)==true)
  {
    Serial.print("Gear Five (3 & 12");
    digitalWrite(ledPin7, LOW);
    digitalWrite(ledPin8, HIGH);
    digitalWrite(ledPin9, HIGH);
    display.showNumberDec(5, false, 4);
  }
  // Gear Reverse
if (magnetPresent(sensorPin2)==true && magnetPresent(sensorPin3)==false && magnetPresent(sensorPin12)==true)
  {
    Serial.print("Gear Reverse (2 & 12");
    digitalWrite(ledPin7, HIGH);
    digitalWrite(ledPin8, LOW);
    digitalWrite(ledPin9, HIGH);
    display.setSegments(r, 1, 3);
  }
  // Neutral
  else if (magnetPresent(sensorPin2)==false && magnetPresent(sensorPin3)==false && magnetPresent(sensorPin12)==false)
{
    Serial.print("Neutral");
    digitalWrite(ledPin7, LOW);
    digitalWrite(ledPin8, LOW);
    digitalWrite(ledPin9, LOW);
    display.setSegments(n, 1, 3);
  }
}

//void printMessage(String message) {
  //counter++;
  //Serial.print(counter);
  //Serial.print(" ");
  //Serial.println(message);
  //delay(200);
//}

boolean magnetPresent(int pin) {
  return digitalRead(pin) == LOW;
}
1 Like

This is the problem with running everything in the loop. Well it’s not actually a problem as such, as your project will work fine. But you could take it a step further and build a functions, and call the function on a gear change, that way you are not sending info to the display and to the serial monitor on every loop cycle.

Another tip, instead of writing if if if, you should write if, else if, else. Or you can look at using a case; break; chain.

it seems that for each sensor you have a sensorState which is presumed to be used to inhibit the repeated action of an if after the action has been taken. this doesn't appear to work because i see repeated prints whenever more than 1 sensor is active.

consider the following which handles the inputs and LED outputs as sets of bits and a table describing parameters for each gear state (assume you can add to dispPr() to display want you want on your 7-segment displays

// Arduino Nano-based manual gear shifter detector & display using the TM1637 7-Segment LED module.
// 3x A3144 Hall Effect Sensors are connected via pins 2, 3 & 12, and when a magnet/s is present,
// will display gear One (pin 2), Gear Two (pin 3), Gear Three (pin 12), Gear Four (Pins 2 & 12),
// Gear Five (Pins 3 & 12), and Reverse (pins 2 & 3) - otherwise Neutral is displayed.


#undef MyHW
#ifdef MyHW
#include "LiquidCrystal.h"

enum { Off = HIGH, On = LOW };

enum { SEG_A, SEG_B, SEG_C, SEG_D, SEG_E, SEG_F, SEG_G };

struct TM1637Display {
    TM1637Display (int clk, int dio)  {};

    void clear ()               {};
    void setBrightness (int a)  {};
    void setSegments (const uint8_t *a)  {};
    void setSegments (const uint8_t *a, int b, int c)  {};
    void showNumberDec (int a, int b, int c)  {};
};

byte sensorPin2  = A1;
byte sensorPin3  = A2;
byte sensorPin12 = A3;

byte ledPin7 = 10;
byte ledPin8 = 11;
byte ledPin9 = 12;

#else
#include Arduino.h
#include TM1637Display.h

enum { Off = HIGH, On = LOW };

byte sensorPin2 = 2;
byte sensorPin3 = 3;
byte sensorPin12 = 12;

byte ledPin7 = 7;
byte ledPin8 = 8;
byte ledPin9 = 9;
#endif


// -----------------------------------------------------------------------------
byte sensorPins [] = { sensorPin2, sensorPin3, sensorPin12 };
#define N_SENSOR    sizeof(sensorPins)
byte sensorState [N_SENSOR];

byte ledPins [] =  { ledPin7, ledPin8, ledPin9 };
#define N_LED    sizeof(ledPins)

const int CLK = 5;                                 // Set the CLK pin connection to the display
const int DIO = 4;                                 // Set the DIO pin connection to the display

const uint8_t blank[] = {0x00, 0x00, 0x00, 0x00};  // Declares the value of "blank"
const uint8_t data[] = {0xff, 0xff, 0xff, 0xff};   // Declares "data" as all segments on
const uint8_t n[] = {                              // Required segments to display the character "n"
    SEG_C | SEG_E | SEG_G
};
const uint8_t r[] = {
    SEG_E | SEG_G
};                                    // Required segments to display the character "r"

TM1637Display display (CLK, DIO);                 //set up the 4-Digit Display.
int TM1637Display (CLK, DIO);

int counter = 0;

// -----------------------------------------------------------------------------
struct Gearing_s {
    const char *  desc;
    byte          leds;
} gearing [] = {
    { "Neutral", 0 },
    { "Gear 1",  1 },
    { "Gear 2",  2 },
    { "Gear 3",  3 },

    { "Gear 4",  4 },
    { "Gear 5",  5 },
    { "Reverse", 7 },
    { "Unknown", 0 },
};

byte sensorInp = 0;

// -----------------------------------------------------------------------------
void
dispUpdt (void)
{
    char s [80];
    sprintf (s, "  %d  %s", sensorInp, gearing [sensorInp].desc);
    Serial.println (s);

    // set LEDs
    for (unsigned n = 0; n < N_SENSOR; n++)  {
        if (gearing [sensorInp].leds & (1 << n))
            digitalWrite (ledPins [n], On);
        else
            digitalWrite (ledPins [n], Off);
    }
}

// -----------------------------------------------------------------------------
void loop ()
{
    for (unsigned n = 0; n < N_SENSOR; n++)  {
        byte sensor = digitalRead (sensorPins [n]);

        if (sensorState [n] != sensor)  {
            sensorState [n] = sensor;

            if (On == sensor)
                sensorInp |= 1 << n;        // set bit
            else
                sensorInp &= ~(1 << n);     // clear bit

            dispUpdt ();
        }
    }
}

// -----------------------------------------------------------------------------
void setup ()
{
    Serial.begin (9600);                              // Setup serial monitor

    for (unsigned n = 0; n < N_SENSOR; n++)  {
        pinMode (sensorPins [n],  INPUT_PULLUP);
        sensorState [n] = digitalRead (sensorPins [n]);
    }

    for (unsigned n = 0; n < N_LED; n++)  {
        digitalWrite (ledPins [n], Off);
        pinMode      (ledPins [n], OUTPUT);
    }

    display.setBrightness (7);                        // Set the diplay to maximum brightness
    dispUpdt ();
}
1 Like

Hi gcjr, that code you suggested is actually very effective. Thankyou.

You are correct - because my code is effectively a crime against coding by sticking bits and pieces together, it looks horrid and is no doubt silly.

I made this change to your code, just so that the 3 leds I have on the breadboard as a visual indicator default to off in the "neutral" position.


 digitalWrite (ledPins [n], Off); //swapped this from On
        else
            digitalWrite (ledPins [n], On); //swapped this from Off

Now, to get a matching output on the TM1637, and adjust which sensor relates to which gear. Your code has given me a lot to learn from, thanks!

never heard of "crime against coding".

it's not uncommon to develop code without a clear idea of "what" it should do. prototypes often flesh out that understanding.

ive only heard of negative programming recently, but realize i've been doing it much of my career. Ken Thompson, inventor of UNIX said "One of my most productive days was throwing away 1,000 lines of code".

so hopefully what i've shown you gives you some ideas and you will improve on it.

i placed the Off/On enum under the if/else depending on HW because it depends on the HW. in my case Off/On are the same for both button inputs and LEDs. that is not necessarily the case and you may need LED_Off/On and Sensor_Off/On. regardless, using Off/On is clearer than HIGH/LOW.

Here is one way to code it. By putting the three sensor bits into a single number you get a single number that represents the current gear. It is then easy to act only on gear changes by comparing the current gear to the previous gear. The single number can also be used for a look-up table of gear names.

// Arduino Nano-based manual gear shifter detector & display using the TM1637 7-Segment LED module.
// 3x A3144 Hall Effect Sensors are connected via pins 2, 3 & 12, and when a magnet/s is present,
// will display gear One (pin 2), Gear Two (pin 3), Gear Three (pin 12), Gear Four (Pins 2 & 12),
// Gear Five (Pins 3 & 12), and Reverse (pins 2 & 3) - otherwise Neutral is displayed.

#include <TM1637Display.h>

const int CLK = 5;                                 // Set the CLK pin connection to the display
const int DIO = 4;                                 // Set the DIO pin connection to the display
const uint8_t blank[] = {0x00, 0x00, 0x00, 0x00};  // Declares the value of "blank"
const uint8_t data[] = {0xff, 0xff, 0xff, 0xff};   // Declares "data" as all segments on
const uint8_t n[] =                                // Required segments to display the character "n"
{
  SEG_C | SEG_E | SEG_G
};
const uint8_t r[] =
{
  SEG_E | SEG_G
};                                    // Required segments to display the character "r"

TM1637Display display(CLK, DIO);                 //set up the 4-Digit Display.

// int TM1637Display(CLK, DIO);
const int FirstGearPin = 2;
const int SecondGearPin = 3;
const int UpperGearsPin = 12;
const int ledPin7 = 7;
const int ledPin8 = 8;
const int ledPin9 = 9;

const char * GearNames[8] =
{
  "Neutral",     // 0
  "First Gear",  // 1 (FirstGearPin)
  "Second Gear", // 2 (SecondGearPin)
  "Reverse",     // 3 (FirstGearPin + SecondGearPin)
  "Third Gear",  // 4 (UpperGearsPin alone)
  "Fourth Gear", // 5 (FirstGearPin + UpperGearsPin)
  "Fifth Gear",  // 6 (SecondGearPin + UpperGearsPin)
  "INVALID"      // 7 (FirstGearPin + SecondGearPin + UpperGearsPin)
};

enum Gears {Neutral, First, Second, Reverse, Third, Fourth, Fifth};

int counter = 0;

void setup()
{
  Serial.begin(9600);                              // Setup serial monitor
  pinMode(FirstGearPin, INPUT);
  pinMode(SecondGearPin, INPUT);
  pinMode(UpperGearsPin, INPUT);
  pinMode(ledPin7, OUTPUT);
  pinMode(ledPin8, OUTPUT);
  pinMode(ledPin9, OUTPUT);

  display.clear();
  display.setBrightness(7);       // Set the diplay to maximum brightness
  display.setSegments(blank);     // Clear display
}

void DisplayGear(enum Gears gear)
{
  // Set the LEDs to match the sensor inputs.
  digitalWrite(ledPin7, gear & 1);
  digitalWrite(ledPin8, gear & 2);
  digitalWrite(ledPin9, gear & 4);

  printMessage(GearNames[gear]);

  display.clear();

  switch (gear)
  {
    case Neutral:
      display.setSegments(n, 1, 3);
      break;

    case First:
    case Second:
      display.showNumberDec(gear, false, 4);
      break;

    case Reverse:
      display.setSegments(r, 1, 3);
      break;

    case Third:
    case Fourth:
    case Fifth:
      display.showNumberDec(gear - 1, false, 4);
      break;

    default:
      break;
  }
}

void loop()
{
  static byte previousGear = 7;

  byte currentGear = (digitalRead(FirstGearPin) == LOW)
                     + ((digitalRead(SecondGearPin) == LOW) << 1)
                     + ((digitalRead(UpperGearsPin) == LOW) << 2);

  if (currentGear == previousGear)
    return;  // Nothing to do if the gear has not changed

  previousGear = currentGear;

  DisplayGear((enum Gears)currentGear);
}

void printMessage(String message)
{
  counter++;
  Serial.print(counter);
  Serial.print(" ");
  Serial.println(message);
  //delay(200);
}

First, I would like to commend you for this piece of code here:

boolean magnetPresent(int pin) {
  return digitalRead(pin) == LOW;
}

Instead of peppering your code with obtuse digitalRead()==LOW expressions, you have replaced them all with a single well-named function. This provides two distinct benefits.

First, it gives semantic meaning to the expression. What does LOW mean? You can't know unless you check the circuit to see what sensor you are using and how it is hooked up. magnetPresent on the other hand makes the situation obvious.

Second, it gives you a single point to define the logic of the magnetic switches, and if you change your magnetic sensors around you only need to change the logic at one point in your code.

I personally do this a different way, defining the values as constants like this, but your way isn't wrong. In fact, you should do the same thing for your LEDs as well.

const uint8_t HALL_MAGNET_PRESENT = LOW;
const uint8_t HALL_MAGNET_ABSENT = !HALL_MAGNET_PRESENT;
const uint8_t LED_ON = HIGH;
const uint8_t LED_OFF = !LED_ON;

if(digitalRead(magnet12)==HALL_MAGNET_PRESENT)
  ...

digitalWrite(led9, LED_ON);

That being said, let's talk about this now:

if ((magnetPresent(sensorPin2) && sensorState2) && (magnetPresent(sensorPin3) && sensorState3) || (magnetPresent(sensorPin3) && sensorState3) && (magnetPresent(sensorPin2) && sensorState2))

The boolean operator && (and ||) is commutative, meaning A && B = B && A. These if conditions are twice as long as they need to be. You don't need to do A && B || B && A.

Thanks Jiggy-Ninja, I appreciate the kind words. That piece of code is actually one that came with an example I was able to change significantly, to get the desired result with the very first example I posted. I encountered difficulties when I started trying to describe requiring two magnets present at sensors for a specific output, and I managed to get around by using && and ||.

The palendromic nature of those statements was just to cover if one sensor was activated before the other, but I can see that it's unnecessary.

I also tried the code suggested by johnwasser, which works perfectly.

I probably should have used the magnetPresent() function. That would be more readable.

  byte currentGear = (magnetPresent(FirstGearPin))
                     + (magnetPresent(SecondGearPin) << 1)
                     + (magnetPresent(UpperGearsPin) << 2);

Thanks again for the help guys.

I've since expanded the code significantly, and moved to NodeMCU ESP8266s. There is now a transmitter/client ESP with the array of magnets, which transmits the magnet state over wifi (UDP) to a receiver/server ESP, that displays that gear number (magnet state) on a MAX7219 8x8 LED matrix. This was working very well when the receiver/server had a TM1637 7 segment LED display (i2C), but upon changing to the MAX7219 (SPI), the display does not always update/receive the transmitted packet. s in, when moving a magnet onto or away from a sensor, sometimes (probably 50% of the time) the display does not update, and stays on the current number.

I've tried troubleshooting, but am a bit confused as to why the display has made such a difference (I assume it's the change to SPI). Any is greatly appreciated, as always. Below code is transmitter/client, followed by the receiver/server.

(the receiver/server code has a lot of TM1637 code commented out, as it's a WIP)

Transmitter/Client Side


// NodeMCU ESP8266-based manual gear shifter detector & display using the MAX7219 8x8 LED Matrix 
// module. 3x A3144 Hall Effect Sensors are connected via pins 2, 3 & 12, and when a magnet/s is 
// present, will display gear One (pin 2), Gear Two (pin 3), Gear Three (pin 12), Gear Four (Pins 
// 2 & 12), Gear Five (Pins 3 & 12), and Reverse (pins 2 & 3) - otherwise Neutral is displayed.

//Hall effect sensor coding is a modified example as provided by Arduino Forum member johnwasser.
//https://forum.arduino.cc/t/my-codes-inefficiency/851135/9

//UDP server/client scripts heavily modified based upon Siytek.com example.
//https://siytek.com/communication-between-two-esp8266/

// ***********Sensor/Transmitter/Client Side************

#include "TM1637Display.h"
#include "ESP8266WiFi.h"
#include "WiFiUdp.h"

#define WIFI_SSID "E36GearShifter"                 // Set WiFi credentials
#define WIFI_PASS "owwmyfrickenexpansiontank"

WiFiUDP UDP;                                       // UDP
IPAddress remote_IP(192,168,4,1);
#define UDP_PORT 4210

const int CLK = D1;                                // Set the CLK pin connection to the display
const int DIO = D2;                                // Set the DIO pin connection to the display
const uint8_t blank[] = {0x00, 0x00, 0x00, 0x00};  // Declares the value of "blank"
const uint8_t data[] = {0xff, 0xff, 0xff, 0xff};   // Declares "data" as all segments on
const uint8_t n[] =                                // Required segments to display the character "n"
{
  SEG_C | SEG_E | SEG_G
};
const uint8_t r[] =
{
  SEG_E | SEG_G
};                                    // Required segments to display the character "r"

TM1637Display display(CLK, DIO);                 //set up the 4-Digit Display.

// int TM1637Display(CLK, DIO);
const int FirstGearPin = D0;
const int SecondGearPin = D3;
const int UpperGearsPin = D4;
const int ledPinD5 = D5;
const int ledPinD6 = D6;
const int ledPinD7 = D7;

const char * GearNames[8] =
{
  "Neutral",     // 0
  "First Gear",  // 1 (FirstGearPin)
  "Second Gear", // 2 (SecondGearPin)
  "Reverse",     // 3 (FirstGearPin + SecondGearPin)
  "Third Gear",  // 4 (UpperGearsPin alone)
  "Fourth Gear", // 5 (FirstGearPin + UpperGearsPin)
  "Fifth Gear",  // 6 (SecondGearPin + UpperGearsPin)
  "INVALID"      // 7 (FirstGearPin + SecondGearPin + UpperGearsPin)
};

enum Gears {Neutral, First, Second, Reverse, Third, Fourth, Fifth};

int counter = 0;

void setup()
{
  Serial.begin(115200);                              // Setup serial monitor
  pinMode(FirstGearPin, INPUT);
  pinMode(SecondGearPin, INPUT);
  pinMode(UpperGearsPin, INPUT);
  pinMode(ledPinD5, OUTPUT);
  pinMode(ledPinD6, OUTPUT);
  pinMode(ledPinD7, OUTPUT);

  WiFi.begin(WIFI_SSID, WIFI_PASS);                // Begin WiFi
  WiFi.mode(WIFI_STA);
  
  //Serial.print("Connecting to ");                  // Connecting to WiFi...
  //Serial.print(WIFI_SSID);
  
  //while (WiFi.status() != WL_CONNECTED)            // Loop continuously while WiFi is not connected
  //{
   // delay(100);
    //Serial.print(".");
  //}
  
  //Serial.println();                                // Connected to WiFi
  //Serial.print("Connected! IP address: ");
  //Serial.println(WiFi.localIP());
 
  UDP.begin(UDP_PORT);                             // Begin UDP port
  Serial.print("Opening UDP port ");
  Serial.println(UDP_PORT);

  display.clear();                                 // Clear display
  display.setBrightness(7);                        // Set the diplay to maximum brightness
  display.setSegments(blank);                      // Clear display
}

void DisplayGear(enum Gears gear)
{
  // Set the LEDs to match the sensor inputs.
  digitalWrite(ledPinD5, gear & 1);
  digitalWrite(ledPinD6, gear & 2);
  digitalWrite(ledPinD7, gear & 4);

  printMessage(GearNames[gear]);

  display.clear();

  switch (gear)
  {
    case Neutral:
      display.setSegments(n, 1, 3);
      break;

    case First:
    case Second:
      display.showNumberDec(gear, false, 4);
      break;

    case Reverse:
      display.setSegments(r, 1, 3);
      break;

    case Third:
    case Fourth:
    case Fifth:
      display.showNumberDec(gear - 1, false, 4);
      break;

    default:
      break;
  }
}

void loop()
{
  static byte previousGear = 7;

  byte currentGear = (digitalRead(FirstGearPin) == LOW)
                     + ((digitalRead(SecondGearPin) == LOW) << 1)
                     + ((digitalRead(UpperGearsPin) == LOW) << 2);

  if (currentGear == previousGear)
    return;  // Nothing to do if the gear has not changed

  previousGear = currentGear;

  DisplayGear((enum Gears)currentGear);
  
  UDP.beginPacket(remote_IP, UDP_PORT);               // Send packet
  UDP.write(currentGear);
  UDP.endPacket();
  delay(100);
}

void printMessage(String message)
{
  counter++;
  Serial.print(counter);
  Serial.print(" ");
  Serial.println(message);
  //delay(200);
}

Receiver/Server Side


// NodeMCU ESP8266-based manual gear shifter detector & display using the MAX7219 8x8 LED Matrix 
// module. 3x A3144 Hall Effect Sensors are connected via pins 2, 3 & 12, and when a magnet/s is 
// present, will display gear One (pin 2), Gear Two (pin 3), Gear Three (pin 12), Gear Four (Pins 
// 2 & 12), Gear Five (Pins 3 & 12), and Reverse (pins 2 & 3) - otherwise Neutral is displayed.

//Hall effect sensor coding is a modified example as provided by Arduino Forum member johnwasser.
//https://forum.arduino.cc/t/my-codes-inefficiency/851135/9

//UDP server/client scripts heavily modified based upon Siytek.com example.
//https://siytek.com/communication-between-two-esp8266/

// ***********Receiver/Display/Server Side***********

#include "ESP8266WiFi.h"
#include "WiFiUdp.h"
#include "LedControl.h"
//#include "TM1637Display.h"

int DIN = D0;                                         //Set the DIN/?Didigtal IN pin
int CS = D1;                                          //Set the CS/?Chip Select pin
int CLK = D2;                                         //Set the CLK/Clock pin
LedControl lc=LedControl(DIN, CLK, CS, 0);

//Set gear numbers as bytes for the display
int One[8] ={B00000000,B00011000,B00111000,B00011000,B00011000,B00011000,B00111100,B00000000};
byte Two [8]={B00000000,B00011000,B00100100,B00000100,B00001000,B00010000,B00111100,B00000000};
byte Three [8]={B00000000,B00111000,B00000100,B00011000,B00001100,B00000100,B00111000,B00000000};
byte Four [8]={B00000000,B00000100,B00001100,B00010100,B00100100,B01111110,B00000100,B00000000};
byte Five [8]={B00000000,B01111110,B01000000,B00111100,B00000010,B01000010,B00111100,B00000000};
byte Reverse [8]={B00000000,B01111100,B01000010,B01000010,B01111100,B01000010,B01000010,B00000000};
byte Neutral [8]={B00000000,B01000010,B01100010,B01010010,B01001010,B01000110,B01000010,B00000000};

//const int CLK = D1;                                 // Set the CLK pin connection to the display
//const int DIO = D2;                                 // Set the DIO pin connection to the display
//const uint8_t blank[] = {0x00, 0x00, 0x00, 0x00};   // Declares the value of "blank"
//const uint8_t data[] = {0xff, 0xff, 0xff, 0xff};    // Declares "data" as all segments on
//const uint8_t n[] =                                 // Required segments to display the character "n"
//{
//  SEG_C | SEG_E | SEG_G
//};
//const uint8_t r[] =                                 // Required segments to display the character "r"
//{
//  SEG_E | SEG_G
//};

//TM1637Display display(CLK, DIO);                     //set up the 4-Digit Display

// Set AP credentials
#define AP_SSID "E36GearShifter"
#define AP_PASS "owwmyfrickenexpansiontank"

// UDP
WiFiUDP UDP;
IPAddress local_IP(192, 168, 4, 1);
IPAddress gateway(192, 168, 4, 1);
IPAddress subnet(255, 255, 255, 0);
#define UDP_PORT 4210

// UDP Buffer
char packetBuffer[UDP_TX_PACKET_MAX_SIZE];

void setup() {

  // Setup TM1637 Display
  //display.clear();
  //display.setBrightness(7);       // Set the diplay to maximum brightness
  //display.setSegments(blank);     // Clear display
  lc.shutdown(0,false);
  lc.setIntensity(0,4);
  lc.clearDisplay(0);

  // Setup LED pin
  pinMode(2, OUTPUT);

  // Setup serial port
  Serial.begin(115200);
  Serial.println();

  // Begin Access Point
  Serial.println("Starting access point...");
  WiFi.softAPConfig(local_IP, gateway, subnet);
  WiFi.softAP(AP_SSID, AP_PASS);
  Serial.println(WiFi.localIP());

  // Begin listening to UDP port
  UDP.begin(UDP_PORT);
  Serial.print("Listening on UDP port ");
  Serial.println(UDP_PORT);

}

void loop()
{
  // Receive packet
  UDP.parsePacket();
  UDP.read(packetBuffer, UDP_TX_PACKET_MAX_SIZE);

  if (packetBuffer[0] == 0) {
    Serial.println("Neutral");
    for(int i=0;i<8;i++) lc.setRow(0,i,Neutral[i]);
    //lc.setRow(Neutral);
    //display.setSegments(n, 1, 3);
  }

  if (packetBuffer[0] == 1) {
    Serial.println("One");
    for(int i=0;i<8;i++) lc.setRow(0,i,One[i]);
    //lc.setRow(One);
    //display.showNumberDec(1, false, 1, 3);
  }

  if (packetBuffer[0] == 2) {
    Serial.println("Two");
    for(int i=0;i<8;i++) lc.setRow(0,i,Two[i]);
    //lc.setRow(Two);
    //display.showNumberDec(2, false, 1, 3);
  }

  if (packetBuffer[0] == 3) {
    Serial.println("Reverse");
    for(int i=0;i<8;i++) lc.setRow(0,i,Reverse[i]);
    //lc.setRow(Reverse);
    //display.setSegments(r, 1, 3);
  }

  if (packetBuffer[0] == 4) {
    Serial.println("Three");
    for(int i=0;i<8;i++) lc.setRow(0,i,Three[i]);
    //lc.setRow(Three);
    //display.showNumberDec(3, false, 1, 3);
  }

  if (packetBuffer[0] == 5) {
    Serial.println("Four");
    for(int i=0;i<8;i++) lc.setRow(0,i,Four[i]);
    //lc.setRow(Four);
    //display.showNumberDec(4, false, 1, 3);
  }

  if (packetBuffer[0] == 6) {
    Serial.println("Five");
    for(int i=0;i<8;i++) lc.setRow(0,i,Five[i]);
    //lc.setRow(Five);
    //display.showNumberDec(5, false, 1, 3);
  }
}

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