Pulse counting from two different frequencies

Hi! A new start to the Arduino world!

And the reason was, that I wanted to see if I could construct a Pulse counter, to receive pulses who comes out from a cars (the very first OBD connectors who was made) OBD connector.

I know, that the signal who comes out, consist of two series of pulses:
the first numbers of pulses, comes every 1 second (represent the numbers of 10 in the error register
The second numbers of pulses comes every 0,5 second and represent the 1 in the error register.

So let says that there comes 4 pulses every 1 second, and 5 pulses every 0,5 second - It will tell an error code on 45, which I will be able to see in an error list.

My question is, if somebody in the Forum, have a code to the Arduiono, to solve that problem, or have seen such one, or maybe would be able to construct one.

My intension was, to let it come out on two 7 segment displays.

Regards

I think that you will need to provide more information on the signal you are trying to measure.

Can you please provide an image (oscilloscope or drawing) of the pulse patterns? What are the pulse lengths. Are they sequential? Are there any stop and start pulses? Is there any other pulse trains coming out of the device other than the two you mentioned?

What is the voltage of the OBD error code pulses?

The pulse, is a +5v signal. And it comes in this pattern as I described! Long puls (1000ms) and short puls (500ms). It runs over and over again.

I can put a Link here, to show how the Diagnose (OBD connector) looks, and what it is I'm "talking about", and thinking on.

http://www.matdunkel.de/sigma/diagnose.htm

I have normally used a LED connected to the + pin out, and then just counted the blink in teh LED. But it would be really nice, to be able to could read it on a Display. :wink:

bassen:
So let says that there comes 4 pulses every 1 second, and 5 pulses every 0,5 second - It will tell an error code on 45, which I will be able to see in an error list.

So the 4 pulses in 1s are on one pin and the 5 pulses in 0.5s on a different pin?
(Signal on 1st pin repeats once per 1s, signal on 2nd pin repeats once per 0.5s)

Or is it a time-division multiplexed signal on the same pin: First 4 pulses in 1s on one pin, followed by 5 pulses in 0.5s on the same pin?
(Signal on the same pin repeats once every 1.5s)

I think that the long pulses are 1000ms and the short pulses are 500ms. It's not clear what the off time between pulses is. I think you could try something very simple with the pulseIn() function. to get you started. You should see an ouptput of long and short times. You should be able to add logic to count the number of long pulses between short ones, and short ones surrounded by long ones. There may also be a specific timing gap between the long and short pulses, and you might be able to pick that up with pulseIn(pin,LOW).

void setup() {
  Serial.begin(115200);
  pinMode(3, INPUT_PULLUP);
}

void loop() {
  Serial.println(pulseIn(3,HIGH));
}

#3 - The signal comes on the same pin, and runs continuesly.

#4 - Where I see "the problem", before I'm even started, is how I can get the counter to "say stop"! By this, I mean that when the output has delivered the pulses (long and short), it starts over again! And there, i have to could grab these two counts, and have them on the display, and hold them there.

And as I wrote in my question, I'm new to Arduino, so I just have to see how the Board works, and how the different Analog / Digital signals comes in and out, and how I can read signals out.
But I'm used to works with electronic, so it's not a problem; I just need a little time to "come into how it works" :slight_smile:

Where I see “the problem”, before I’m even started, is how I can get the counter to “say stop”! By this, I mean that when the output has delivered the pulses (long and short), it starts over again!

Yes, start and stop is often the key to communication protocols. Have you measured both the high and low pulses in a group to determine if there is a specific timing gap between the sets of pulses?

How does the OBD output handle multiple defect codes? How does it handle 0? Is there a code defect 50?

Even with multiple codes, I think the way forward is to count longs and shorts, and look for repeating patterns of data. You can detect a long or short with a test like this

if(pulseLength >=300 && pulseLength <=700)
       //its short//do something
 if(pulseLength >= 800 && pulseLength <=1200)
    //its long//do something

With only two well defined pulses, you may be able to test for one of them, and use if …else logic.

Take a look at the State Change Detection example program in the digital examples which are part of the IDE. You will compare each pulse length to the one preceding it and detect a change between long and short pulse groups. You will group the counts between changes.

I think the logic, for example, would be to look for a change between long and short pulses, count the number of short pulses, until you see a change from short pulses to long pulses. Save the short number and start counting the long number until the next state change. Do this until you see a repeating pattern.

This gets reasonably complex and you can appreciate the approach using the flashing led.

Will this work?

Use interrupt method to detect any pulse transition eg positive going.
Measure period by recording time between pulses.
First Look for period of 1 second then count and store the number of pulses - ignore the 0.5 sec pulses.
When 1 sec pulses have ended, then look for and count 0.5 sec pulses.
Send the result to the display and hold until next 2 digits are available, or hold until user presses an update button.

In case of being part way through any transmit sequence, which would result in getting the wrong count, do it twice to get a match before displaying the result.

#6 - Cattledog, thanks so far! :slight_smile: Regarding the codes which comes. If you dont mind, it could be a good help to better understand this I mean with the pulses, at the Link here:

http://www.matdunkel.de/sigma/diagnose.htm

All pulses which comes, has a fully exact pattern, no matter from which Pin they comes. The only thing, which i so far have not done, is to read out the delay from the last short pulses, and untill a new start of the error code comes again.

You ask! "....How does the OBD output handle multiple defect codes? How does it handle 0? Is there a code defect 50?"
For reading out (if more than one error in same Pin) more codes, you have to have cleared the first error, so it dont exist; then you will get the next code in the queue. The OBD interface is from the very first beginning of OBD, and has no function to could store more codes at a time.
But the diffrent Pins in the OBD connector, reads out, from different part of the Car (explanation in the Link I included).

So I will try out, to see if I can "catch" the length of the Break between an end of an error code series, and untill it starts over again. If it by example, is maybe two seconds, it can be the separator, who can beused to indicate where the pulses has to be interrupted.
And then I will return when i have the length of the break between a new series of pulses.

#7 - I'm not sure, I fully understand what you mean by "measure time between pulses" that's what I already have done; the pattern is as I have described, with 1 second, and 0,5 second.

Thanks

I have now, checked the pulses which comes, and a more specific pattern.

Long pulses, are 1000 ms
Short pulses are: 500 ms
Time between the next code start: 2000ms

And I have to correct what I have been written about more codes, on same Pin.
If more errors in the system on same Pin, it will deliver these codes after same pattern: Long, short, and a break on 2 seconds. And then the next code will come, untill it reach the end, and then it start over again.
So actually, it can holds the error codes, without I have to clear the error between the readings.

So now it begins to be a bit more complicated, as the Arduino have to could pick up the codes, and have a kind of register, to could store / hold these, untill cleared. And so far, I dont know what the Arduino system is capable to do.

I have now, checked the pulses which comes, and a more specific pattern.

And I just wanted to post this :smiley: Anyway

The below code can act as a small analyser so you can get an idea if timings. It would make life easier if you / we have any idea of details (e.g. is there N second delay between the repetition of the error code).

#define INPUTPIN 5

void setup()
{
  pinMode(INPUTPIN, INPUT_PULLUP);

  Serial.begin(9600);
  Serial.println(F("state\tduration"));
}

void loop()
{
  static unsigned long lastmillis = 0;
  static int lastpinstate = 0;

  int pinstate = digitalRead(INPUTPIN);

  if (pinstate != lastpinstate)
  {
    unsigned long currentmillis = millis();
    Serial.print(pinstate);
    Serial.print(F("\t"));
    Serial.println(currentmillis - lastmillis);
 
    pinstate = lastpinstate;
    lastmillis = currentmillis;
  }
}

I’m not sure why you want to remember the codes (it’s easy to store e.g. 100 codes; e.g. use an array where each index reflects one code and increment the value at the index of the error code). Question is how you want to display them afterwards? On button press one by one? Or something else.

With the original requirement, the below code might do the trick (not tested and you need to implement the display function). Functionality is added to store the errors in an array but more details are required to complete it (e.g. how do you want to reset for a new ‘measurement’; currently only a reset will do that).

#define INPUTPIN 5    // the input pin
#define MIN500  400   // minimum duration for 500ms sec pulse
#define MAX500  600   // maximum duration for 500ms sec pulse
#define MIN1000 900   // minimum duration for 1000ms sec pulse
#define MAX1000 1100  // maximum duration for 1000ms sec pulse
#define DELAY 1500    // actually 2000; add some safety margin

byte highcode = 0;
byte lowcode = 0;

int errors[100];

void setup()
{
  pinMode(INPUTPIN, INPUT_PULLUP);

  displayCode();
}

void loop()
{
  static unsigned long lastmillis = millis();
  unsigned long duration;
  static bool start = false;
  static bool lastpinstate = false;
  bool pinstate;

  // sync on delay
  ////////////////////
  if (start == false)
  {
    // wait for a period without activity
    pinstate = digitalRead(INPUTPIN);
    // if there is a change in the pin, we're not in the delay between two codes
    if (pinstate != lastpinstate)
    {
      // restart the duration timing
      lastmillis = millis();
      // remember the last state
      lastpinstate = pinstate;
      return;
    }

    // if delay between codes has expired
    if (millis() - lastmillis > DELAY)
    {
      // indicate that we can start looking for a code
      start = true;
      // reset to zero for net use
      lastmillis = 0;

      // display last received code
      // this is the only place / time where we are sure that it did not change for a while
      displayCode();

      // add to errors array
      int index = highcode * 256 + lowcode;
      errors[index] = 1;

      // reset the counters
      highcode = lowcode = 0;
    }
    // done with loop
    return;
  }

  // start counting
  ////////////////////

  // read pin
  pinstate = digitalRead(INPUTPIN);

  // if high and lastmillis equals zero, it's the start of pulse
  if (pinstate == true && lastmillis == 0)
  {
    lastmillis = millis();
  }
  // if low and lastmillis is not equal to zero, it's the end of pulse
  if (pinstate == false && lastmillis != 0)
  {
    // get duration
    duration = millis() - lastmillis;

    // if 500ms
    if (duration > MIN500 && duration < MAX500)
    {
      lowcode++;
    }
    // if 1000ms
    if (duration > MIN1000 && duration < MAX1000)
    {
      highcode++;
    }
    lastmillis = millis();
  }
}

void displayCode()
{

}

The above is based on cattledog’s earlier code. It first ‘syncs’ on a delay. Next it measures the duration of pulses and depending on the duration increments either the most significant code (highcode) or the least significant code (low code).

The only time that we are sure that the error code does not change is after the code has sync’ed on the delay between two error codes. Only then it will display the error code (displayCode; to be written by you) and error code is ‘added’ to an array by setting the value at the index indicated by the code to 1.

Code compiled with IDE 1.6.6 but not tested.

#11 - Thanks sterretje! It looks interesting, with the code, and thanks so far!

Regarding this you wrote:

sterretje:
I'm not sure why you want to remember the codes (it's easy to store e.g. 100 codes; e.g. use an array where each index reflects one code and increment the value at the index of the error code). Question is how you want to display them afterwards? On button press one by one? Or something else.

Yes, about this where I want to display these errors afterwards. Now, that I have realized, that there actually comes more codes if more errors, the originall plans to show on two 7 segment displays, goes a bit in the background. So now, it's maybe better to look for a rela display, to could read it out there. Or else, i have to use a kind of button, to step in the register of codes.

When I look at the code you have written (it's new to me, with this coding), is it then correctly that you have set it as a Digital input? And do the code aint need a Pin number in the code, to know where it reads from?

I can see, that the more answers, the more it opens up for new questions. And in reality, it's also the meaning, so I can find a way in this project, and the learning curve in Arduino.

I will begin to put something together, and see if I can the code tested, and get an early indication of it will works.

But I'm open for input, ideas and learning. Even that I'm 65 now, I dont think it has to be this who have to stop me, in enjoying the fun things in life!

Thanks

In the beginning of the code I have a few #define lines. The first one defines which pin is the input pin. So everywhere where you would use '5', you can now use a sensible name.

Other people use / prefer a line like int inputPin = 5; or const int inputPin = 5;.

The difference between the last two is that the compiler will warn you if you accidentally try to modify the value of the variable. I have grown up with #define and use that; I think there is no practical difference between #define and const int inputPin = 5; but have never digged deep into it; others might have a different opinion and can prove that I'm wrong :wink:

The pin is indeed configured as an input pin using

  pinMode(INPUTPIN, INPUT_PULLUP);

I configured it with the internal pullup resistor so it is high if nothing is connected; this can prevent spurious counting when nothing is connected.

Here is a sketch which reports the OBD error codes. It uses pulseIn() with a long time out to recognize pulse lengths.

I wrote it before I knew about the 2 second gap between error codes, and, consequently it starts an error sequence when it recognizes a complete run of short pulses following a complete run of long pulses. That is, a valid long sequence must precede a valid short one for there to be a error code reported.

I have used boolean variables to manage the states and the actions required. Multiple error codes are reported. In the reference material it says that there are no error codes without both long and short pulses so the code does not consider any codes containing zeros.

I have also included the sketch I wrote to test the code with simulated OBD error code pulses.

byte longCount;
byte shortCount;

byte tensValue;//for error code
byte onesValue;//for error code

boolean getNextShortCount = false;
boolean getNextLongCount = false;

boolean longPulse = false;
boolean shortPulse = false;

boolean shortCountValid = false;
boolean longCountValid = false;

void setup()
{
  Serial.begin(115200);
  pinMode(3, INPUT_PULLUP);
  Serial.println("Waiting for pulse measurement...");
}

void loop()
{
  unsigned long value = pulseIn(3, HIGH, 2500000);//long timeout required

  if (value >= 800000 && value <= 1200000)
  {
    longPulse = true;
    
    if (longPulse == shortPulse)//transition from shorts to longs
    {
      shortPulse = false; //reset shortPulse state after transition match
      getNextLongCount = true;// next long count will be complete
      longCount = 0;//reset long count
    }
    Serial.print("LONG");
    Serial.print('\t');
    longCount++;//start long count
    Serial.println(longCount);

    if (getNextShortCount == true)
    {
      Serial.print("last complete short count ");
      Serial.println(shortCount);
      if (longCountValid == true)//short valid only after long valid
      {
        shortCountValid = true;
        Serial.println("valid short count after long");
      }
      onesValue = shortCount;
      shortCount = 0;
      getNextShortCount = false;
    }
  }
  if (value >= 300000 && value <= 700000)
  {
    shortPulse = true;

    if (shortPulse == longPulse) //transition from longs to shorts
    {
      longPulse = false;//reset longPulse state after transition match
      getNextShortCount = true;//next short count will be complete
      shortCount = 0;//reset short count
    }

    Serial.print("SHORT");
    Serial.print('\t');
    shortCount++;//start short count
    Serial.println(shortCount);

    if (getNextLongCount == true)
    {
      Serial.print("last complete long count ");
      Serial.println(longCount);
      longCountValid = true;
      tensValue = longCount;
      getNextLongCount = false;
      longCount = 0;
    }
  }

  if (longCountValid == true && shortCountValid == true)
  {
    Serial.print("New ErrorCode = ");
    Serial.println(tensValue * 10 + onesValue);
    shortCountValid = false;
    longCountValid = false;
    onesValue = 0;
    tensValue = 0;
  }


}

Pulse Generating Test Code

void setup()
{
  pinMode(3, OUTPUT);
}

void loop()
{
  //error code 75
  for (int i = 0; i < 7; i++)
  {
    digitalWrite(3, HIGH);
    delay(1000);
    digitalWrite(3, LOW);
    delay(1000);
  }
  for (int i = 0; i < 5; i++)
  {
    digitalWrite(3, HIGH);
    delay(500);
    digitalWrite(3, LOW);
    delay(500);
  }
  delay(2000);
  //error code 48
  for (int i = 0; i < 4; i++)
  {
    digitalWrite(3, HIGH);
    delay(1000);
    digitalWrite(3, LOW);
    delay(1000);
  }
  for (int i = 0; i < 8; i++)
  {
    digitalWrite(3, HIGH);
    delay(500);
    digitalWrite(3, LOW);
    delay(500);
  }
  delay(2000);
}

Hi Cattledog! I was away for a day, and did see the new post now! And thanks for your code (both codes), and I really look forward to could test it up against my OBD interface. But first, I need to put together some hardware still, as I only did buy a Board to start up, to see what Arduino was, and what it could do.

So there will goes x days, before I have the possibility to test it out.

But I think, out from the answers I already got from people in here in the Forum (very helpfull), that i will use a "real" Display (2 or 4 lines), because it gives me much more possibilties than just the code numbers on 7 segment displays.

But thanks, so far :wink: