Semaphor project

hi everybody

this is my first script in C++/Arduino.
it suposes to be a semaphor simulator, where on keypad 4x4 one of 32 signals is selected (first series directly by single press, than second one, by double or long click). Semaphor consists of 5 LED plus addtional RGB led. Keypad is read by only one cable (using bynch of resistors). Serial prints might be used to display signal code on 4 disgit 7 segment display, or LED display
Generally it is working - do the intented steps. However....

  • more often than it working fine it ceased, and it is not responsive, or sometimes it takes a good while and several presses.
  • sometimes signals are not displayed correctly - like being mismatched
  • it responds ok to long press, however a double click give only momentary switch, and comes back to first series same position (like 10a and 10 straight after)
    -measurements and pinReading are correct - i got them on seperate script, and responses were without any delay. on problems occuring i double checked them, and still yhe same.

i would be gratefull for aby hint how to improve, or what to change, or any indication where i am doing a mistakes. comments in native language were removed. have a nice day

int measurement[16] = { 272, 214, 145, 61, 260, 199, 128, 41, 247, 184, 110, 21, 235, 169, 92, 0 };

char* sigKODSemaphor[] = { "S1", "S2", "S3", "S4", "S5", "S6", "S7", "S8", "S9", "S10", "S11", "S12", "S13", " ", " ", "Sz", "Sp1", "Sp2", "Sp3", "Sp4", " ", " ", " ", " ", " ", "S10a", "S11a", "S12a", "S13a", " ", " ", "Sz", '\0' };

int sigNUMSemaphor[] = { 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 0, 0, 120, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 0, 0, 220 };

int green = 7, yell1 = 6, red = 5, yell2 = 4, white = 3;
int rLEDPin = 9, gLEDPin = 10, bLEDPin = 11;

bool ledBlinkState = 0;

const int pinReading = A2;
bool buttonState = 0, marker = 0;

const int timeDelay = 1500, timeReaction = 2000, timeHold = 750;
int maintain = 1023, delayTime = 1000;


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

  pinMode(green, OUTPUT);
  pinMode(yell1, OUTPUT);
  pinMode(red, OUTPUT);
  pinMode(yell2, OUTPUT);
  pinMode(white, OUTPUT);


  pinMode(rLEDPin, OUTPUT);
  pinMode(gLEDPin, OUTPUT);
  pinMode(bLEDPin, OUTPUT);
}

void loop() {
  //put your main code here, to run repeatedly:
  bool additionalSignals = 0;
  int i = 0;

  int feed = analogRead(pinReading);


  if (!(abs(feed - 1023) < 5) && (isButtonDoubleOrLongPressed(pinReading, timeDelay, timeReaction, timeHold) == 1)) additionalSignals = 1;  

  while (i < 16) { 
    if (abs(feed - measurement[i]) < 5) {
      maintain = feed;
      marker = additionalSignals;

      if (additionalSignals == 1) Serial.println(sigKODSemaphor[i + 16]);  
      else Serial.println(sigKODSemaphor[i]);

      while (analogRead(pinReading) < 1000) { 
        delay(100);
        break;
      }
    }
    i++;
  }

  switch (semaphorSignal(maintain, marker)) {
    case 101:
      digitalWrite(green, LOW);
      digitalWrite(yell1, LOW);
      digitalWrite(red, HIGH);
      digitalWrite(yell2, LOW);
      digitalWrite(white, LOW);
      setLedRGBColor(0, 0, 0);
      break;
    case 102:
      digitalWrite(green, HIGH);
      digitalWrite(yell1, LOW);
      digitalWrite(red, LOW);
      digitalWrite(yell2, LOW);
      digitalWrite(white, LOW);
      setLedRGBColor(0, 0, 0);
      break;
    case 103:
      blink(green);
      digitalWrite(yell1, LOW);
      digitalWrite(red, LOW);
      digitalWrite(yell2, LOW);
      digitalWrite(white, LOW);
      setLedRGBColor(0, 0, 0);
      break;
    case 104:
      digitalWrite(green, LOW);
      blink(yell1);
      digitalWrite(red, LOW);
      digitalWrite(yell2, LOW);
      digitalWrite(white, LOW);
      setLedRGBColor(0, 0, 0);
      break;
    case 105:
      digitalWrite(green, LOW);
      digitalWrite(yell1, HIGH);
      digitalWrite(red, LOW);
      digitalWrite(yell2, LOW);
      digitalWrite(white, LOW);
      setLedRGBColor(0, 0, 0);
      break;
    case 106:
      digitalWrite(green, HIGH);
      digitalWrite(yell1, LOW);
      digitalWrite(red, LOW);
      digitalWrite(yell2, HIGH);
      digitalWrite(white, LOW);
      setLedRGBColor(0, 255, 0);
      break;
    case 107:
      blink(green);
      digitalWrite(yell1, LOW);
      digitalWrite(red, LOW);
      digitalWrite(yell2, HIGH);
      digitalWrite(white, LOW);
      setLedRGBColor(0, 255, 0);
      break;
    case 108:
      digitalWrite(green, LOW);
      blink(yell1);
      digitalWrite(red, LOW);
      digitalWrite(yell2, HIGH);
      digitalWrite(white, LOW);
      setLedRGBColor(0, 255, 0);
      break;
    case 109:
      digitalWrite(green, LOW);
      digitalWrite(yell1, HIGH);
      digitalWrite(red, LOW);
      digitalWrite(yell2, HIGH);
      digitalWrite(white, LOW);
      setLedRGBColor(0, 255, 0);
      break;
    case 110:
      digitalWrite(green, HIGH);
      digitalWrite(yell1, LOW);
      digitalWrite(red, LOW);
      digitalWrite(yell2, HIGH);
      digitalWrite(white, LOW);
      setLedRGBColor(0, 0, 0);
      break;
    case 210:
      digitalWrite(green, HIGH);
      digitalWrite(yell1, LOW);
      digitalWrite(red, LOW);
      digitalWrite(yell2, HIGH);
      digitalWrite(white, LOW);
      setLedRGBColor(255, 255, 0);
      break;
    case 111:
      blink(green);
      digitalWrite(yell1, LOW);
      digitalWrite(red, LOW);
      digitalWrite(yell2, HIGH);
      digitalWrite(white, LOW);
      setLedRGBColor(0, 0, 0);
      break;
    case 211:
      blink(green);
      digitalWrite(yell1, LOW);
      digitalWrite(red, LOW);
      digitalWrite(yell2, HIGH);
      digitalWrite(white, LOW);
      setLedRGBColor(255, 255, 0);
      break;
    case 112:
      digitalWrite(green, LOW);
      blink(yell1);
      digitalWrite(red, LOW);
      digitalWrite(yell2, HIGH);
      digitalWrite(white, LOW);
      setLedRGBColor(0, 0, 0);
      break;
    case 212:
      digitalWrite(green, LOW);
      blink(yell1);
      digitalWrite(red, LOW);
      digitalWrite(yell2, HIGH);
      digitalWrite(white, LOW);
      setLedRGBColor(255, 255, 0);
      break;
    case 113:
      digitalWrite(green, LOW);
      digitalWrite(yell1, HIGH);
      digitalWrite(red, LOW);
      digitalWrite(yell2, HIGH);
      digitalWrite(white, LOW);
      setLedRGBColor(0, 0, 0);
      break;
    case 213:
      digitalWrite(green, LOW);
      digitalWrite(yell1, HIGH);
      digitalWrite(red, LOW);
      digitalWrite(yell2, HIGH);
      digitalWrite(white, LOW);
      setLedRGBColor(255, 255, 0);
      break;
    case 120:
      digitalWrite(green, LOW);
      digitalWrite(yell1, LOW);
      digitalWrite(red, HIGH);
      digitalWrite(yell2, LOW);
      blink(white);
      break;
    case 0:
      digitalWrite(green, LOW);
      digitalWrite(yell1, LOW);
      digitalWrite(red, LOW);
      digitalWrite(yell2, LOW);
      digitalWrite(white, LOW);
      setLedRGBColor(0, 0, 0);
      break;
     default:
      break;
  }
}


bool isButtonDoubleOrLongPressed(int keyPadPin, int delayTime, int reactTime, int timeHold) {  
  int feed_1, feed_2;
  unsigned long currentPressTime, midPressTime;

  if (!(abs(analogRead(keyPadPin) - 1023) < 5) && buttonState == 0) { 
    buttonState = 1;
    feed_1 = analogRead(keyPadPin);
    currentPressTime = millis();
    while (analogRead(keyPadPin) < 1000) delay(100); 

    buttonState = !buttonState;
    midPressTime = millis();
    if (millis() - currentPressTime > timeHold) {  
      return 1;
      buttonState = 0;
    }
  } else {
    buttonState = 0;
    return 0;
  }

  while (millis() - midPressTime < delayTime) {
    if (!(abs(analogRead(keyPadPin) - 1023) < 5) && buttonState == 0) {  
      feed_2 = analogRead(keyPadPin);
      if ((abs(feed_1 - feed_2) < 5) && (abs(millis() - currentPressTime) < reactTime)) {  
        return 1;
      }
    }
  }
  return 0;
  buttonState = 0;
}


int semaphorSignal(int reading, bool signalAdditional) {  
  int i;
  i = 0;
  while (i < 16) {
    if (abs(reading - measurement[i]) < 5) {
      if (signalAdditional == 1) return (sigNUMSemaphor[i + 16]);
      else return (sigNUMSemaphor[i]);

      while (analogRead(pinReading) < 1000) { 
        delay(100);
        break;
      }
    }
    i++;
  }
  return 0;
}


void blink(int ledPin) {  
  static unsigned long previousBlinkTime = 0;
  unsigned long currentBlinkTime = millis();
  if (currentBlinkTime - previousBlinkTime > 1000) {
    previousBlinkTime = currentBlinkTime;
    if (ledBlinkState == 0) ledBlinkState = 1;
    else ledBlinkState = 0;

    digitalWrite(ledPin, ledBlinkState);
  }
}


void setLedRGBColor(int red, int green, int blue) {
#ifdef COMMON_ANODE
  red = 255 - red;
  green = 255 - green;
  blue = 255 - blue;
#endif

  analogWrite(rLEDPin, red);
  analogWrite(gLEDPin, green);
  analogWrite(bLEDPin, blue);
}

Whenever someone says their project has problems reacting to switch press, I look for the most common causes which are the use of "while()" and the use of "delay()". And guess what there they are in your code. So the program is doing exactly what you have written.

How to fix? I don't know because I can't follow your logic. But if you rework the code to get rid of the problems, it will be much more reactive to input.

16 buttons to a single analog input ? Breadboards have often bad contacts. That will not work reliable.
The lowest value is 21 and the highest value is only 272. That is a small range.
The distance between the values is: 21, 20, 20, 31, 18, 18, 17, 24, 15, 15, 15, 21, 12, 13, 12
The lowest distance is 12. The limit to check a value is therefor 5 or 6. You have 5 in your sketch. That is the result of the circuit, but it is a small value.

Can you make a small (test)sketch to test the buttons ?
If you use a matrix, then 8 digital pins are needed. I think that there are still 8 pins available on the Arduino Uno for that.

The char* sigKODSemaphor[] is a list of pointers to text in memory. The compiler can decide where to place the actual text in memory.
However, the last item is '\0'. That could be a bug, but that last item is not used. You can remove it.
The compiler prefers to add "const" : const char* sigKODSemaphor[]

This could also be a bug: abs(millis() - currentPressTime) < reactTime
The variable "currentPressTime" is unsigned long and millis() returns a unsigned long. To avoid a rollover problem, keep that as it is. Don't use the "abs()" there, even if it is not a real bug.

An event from the outside world should not be able to stop a sketch. Your "while()" and "delay()" can do that, as Paul_KD7HB already wrote.

Hello macs77

Welcome to the best Arduino Forum ever :slight_smile:

Post a connection diagram to see how we can help.

Hi

The simple sketch that reads response of keys is working fine without any issues. The deviation from arrays is 1-2. I did not observe higher diffrence.

My intention was to limit usage of digital pins, thus the diffrence in key press is determine by analog input VIA voltage divider. On above Simple sketch is working fine. This is what i have started from

And on the current value of the voltage applied to the divider. When I did similar, years ago, I had to adjust the code for different power sources.

Despite I tried on battery 9V, I mainly powered micro controller from USB computer, and took 5V of VCC. On this I worked out measurement. As I said, it did not differed more than 2 from original on several attempts.

1 Like

FWIW, I scan up to 22 buttons on one AI, so it can be done. My button resistors are selected to arrive at > 30 counts per button, and a LUT is used to optimize the selection process. A capacitor is used to reduce noise.

Just to check, I have added condition:

If (!(abs(feed-1023)<5) {}

for the first while in the loop section. Then monitored feed, maintain and semaphorSignal After a couple presses, in idle state ( with no presses), last three variables where dead staedy - and stay unchanged despite next presses. Truły working, I cannot see, which while or delay might block the core and why

The only diffrence I don't have capacitor available at the moment. Resistors used are 0.2 and 1.0 kOhm

And that might suffice for the number you want, but it can be improved upon.

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