piezo sensor/Reading it/06. The first reading
Reading it · 06 of 9

The first reading

Two wires, no library, and a sketch that prints the highest reading in every 20 ms, so each tap shows on the Serial Plotter as one spike at nearly its real height. GND to GND, SIGNAL to an analog pin: A0 on an Uno, GPIO 34 on an ESP32, GPIO 4 on an ESP32-S3, GP26 on a Pico. No supply wire.

Two wires

Two wires
Your board
GND to
GND
SIGNAL to
GPIO 4
Supply wire
none
GND to GND and SIGNAL to GPIO 4, an ADC1 pin, which keeps working while Wi-Fi is on. No supply wire: nothing on the block uses one. The ESP32-S3 reads 12 bits, 0 to 4095, and stops growing at about 3.1 V.

GND to GND. SIGNAL to an analog pin: the pins the TK27 Analog Microphone book uses, so one wiring serves both blocks. Both NC pins stay unconnected, and there is no supply wire, because nothing on the block uses one.

On an ESP32, GPIO 34 is on ADC1, which keeps working while Wi-Fi is on; ADC2's pins do not. On an ESP32-S3, GPIO 4 is on ADC1 as well and is not a strapping pin.

The sketch

A tap is a hump that rises in about a millisecond and falls over a tenth of a second or so. The sketch reads SIGNAL as fast as the board allows for 20 ms, keeps the highest reading, prints it, and starts again. Twenty milliseconds is short next to the hump, so the highest reading in each window is close to the hump's real top whenever the tap lands.

It prints millivolts, not raw counts, so an Uno's 0 to 1023 and an ESP32's 0 to 4095 come out on the same scale. On an ESP32 analogReadMilliVolts uses the chip's own calibration. On an Uno it multiplies by 5000 / 1023; on a Pico, set FULL_SCALE_MV to 3300.

In MicroPython

The same sketch for an ESP32, an ESP32-S3 or a Pico. On an ESP32 it sets the ADC to its widest range with adc.atten(ADC.ATTN_11DB) first: MicroPython starts it on a range of about 1 V, where even a light tap reads full scale. The script for this block that this book replaces never set it. Then read_uv() gives calibrated microvolts. On a Pico, read_u16() is scaled against 3.3 V. Thonny's plotter shows the taps.

piezo_first_reading.py
"""
  Piezo-Ceramic Sensor - first reading, MicroPython    TK59 / /p/tk59

  Two wires: the block needs no supply. Count from the square pad on
  the TinkerBlock board, parts up, header on the left:

    GND    -> GND
    NC     -> nothing   (connected to nothing on the board)
    NC     -> nothing   (nor is this one: there is no VCC pin)
    SIGNAL -> GPIO 34 on an ESP32, GPIO 4 on an ESP32-S3,
              GP26 on a Raspberry Pi Pico

  Thonny
    Run > Configure interpreter   MicroPython (ESP32) or
                                  MicroPython (Raspberry Pi Pico)
    View > Plotter                to see each tap
    Nothing to install: machine, sys and time are built in.
"""

import sys
import time
from machine import ADC, Pin

# The GPIO number SIGNAL is wired to. ESP32: 34. ESP32-S3: 4. Pico: 26.
PIEZO_PIN = 4
# A tap is a hump: up in about a millisecond, down over a tenth of a
# second or so. The highest reading in each 20 ms catches the top.
WINDOW_MS = 20

adc = ADC(Pin(PIEZO_PIN))
ESP32 = sys.platform == "esp32"       # ESP32 and ESP32-S3
if ESP32:
    adc.atten(ADC.ATTN_11DB)          # the full range, to about 3.1 V


def read_mv():
    if ESP32:
        return adc.read_uv() // 1000  # calibrated in the chip
    return adc.read_u16() * 3300 // 65535


while True:
    peak = 0
    start = time.ticks_ms()
    while time.ticks_diff(time.ticks_ms(), start) < WINDOW_MS:
        mv = read_mv()
        if mv > peak:
            peak = mv
    print(peak)
View on GitHub · blocks/tk59-piezo-sensor/micropython/piezo_first_reading.py @ v1.5

What you should see

Open Tools > Serial Plotter at 115200. With nothing touching the disc the line sits at 0, or within a few tens of millivolts of it on an ESP32. Tap the disc and a spike goes up and falls back over a few points. A harder tap makes a taller spike. Press and hold, and the spike falls back while your finger is still down.

The owner's two videos show the block on a LEGO baseplate. It has no light of its own, so nothing on it changes as the disc is pressed: what it does shows only in the numbers.

The TK59 on a LEGO baseplate, cabled to an Uno-format board, its disc lying beside it. A finger presses and taps the disc; the block has no light, so the result is in the serial monitor, not on the block.
The same block wired to a Raspberry Pi Pico 2 on a LEGO baseplate. A finger taps the disc at the right of the picture.

The code

piezo_first_reading.ino

No library. The sketch reads SIGNAL as fast as it can for 20 ms, keeps the highest reading, prints it in millivolts, and starts again. On an ESP32 analogReadMilliVolts does the conversion with the chip's own calibration; on an Uno or a Pico it is arithmetic on the ADC's full scale.

/*
  Piezo-Ceramic Sensor - first reading                  TK59 / /p/tk59

  Two wires: the block needs no supply. Count from the square pad on
  the TinkerBlock board, parts up, header on the left:

    GND    -> GND
    NC     -> nothing   (connected to nothing on the board)
    NC     -> nothing   (nor is this one: there is no VCC pin)
    SIGNAL -> A0 on an Uno, GPIO 34 on an ESP32, GPIO 4 on an
              ESP32-S3, GP26 on a Raspberry Pi Pico

  Arduino IDE
    Tools > Board                 your board, e.g. Arduino Uno
    Tools > Port                  the one that appears when you plug in
    Tools > USB CDC On Boot       Enabled   (ESP32-S3 only)
    Tools > Serial Plotter        at 115200, to see each tap
    No library needed.
*/

// The analog pin SIGNAL is wired to.
// Uno: A0. ESP32: 34. ESP32-S3: 4. Pico: 26.
const int PIEZO_PIN = A0;

// Uno and Pico only: the ADC's full scale, in mV.
// Uno: 5000. Pico: 3300.
const float FULL_SCALE_MV = 5000.0;

// A tap is a hump: up in about a millisecond, down over a
// tenth of a second or so. The highest reading in each 20 ms
// catches the top of it.
const unsigned long WINDOW_MS = 20;

int readMilliVolts() {
#if defined(ARDUINO_ARCH_ESP32)
  return analogReadMilliVolts(PIEZO_PIN);   // calibrated in the chip
#else
  return analogRead(PIEZO_PIN) * FULL_SCALE_MV / 1023.0;
#endif
}

void setup() {
  Serial.begin(115200);
}

void loop() {
  int peak = 0;
  unsigned long start = millis();
  while (millis() - start < WINDOW_MS) {
    int mv = readMilliVolts();
    if (mv > peak) peak = mv;
  }
  Serial.print("mV:");
  Serial.println(peak);
}

Change PIEZO_PIN to the pin you wired SIGNAL to, and FULL_SCALE_MV to 3300 on a Pico. The mV: label names the line on the Serial Plotter. The sketch compiles for an ESP32-S3, an ESP32 and an Uno.

View on GitHub · blocks/tk59-piezo-sensor/arduino/piezo_first_reading/piezo_first_reading.ino @ v1.5

When it does not work

The plot stays at 0 when I tap.

Check SIGNAL is on the bottom pin, farthest from the square pad, and not on the NC beside it, and that PIEZO_PIN names the pin you wired. Then tap the disc itself, firmly, on its face: a tap on the table beside it bends it very little.

The serial monitor stays empty on my ESP32-S3.

Set Tools > USB CDC On Boot to Enabled and upload again. Without it the S3's USB port does not bring up a serial port at boot, so the sketch runs with nowhere to print.

The plot jumps about with nothing touching it.

GND is not wired, so SIGNAL has nothing to be measured against. On an ESP32 a few tens of millivolts of noise at rest is normal; the tap switch in this book ignores anything under 150 mV.

I get garbage characters in the serial monitor.

Set the monitor to 115200 baud, the rate the sketch opens with. The page this book replaces used 9600; either works, but they have to match.

Where this goes next

How often to read, and why a reading every 100 ms misleads.

A tap is a hump →

Edit this page — content/books/piezo-sensor/the-first-reading.mdx

Community

Questions about this product

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

Ask a question ↗

Piezo-Ceramic Sensor

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 →