Read Pattern Data pada Digital Input Arduino UNO

Please help how to read the following digital pin (2) Arduino UNO.

The data I want to check is the HIGH status (475-525 miliseconds) followed by the LOW status (475-525 miliseconds).

If the data is found in a row 3 times then the pattern is considered suitable.

With the sketch below, I can read the pattern.

But I'm not sure whether this sketch is effective and efficient enough? And safe enough?

Please suggest writing a better (accurate) program for the project I'm working on. Thank You.


int iHigh =0;
int iLow =0;
int stateMatch =0;

const int enablePin = 4;
const int signalPin = 2;

void setup() {

  pinMode(enablePin, INPUT);
  pinMode(signalPin, INPUT);
  Serial.begin(9600);
}

void loop() {
  if (digitalRead(enablePin) == HIGH){
     detectPattern();
  }
}

void detectPattern(){
  unsigned long startTime, endTime;
  while (digitalRead(signalPin) == LOW);
  startTime = millis();
  while (digitalRead(signalPin) == HIGH);
  endTime = millis();
  unsigned long highDuration = endTime - startTime;

  
  while (digitalRead(signalPin) == HIGH);
  startTime = millis();
  while (digitalRead(signalPin) == LOW);
  endTime = millis();
  unsigned long lowDuration = endTime - startTime;
  
  if (highDuration >= 475 && highDuration <= 525) {
      iHigh = 1;
    }else{
      iHigh = 0;
    }

  
  if (lowDuration >= 475 && lowDuration <= 525) {
      iLow = 1;
    }else{
      iLow = 0;
    }
 

   if (iHigh == 1 && iLow ==1) {
      stateMatch += 1;
    }else{
      stateMatch = 0;
    }
    if (stateMatch == 3){
      Serial.println("Pattern Detected");
      stateMatch = 0;
    }
}


read about pulseIn() function
and look ping example in IDE
изображение

1 Like

The pulseIn() function is not at all suitable for reading consecutive HIGH and LOW times. When it reads a HIGH pulse it doesn't return until the signal goes LOW. After that it is too late to read a LOW pulse because pulseIn() will wait until the end of the next HIGH pulse to start timing.

1 Like

yes, but what is able to read consecutive periods?

UPD;

1 Like

CHANGE interrupt. If the pin is HIGH it was a rising edge. If the pin is LOW it was a falling edge.

In this case, it doesn't even matter much if the edge is rising or falling since all of the states must be 500 milliseconds (+/- 25). If you get a rising edge followed by 6 changes at the required intervals, the pattern is present.

Here is an example of how it might be done on an External Interrupt pin (pin 2, in this case). NOTE: This looks for three HIGH pulses with two LOW pulses between. Changing the desired count to 7 would require the third LOW pulse to be followed by a HIGH at the expected time.

volatile bool PatternFound = false;
void ChangeISR2()
{
  unsigned long currentMicros = micros();
  static unsigned long previousMicros = 0;
  static byte changeCount = 0;
  int pinState = digitalRead(2);

  if (changeCount == 0)
  {
    if (pinState == HIGH)  // First rising edge
    {
      changeCount = 1;
      previousMicros = currentMicros;
    }
  }
  else
  {
    unsigned long elapsedMicros = currentMicros - previousMicros;
    if (elapsedMicros < 475000ul || elapsedMicros > 525000ul)
    {
      // Pulse or gap too long or too short
      changeCount = 0;
      if (pinState == HIGH)  // A new 'First rising edge'
      {
        changeCount = 1;
        previousMicros = currentMicros;
      }
    }
    else
    {
      // Valid pulse or gap
      changeCount++;
      previousMicros = currentMicros;

      if (changeCount == 6)
      {
        changeCount = 0;
        PatternFound = true;
      }
    }
  }
}
1 Like
volatile uint8_t Status = 0;
volatile uint32_t StartRising = 0;
volatile uint32_t StartFalling = 0;
volatile uint32_t EndPeriode = 0;

void setup() {
  Serial.begin(115200);
  attachInterrupt(digitalPinToInterrupt(2), ISR, CHANGE);
}

void loop() {
  static uint8_t PatternWait = 0;
  if (~(PINB & 1 << 2))interrupts();
  delay(2000);
  noInterrupts();

  if (abs(int(StartFalling - StartRising - 500UL)) < 26 && abs(int(EndPeriode - StartFalling - 500UL)) < 26)PatternWait++;
  if (PatternWait == 3) {
    Serial.println("Pattern found");
    PatternWait = 0;
  }
  Status = 0;
}

void ISR() {
  switch (Status) {
    case 0:
      StartRising = micros();
      Status += 1;
      break;
    case 1:
      StartFalling = micros();
      Status += 1;
      break;
    case 2:
      EndPeriode = micros();
      Status += 1;
      break;
  }
}

read about pulseIn() function

I just found out about the pulsein() function, I might give it a try.

In this case, I intend to read IC CMX673 output data, the expected data is 500 millisecond HIGH and 500 millisecond LOW. With a slight tolerance (+/-25).

CP CMX673

Datasheet IC Call Progress Detector CMX673

To ensure that the HIGH and LOW statuses are correct, I think there are at least three identical HIGH LOW patterns, so the pattern is considered correct.

I'm still confused with the interrupt function.
Sorry if this is a stupid question: what if the Digital Input used as the Input Signal is not read on PIN2? Can you use the interrupt function like the code you wrote?

Thanks

I really appreciate your time to take time to help my case.
I will study the lines of code you wrote, and will update you as soon as I try them out.
Thanks

I tried to upload your sketch, and an error appears:

sketch_apr24c:25:6: error: expected ')' before 'void'

exit status 1
'ISR' was not declared in this scope

then I changed the ISR routine calling a bit so:

 attachInterrupt(digitalPinToInterrupt(2), _ISR, CHANGE);

and

void _ISR() {
  switch (Status) {
    case 0:
      StartRising = micros();
      Status += 1;
      Serial.println("0");
      break;
    case 1:
      StartFalling = micros();
      Status += 1;
      Serial.println("1");
      break;
    case 2:
      EndPeriode = micros();
      Status += 1;
      Serial.println("2");
      break;
  }
}

Result on Serial terminal:

0
1
2
0
1
2
0
1
2
0
1
2
0
1
2

Pattern not found.

Where did I go wrong? Thanks.

To use the built-in "attachInterrupt()" function you need to use a pin that supports External Interrupts. On the UNO or NANO that is Pin 2 or Pin 3. For most other pins you can use the third-party "PinChangeInterrupts" library to get interrupts or hand-code them.

What model Arduino are you using?

For such a slow signal there isn't a real need to use interrupts. It can easily be done in software on any pin.

const byte DetectPin = 7;

void setup()
{
  pinMode(DetectPin, INPUT);
}

void PatternFound()
{
  // Put the code here to execute when the pattern is detected
}

void loop()
{
  unsigned long currentMillis = millis();
  static unsigned long lastChangeTime = 0;
  static byte changeCount = 0;
  static int previousPinState = LOW;

  int pinState = digitalRead(DetectPin);

  if (pinState != previousPinState)
  {
    // Pin has changed state
    previousPinState = pinState;

    if (changeCount == 0)
    {
      if (pinState == HIGH)  // First rising edge
      {
        changeCount = 1;
        lastChangeTime = currentMillis;
      }
    }
    else
    {
      unsigned long elapsedMillis = currentMillis - lastChangeTime;
      if (elapsedMillis < 475 || elapsedMillis > 525)
      {
        // Pulse or gap too long or too short
        changeCount = 0;
        if (pinState == HIGH)  // A new 'First rising edge'
        {
          changeCount = 1;
          lastChangeTime = currentMillis;
        }
      }
      else
      {
        // Valid pulse or gap
        changeCount++;
        lastChangeTime = currentMillis;

        if (changeCount == 6)
        {
          changeCount = 0;
          PatternFound();
        }
      }
    }
  }
}

Currently using ATmega328 (ARDUINO UNO R3), but in the future I plan to use a microcontroller with simpler specs, such as Attiny44. I'm ordering it online today.

I am very excited to read it. So I then thought of using a lower spec microcontroller.

I'm sure you will agree. If you can use components that are more efficient, why should you use expensive components. As long as the desired specs can be met.

The code you wrote, I have just tried, and it works fine.

void PatternFound()
{
  // Put the code here to execute when the pattern is detected
  Serial.println("HEY! I AM HERE. I'M ON! I'M ON!");
}

MENYALA

Thank you for your help. I am very happy.

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