Divide Input and set as output

Hi everyone,

I'm new at this programming fun..

I have a relative simple question I think

I need to have my Arduino counting a proximity sensors(PNP) input, about 400 inputs , and for each 100 inputs, I need to set and output.

And for every 400 inputs I need to reset counter to 0 and start over..
And if input stops counting i needs to reset it self to 0 after 10 sec.''

Can anyone help me ??

this is a type of frequency divider, because my PLC siemens Logo plc inputs is to slow

martinpede-vest:
I need to have my Arduino counting a proximity sensors(PNP) input,

You will have to be more specific. What does the 'input' act like? Is it a pulse? Hight pulse or low pulse? How long is the pulse? How frequent at the pulses.

martinpede-vest:
about 400 inputs ,

Would I be correct in guessing that this is 400 'inputs' from one sensor and not 400 sensors?

martinpede-vest:
and for each 100 inputs, I need to set and output.

You have to be more specific about the outputs. Are their three outputs that are set HIGH at 100, 200, and 300 counts?

martinpede-vest:
And for every 400 inputs I need to reset counter to 0 and start over.

That should be easy enough. I'm guessing this means the three outputs go back to LOW.

martinpede-vest:
And if input stops counting i needs to reset it self to 0 after 10 sec.

So if no inputs arrive in 10 seconds reset the counter to 0 and the three outputs back to LOW?

martinpede-vest:
Can anyone help me ??

Yes, but you need to make your description much clearer before you start.

johnwasser:
You will have to be more specific. What does the 'input' act like? Is it a pulse? Hight pulse or low pulse? How long is the pulse? How frequent at the pulses.

Input is a Flowmeter, where I have a inductive proximity sensor which pulses 343 for each liter which parses through

so it pulses from high to low. aproximately 343*15 each minute.

Would I be correct in guessing that this is 400 'inputs' from one sensor and not 400 sensors?"

"

Yes, you quessing correct,

You have to be more specific about the outputs. Are their three outputs that are set HIGH at 100, 200, and 300 counts?"

"

For each 86 pulses I need to send 1 pulse out: from 0 to 1 and back to 0

"That should be easy enough. I'm guessing this means the three outputs go back to LOW."

Only 1 output.

"So if no inputs arrive in 10 seconds reset the counter to 0 and the three outputs back to LOW?"

Yes you are correct

Yes, but you need to make your description much clearer before you start.

I'm A bit tired right now :slight_smile: (working late in a hobby brewery)

Hopes this make sense :slight_smile:

Use edge detection instead of level.
Just respond to positive edges.
Dwight

So you have a 343 pulse per liter flow meter and you want a pulse about every 1/4 liter.

I would use an edge-triggered interrupt (see: attachInterrupt()) and a global counter:

void ISR() {
    Counter = (Counter+1) % 86;
    if (Counter == 0) {
        digitalWrite(OutputPin, HIGH);
        digitalWrite(OutputPin, LOW);
    }
}

The loop() function could then monitor the Counter and set it to 0 if it has not changed in 10 seconds. It would not be too hard to compensate for the fact that 343 is not evenly divisible by 4.

thx. for info.. I will try make some code, and upload it :slight_smile:

Hi,

Could this maybe work ? I'm not having my board and sensor hooked up yet.

I'm not sure about the loop function will work properly..

I'm thinking also make a debug solution where I have serial readout

nst byte ledPin = 13;
const byte OutputPin = 10;
const byte interruptPin = 2;
volatile byte state = LOW;
int Counter = 0;
int Counter1 = 0;
int Counter2 = 0;
unsigned long previousMillis = millis();
unsigned long currentMillis = millis();

void setup() {
  pinMode(OutputPin, OUTPUT);
  pinMode(ledPin, OUTPUT);
  pinMode(interruptPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(interruptPin), isr, RISING);
}

void loop() {
 currentMillis = millis();
  Counter1 = Counter ;
  if (Counter1 == Counter2){
    if (currentMillis - previousMillis >= 100000UL)
    Counter = 0;
  }
previousMillis = millis();
Counter2 = Counter;
}

void isr() {
    Counter = (Counter+1) % 86;
    if (Counter == 0) {
        digitalWrite(OutputPin, HIGH);
        digitalWrite(OutputPin, LOW);
    }
}

Counter is an int. That means that it is 2 bytes (on most Arduinos). Reading that int and copying it to Counter1 takes two clock cycles. The interrupt may be triggered during that time, giving you the first byte from one version of the counter and the second byte from the other version. You will get really weird inconsistent errors.

Every time that you grab a copy of Counter, wrap it with noInterrupts(); and interrupts(); That way if an interrupt does occur, it will be delayed momentarily until you have finished the copy.

Please explain what you are trying to do in the loop(). That makes no sense to me. It doesn't seem to have any effect on any output except that it sometimes will damage the value of Counter by setting it to zero.

The Counter only goes from 0 to 85 so we can use a byte and avoid race conditions. When reading more than one byte of volatile data you should turn off interrupts (noInterrupts()) and copy them to local variables before turning interrupts back on (interrupts()). Same if you are writing more than one byte of volatile data.

I think you accidentally set your timer to 100 seconds (100,000 milliseconds) rather than 10 seconds (10,000 milliseconds). It's good to let the compiler do the math at compile time. The result is the same but it is more clear how that value is derived.

Arduino examples tend to go overboard with global variables. I prefer 'static' variables inside a function since they are also persistent (the changes are kept for the next time the function is called) and also local, so no other function can change them.

const byte OutputPin = 10;
const byte InterruptPin = 2;
volatile byte Counter = 0;
const unsigned long Timeout = 10UL * 1000UL;

void setup() {
  pinMode(OutputPin, OUTPUT);
  pinMode(InterruptPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(InterruptPin), isr, RISING);
}

void loop() {
  static byte previousCounter = 0;
  byte currentCounter = Counter;  // Only one byte so noInterrupts()/interrupts() not needed
  static unsigned long previousMillis = 0;
  unsigned long currentMillis = millis();

   // If pulses have arrived...
  if (currentCounter != previousCounter) {
    previousMillis = currentMillis;   // Reset the timeout timer
    previousCounter = currentCounter;  // Check for further changes
  }

  // If the Timeout interval has passed without a timer reset...
  if (currentMillis - previousMillis >= Timeout) {
    Counter = 0;  // Re-start the counter
  }
}

void isr() {
  Counter = (Counter + 1) % 86;
  if (Counter == 0) {
    digitalWrite(OutputPin, HIGH);
    digitalWrite(OutputPin, LOW);
  }
}