Pulse Counting

Greetings Arduino community! I am relatively new to this community however I have...how do you say...been a long time listener...first time caller....

I will come out with it immediately...I am more hardware than software and have been using this time under quarantine to dig deeper into the software perspective.

Description of device.....

I have a device that outputs a 5v+ DC error message as a pulse train....150ms on....150ms off for the first 5 rising edge pulses...indicating there is an error message coming....then upon the fifth rising edge when it falls it stays low for 1.1seconds....then followed by the error message which is 700ms on and 600ms off...consisting of 1-11 pulses to differentiate between the errors. Their are a few unknowns about the packet repetition etc...however I will be measuring everything to tailor the software. Yes I am using a pulldown etc My objective is to count the pulses until the pin is low for 'x' seconds

Description of my solution(s)....

From what I understand there are two fairly simple ways to accomplish this, digitalRead() pin state -OR- attach interrupt. I have been playing with the attach interrupt as to learn more about it's functioning and I can get it to count all the pulses...however...it counts and outputs them individually....what I am trying to do is count all the pulses that follow the first pulse so I have the total of pulses to work with. The counter also needs to reset to zero after every packet which this code effectively does. I don't know if I am individually overthinking this problem however when the software is counting pulses i want to make sure it grabs all the pulses so it would need to understand to stay low at least 2 seconds(until I can measure the time between error packet delivery etc) This is my starting code which focuses only on the interrupt. I guess I am not looking for someone to just answer me, I would like to understand the solution etc...thank you for your time.

sketch_apr24d.ino (634 Bytes)

Which you do really depends on if you have got anything else to do at the same time.
If you don't mind sitting in a loop counting pulses, that's fine. Otherwise use the interrupt.
You can use the millis() function to find out how long you have been waiting for since the last pulse.

Never EVER put a delay() in an interrupt routine. It's just asking for trouble as you will miss interrupts.

Coding interrupts is quite hard to get your head around. You need to get away from "linear" programming...

  1. Do this until this happens
  2. Do something else until something else happens

And start thinking about states and events...

  1. When in this state and this event happens, move to the next state
  2. When in the new state and this event happens, move to another state
    etc.

Thank you pcbbc for your response,

Ultimately the unit will simply be there to only monitor that line...however, after it counts the pulses, I need to take that pulse count and output it as a nibble(4-bit byte) so another device is aware there is an error and which error it is. I am effectively using an Arduino Uno as a middle man between Device 1 outputting the error and Device 2 listening for error...device 2 does not have the resolution to interpret pulses from Device 1....which is why I figured I would use UNO to listen and then send out a nibble to Device 2

I would say that the device can sit in the loop waiting to count pulses, however after the total pulses are counted and line is low for 2 seconds I need to output.

If I understand your suggestion correctly, you are saying to use the millis() function to determine when the line was low for 2 seconds? That's how I can handle stop counting pulses?

I think I am confusing myself in code land as it's still not clear as to how I total the pulses?

The ESP32 has a hardware pulse counter that is not dependent upon the CPU, which can be accessed through the PCNT API of the ESP32.

https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/pcnt.html

The PCNT (Pulse Counter) module is designed to count the number of rising and/or falling edges of an input signal. Each pulse counter unit has a 16-bit signed counter register and two channels that can be configured to either increment or decrement the counter. Each channel has a signal input that accepts signal edges to be detected, as well as a control input that can be used to enable or disable the signal input. The inputs have optional filters that can be used to discard unwanted glitches in the signal.

Thank you Idahowalker!

I appreciate the pointer to that board! That is nice little piece of equipment. However, all I have at the moment is an Arduino UNO, MEGA, LEONARD and DUE. I'd like to try this home project with one of those four to better understand the IDE!

Possibly pulsein could be applied. Use one for the high time, another for the low time. If times are within some range they're valid so count a pulse. After start sequence use a different set of pulsein to decode the error message.

A state machine may be useful here.

arduino search state machine.png

arduino search state machine.png

dougp thank you for the suggestion...especially about the state machine! That is very interesting however I need to learn a little more about that in particular before I attempt to implement. Great share!

That being said....after all the suggestions and research I have come up with, what I would consider generic solution...effectively counts pulses...again....of a known pulse width, train architecture transmission etc....it will reset....but I used a timer to do it. That being said now...if a second pulse train comes in...it interferes with the existing count etc....of course I would like to share this solution as it may help someone else....so please review and if anyone has a suggestion on how to prevent counter interruption...please share experience! I feel an interrupt would prevent this but I am not 100% positive on how to appropriately implement this.

Pulse_Counter_Reset_Zero_Slow_Pulse.ino (648 Bytes)

1 Like

Did you want to filter out pulse trains that don't match the desired pattern? I think the first step would be to spell out the desired pattern:

// Desired pattern of pulses, alternating HIGH and LOW
unsigned Pattern[] = {150, 150,  150, 150,  150, 150,  150, 150,  150, 1100,  700, 600,  700, 600,  700, 600,  700, 600,  700, 600,  700, 600,  700, 600,  700, 600,  700, 600,  700, 600,  700, 600,  700, 600,  700, 600};

Then keep track of which half-pulse you are on. If the pulse is longer than 1500, you are done and can tell how many 700 ms pulses there were. If the pulse is less than 1500, check to see that it comes close to matching the desired half-pulse width. If it doesn't match, reset and start looking for the first HIGH pulse again.

Greetings John!

Thank you for taking the time to review my question and provide your post and reply.

To answer your question....in the original post I provided details about the specifics to the pulse train and the information I was interested in gathering...."outputs a 5v+ DC error message as a pulse train....150ms on....150ms off for the first 5 rising edge pulses...indicating there is an error message coming....then upon the fifth rising edge when it falls it stays low for 1.1seconds....then followed by the error message which is 700ms on and 600ms off...consisting of 1-11 pulses to differentiate between the errors."....so my objective now is to interpret amount of pulses; 5 guaranteed, followed by only 1 to 11 individual pulses,(there is still some data logging I need to do here, particularly time between pulse trains etc) which is why I simply want to count the total number of pulses....grab that variable before it resets....pass it to another variable that will enter a switch statement writing directly to port registers of Arduino pinHIGH to emulate a binary message(in a sense) turning on an arrangement of 1-4 ports to represent 1-11 error codes(the interpretation is on other end in another device.

I hope this helps you understand more! Thank you again for taking the time to review my question!