coin acceptor/Reading the pulses/09. Three modes, and which one you want
Reading the pulses · 09 of 11

Three modes, and which one you want

Counter, value and mapped. Each one reads a different wire, needs a different pulse plan, and quietly leaves one of the library's totals at zero forever. Pick by what you need to know, not by which sounds most capable.

The three

What the sketch gets, after three coins
COIN_MODE_COUNTER · reads COUNTER
Mode
Signal wire
COUNTER
Coins counted
3
Money totalled
How many coins have been accepted. It cannot tell a dollar from five cents. Every coin is one event. It is the mode to start with: one wire, one event per coin, and nothing to program wrong.

The figure runs the same three coins through each mode and shows what the library's four readout calls contain afterwards. The greyed rows are the point: every mode leaves something permanently at zero, and the library does not warn you about it.

Counter mode

CoinAcceptor coin(COIN_PIN, COIN_MODE_COUNTER);

One event per accepted coin, read off the COUNTER wire. update() returns true once per coin and totalCoins() goes up by one. There is nothing to program into the acceptor beyond training, because the coin's pulse value is irrelevant — COUNTER sends one pulse regardless.

This is the mode to start with. If it works, your wiring and your training are both fine, and anything that then goes wrong in another mode is a configuration problem rather than a hardware one.

Value mode

CoinAcceptor coin(COIN_PIN, COIN_MODE_VALUE);

void setup() {
  coin.setPulseValue(5);   // five cents per pulse
  coin.begin();
}

Reads the COIN wire, multiplies the pulses in each group by a fixed rate, and adds the result to totalValue(). It never has to recognise anything, so it cannot mis-recognise anything — which makes it the robust choice when the total amount is what matters.

The condition is the pulse plan. Every coin must be set to a pulse count proportional to its value at that one rate, or the total is nonsense. And note what it does not fill in: totalCoins() stays at zero in this mode however much money goes in.

Mapped mode

CoinAcceptor coin(COIN_PIN, COIN_MODE_MAPPED);

void setup() {
  coin.addCoin(1, 5);      // 1 pulse  = 5 cents
  coin.addCoin(3, 25);     // 3 pulses = 25 cents
  coin.addCoin(5, 100);    // 5 pulses = 1 dollar
  coin.begin();
}

Waits for a complete group of pulses, looks the count up in the table you built, and reports that coin's value. Both totalCoins() and totalValue() are filled in, and value() tells you what the last coin was worth. Up to six coins, each with a distinct pulse count, none above 50 pulses.

This is the mode that can be wrong rather than merely incomplete. A pulse count it does not recognise sets hasError(), which you should check on every event:

if (coin.update()) {
  if (coin.hasError()) {
    Serial.print("unrecognised: ");
    Serial.println(coin.pulses());
    return;
  }
  Serial.println(coin.value());
}

Why mapped mode can be confidently wrong

Two coins dropped in close together merge into one group, and the count is the sum. With the table above, a 5c and a 25c together make four pulses, which is not a coin — so hasError() fires and you find out.

Change the table so that some pair sums to a count you did use, and the same merge is reported as a single valid coin, with no error at all. No amount of checking in your sketch can detect that, because a single wire carrying a pulse count genuinely does not distinguish the two cases. Why fast coins get missed is the page about that, and value mode is the escape from it.

Choosing

  • One coin buys one thing — counter mode, on COUNTER. Nothing to get wrong.
  • A running total of money — value mode, on COIN, with a proportional plan.
  • Different coins do different things — mapped mode, on COIN, and check hasError() every time.

Everything above must be set before begin(). setPulseValue, addCoin, setTiming and setInterruptEnabled all check whether the library has started and do nothing if it has.

When it does not work

totalCoins() is always zero and money is adding up fine

You are in value mode, and that is what value mode does — it adds to totalValue() and never touches totalCoins(). Nothing is broken. If you need both numbers, use mapped mode, which fills in both.

begin() returns false and my sketch stops in setup()

Three things make begin() fail. Value mode with a pulse value of zero, mapped mode with no coins added, or an invalid mode. In mapped mode the usual cause is an addCoin() call that was rejected — a duplicate pulse count, a count above 50, a zero value — leaving no coins mapped at all.

hasError() keeps going true in mapped mode

A group of pulses arrived that does not match any coin you added. Either the coins are going in too fast and two trains are merging, or the pulse values programmed into the acceptor do not match the numbers in your addCoin() calls. Print coin.pulses() when the error fires — the count tells you which.

setPulseValue() or addCoin() seems to be ignored

They only work before begin(). Every configuration call on this library checks that it has not started yet and returns without doing anything if it has. Put them above begin() in setup().

Where this goes next

The whole build: three wires, one sketch, and a total on the serial monitor.

Count coins on an ESP32 or an UNO

Edit this page — content/books/coin-acceptor/three-modes.mdx

Community

Questions about this product

See what other owners have asked, and read their solutions.

Ask a question ↗

Arcade Coin Acceptor Module Kit, USB-C Powered

Loading discussions…

Discuss this article

Ask about this page. The answer stays here, on the page it belongs to, for whoever hits the same wall next.

Browse Modules and blocks on the forum