The first read
Three wires, no library and a sketch that reads the pin as fast as loop() can go and prints a line every time it changes to HIGH. Knock the table once and several lines appear, a few milliseconds apart: that is the spring ringing, and the rest of the book is about it.
Three wires
GND to GND. VCC to your board's logic supply: 5V on an Uno, 3V3 on the three 3.3 V boards. SIGNAL to a digital pin. NC stays unconnected.
The input pin is the same in every sketch in this book, and the same as the TK17 collision sensor's: D2 on an Uno, GPIO 25 on an ESP32, GPIO 4 on an ESP32-S3, GP15 on a Pico. None of them is read by the chip at boot or tied up with its flash memory, so a knock while the board starts cannot stop it starting. On an Uno, D2 is also one of the two pins that can raise an interrupt, which a later sketch needs.
The sketch
pinMode(KNOCK_PIN, INPUT) makes the pin an input with nothing of its own
switched on, because the block already has its pull-down.
digitalRead(KNOCK_PIN) returns HIGH or LOW: HIGH is the spring
touching the rod.
The sketch prints only when the reading changes from LOW to HIGH, the start
of a pulse, and it never waits. Both matter. A sketch that printed on every
pass while SIGNAL is HIGH would print dozens of lines per pulse; a sketch
with a delay(100) in it would be asleep for almost every pulse, because
each one lasts about a millisecond.
What you should see
Open the serial monitor at 115200 and knock the table next to the block, firmly, once. Then once more. Something like this, though your times and counts will differ:
4212 ms pulse 1
4214 ms pulse 2
4217 ms pulse 3
4220 ms pulse 4
6031 ms pulse 5
6033 ms pulse 6
6036 ms pulse 7Two knocks, seven lines. The first four came within ten milliseconds of each other; that is one knock, with the spring touching the rod four times. The next article counts each burst as one.
The code
No library. pinMode makes the pin an input and digitalRead returns HIGH or LOW. The sketch remembers the last reading, so it can print on the change to HIGH rather than on every pass while SIGNAL is HIGH. Change KNOCK_PIN to the pin you wired SIGNAL to.
/*
Knock Sensor - first read TK28 / /p/tk28
Wiring. Count from the square pad on the TinkerBlock board, switch
at the top, header at the bottom:
GND -> GND
VCC -> 5V on an Uno; 3V3 on an ESP32, ESP32-S3 or Pico
(during a knock, SIGNAL gives your pin whatever VCC is)
NC -> nothing (unconnected on the board)
SIGNAL -> D2 on an Uno, GPIO 25 on an ESP32, GPIO 4 on an
ESP32-S3, GP15 on a Raspberry Pi Pico
Arduino IDE
Tools > Board your board, e.g. ESP32S3 Dev Module
Tools > Port the one that appears when you plug in
Tools > USB CDC On Boot Enabled (ESP32-S3 only)
No library needed.
*/
// The GPIO number SIGNAL is wired to.
// Uno: 2. ESP32: 25. ESP32-S3: 4. Pico: 15.
const int KNOCK_PIN = 4;
int last = LOW; // the reading last time round
unsigned long pulses = 0;
void setup() {
Serial.begin(115200);
pinMode(KNOCK_PIN, INPUT); // the block has its own pull-down
}
void loop() {
int level = digitalRead(KNOCK_PIN);
if (level == HIGH && last == LOW) { // a change to HIGH: a pulse
pulses++;
Serial.print(millis());
Serial.print(" ms pulse ");
Serial.println(pulses);
}
last = level; // never waits: a pulse is about 1 ms
}INPUT, not INPUT_PULLUP: the block has its own 10 kΩ pull-down, and the chip's pull-up would fight it. There is no delay() anywhere: a pulse lasts about a millisecond, and a sketch that sleeps misses it.
The same read in MicroPython, for an ESP32, an ESP32-S3 or a Pico. Pin.IN makes the pin an input and value() returns 1 or 0. It prints on the change from 0 to 1.
"""
Knock Sensor - first read, MicroPython TK28 / /p/tk28
Wiring. Count from the square pad on the TinkerBlock board, switch
at the top, header at the bottom:
GND -> GND
VCC -> 3V3 (never 5V: during a knock, SIGNAL gives your pin VCC)
NC -> nothing (unconnected on the board)
SIGNAL -> GPIO 25 on an ESP32, GPIO 4 on an ESP32-S3,
GP15 on a Raspberry Pi Pico
Thonny
Run > Configure interpreter MicroPython (ESP32) or
MicroPython (Raspberry Pi Pico)
Save it to the board as main.py to run it on every power-up.
Nothing to install: machine and time are built in.
"""
from machine import Pin
import time
# The GPIO number SIGNAL is wired to. ESP32: 25. ESP32-S3: 4. Pico: 15.
KNOCK_PIN = 4
knock = Pin(KNOCK_PIN, Pin.IN) # no pull: the block has its own
last = 0 # the reading last time round
pulses = 0
while True:
level = knock.value()
if level == 1 and last == 0: # a change to HIGH: a pulse
pulses += 1
print(time.ticks_ms(), "ms pulse", pulses)
last = level # never waits: a pulse is about 1 msThere is no Uno here: an Uno cannot run MicroPython. No pull argument: the block's own pull-down holds SIGNAL LOW. MicroPython is slower than C, a few tens of microseconds a pass, which is still well inside a pulse. Stop it with Ctrl-C in Thonny's shell.
When it does not work
Watch the red LED while you knock the board itself firmly. If it never flickers, VCC or GND is not connected, or the cable is one pin over. If it flickers, SIGNAL is on a different pin from the one KNOCK_PIN names: the number is the GPIO number printed beside the pin, not its position along the header.
That is right, and it is the point of this sketch. The spring swings back and forth and touches the rod several times for one knock, and each touch is a separate change to HIGH. The next article counts a knock once.
Each pulse lasts about a millisecond. A loop that sleeps for 100 ms reads the pin ten times a second and is asleep for almost all of every pulse. Keep loop() free of delay(), or move the reading into an interrupt, which is the article after next.
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 red LED flickering tells you the block itself is fine.
Edit this page — content/books/knock-sensor/the-first-read.mdx
Questions about this product
See what other owners have asked, and read their solutions.
Knock 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.