ESP32 S3 UNO - Force Sensor

This ESP32 S3 Uno force sensor tutorial shows you how to wire a force sensor to the ESP32 S3 Uno form board and measure how hard you press it with Arduino code. A force sensor is also called a force sensing resistor, force sensitive resistor or FSR. When you press it, the board prints a number and a label like "light touch" or "big squeeze" in the Serial Monitor.

In this tutorial, you will:

  1. Learn how a force sensing resistor (FSR) works
  2. Wire the force sensor and a 10 kΩ resistor to the ESP32 S3 Uno
  3. Read the pressure with analogRead() in Arduino IDE
  4. Turn the raw analog value into simple pressure levels
ESP32 S3 Uno force sensor

Hardware Preparation

1×ESP32 S3 Uno-form Board
1×USB Cable Type-A to Type-C (for USB-A PC)
1×USB Cable Type-C to Type-C (for USB-C PC)
1×Force Sensor
1×10 kΩ Resistor
1×Breadboard
1×Jumper Wires

Or you can buy the following kits:

1×DIYables Sensor Kit (18 sensors/displays)
Disclosure: Some of the links provided in this section are Amazon affiliate links. We may receive a commission for any purchases made through these links at no additional cost to you.
Additionally, some of these links are for products from our own brand, DIYables .

Overview of Force Sensor

Before you wire anything, it helps to know what the sensor really measures. A force sensor does not give you grams or pounds. It gives you a resistance that changes with pressure.

Force sensor pinout

People call this part a force sensing resistor, a force sensitive resistor, or just an FSR. It is a thin, flat resistor. Its resistance changes when you push on the round sensing area.

The sensor is cheap and very easy to use. It is great for detecting a touch, a press or a squeeze. It is not good for measuring exact weight, so do not use it as a kitchen scale. You can find FSRs in electronic drums, phones, handheld game controllers and many other small devices.

Pinout

The force sensor has only two pins. It acts like a normal resistor, so the two pins are the same. You can connect it either way round.

How It Works

The force sensor works like a resistor whose value depends on pressure. With no pressure, the resistance is very high. The harder you press, the lower the resistance between its two pins.

When you put the sensor in series with a fixed 10 kΩ resistor, the two parts form a voltage divider. More pressure means lower FSR resistance, so the voltage at the middle point goes up. The ESP32 S3 Uno reads this voltage on an analog pin.

ESP32 S3 Uno Pinout

The image below shows the pinout diagram of the ESP32 S3 Uno form board. Use it to find the Uno header pins (A0, 3.3V, GND…) and their GPIO numbers when you wire the circuit.

ESP32 S3 Uno pinout diagram

Wiring Diagram

One leg of the force sensor goes to 3.3V. The other leg goes to analog pin A0, and a 10 kΩ pull-down resistor connects that same point to GND.

The wiring diagram between ESP32 S3 Uno Force Sensor

This image is created using Fritzing. Click to enlarge image

Component Pin ESP32 S3 Uno Pin
Force Sensor Pin 1 3.3V
Force Sensor Pin 2 and 10 kΩ resistor A0 (GPIO2)
Other end of 10 kΩ resistor GND

WARNING

Power the force sensor from the 3.3V pin, not 5V. When you press hard, the voltage on A0 gets close to the supply voltage. The ESP32 S3 Uno pins are not 5V tolerant, so 5V on A0 can damage the board.

How To Program For Force Sensor

The program only needs one function to read the sensor. The real work is turning the number into something useful.

The ESP32 S3 Uno has analog input pins A0 to A5. Each one turns a voltage from 0V to about 3.3V into a whole number from 0 to 4095. This number is called the ADC value or analog value. The ESP32 S3 Uno ADC is 12-bit, so the range is bigger than the 0 to 1023 range on many other Arduino boards.

Because the force sensor is wired to A0, you can call analogRead() on that pin. A bigger number means more pressure on the sensor.

ESP32 S3 Uno Code

The sketch reads the force sensor on A0 (GPIO2) once every second. It prints the raw value, then compares it with four limits and prints a pressure level, from "no pressure" up to "big squeeze".

/* * This ESP32 S3 Uno code was developed by newbiely.com * * This ESP32 S3 Uno code is made available for public use without any restriction * * For comprehensive instructions and wiring diagrams, please visit: * https://newbiely.com/tutorials/esp32-s3-uno/esp32-s3-uno-force-sensor */ #define FORCE_SENSOR_PIN 2 // The ESP32 S3 Uno pin A0 (GPIO2) connected to the FSR force sensor with 10K pulldown void setup() { Serial.begin(9600); // set the ADC attenuation to 11 dB (up to ~3.3V input) analogSetAttenuation(ADC_11db); } void loop() { int analogReading = analogRead(FORCE_SENSOR_PIN); Serial.print("Force sensor reading = "); Serial.print(analogReading); // print the raw analog reading if (analogReading < 40) // from 0 to 39 Serial.println(" -> no pressure"); else if (analogReading < 800) // from 40 to 799 Serial.println(" -> light touch"); else if (analogReading < 2000) // from 800 to 1999 Serial.println(" -> light squeeze"); else if (analogReading < 3200) // from 2000 to 3199 Serial.println(" -> medium squeeze"); else // from 3200 to 4095 Serial.println(" -> big squeeze"); delay(1000); }

In setup(), the code calls analogSetAttenuation(ADC_11db). By default, the ESP32 S3 Uno ADC can only measure a small voltage. With 11 dB attenuation, the analog pin reads the full range from 0V up to about 3.3V. Without this line, the reading hits 4095 too early and the force values look wrong.

The limits in the code (40, 800, 2000 and 3200) are made for the 0 to 4095 range. Every FSR is a little different, so feel free to change them for your own sensor.

Detailed Instructions

Follow these steps one by one:

  1. New to the ESP32 S3 Uno? Follow ESP32 S3 Uno - Getting Started first.
  2. Wire it up as shown in the diagram.
  3. Connect the board to your computer with a USB Type-C cable.
  4. Open Arduino IDE, choose the ESP32S3 Dev Module board and the correct COM port.
  5. Copy the code above and paste it into Arduino IDE.
  6. Upload the code by clicking the Upload button.
Arduino IDE Upload Code
  1. Open the Serial Monitor and set the baud rate to 9600.
  2. Press the force sensor with different strength.
  3. Check the result in the Serial Monitor.
∞
Newbiely | Arduino IDE 2.3.8
──
☐
✕
File
Edit
Sketch
Tools
Help
ESP32S3 Dev Module
Newbiely.ino
···
8 Serial.println("Hello World!");
Output
Serial Monitor
Message (Enter to send message to 'ESP32S3 Dev Module' on 'COM15')
New Line
9600 baud
Force sensor reading = 0 -> no pressure Force sensor reading = 0 -> no pressure Force sensor reading = 528 -> light touch Force sensor reading = 590 -> light touch Force sensor reading = 1576 -> light squeeze Force sensor reading = 1684 -> light squeeze Force sensor reading = 2428 -> medium squeeze Force sensor reading = 3164 -> medium squeeze Force sensor reading = 3684 -> big squeeze Force sensor reading = 3948 -> big squeeze Force sensor reading = 0 -> no pressure Force sensor reading = 0 -> no pressure
Ln 11, Col 1
ESP32S3 Dev Module on COM15
2
  1. Tip: Press the sensor in the middle of the round area. Pressing near the edge or on the tail gives low and unstable values.

Video Tutorial

Watch the video below to see this ESP32 S3 Uno project step by step.

The demo in the video goes one step further. It shows the force level on 8 LEDs (D2 to D9) and as a battery-style bar on an SSD1306 OLED display. The OLED uses the SDA (GPIO8) and SCL (GPIO9) header pins. Here is the ESP32 S3 Uno code for the demo:

/* * This ESP32 S3 Uno code was developed by newbiely.com * * This ESP32 S3 Uno code is made available for public use without any restriction * * For comprehensive instructions and wiring diagrams, please visit: * https://newbiely.com/tutorials/esp32-s3-uno/esp32-s3-uno-force-sensor */ #include <Wire.h> #include <Adafruit_GFX.h> #include <Adafruit_SSD1306.h> // OLED display configuration #define SCREEN_WIDTH 128 #define SCREEN_HEIGHT 64 #define OLED_RESET -1 Adafruit_SSD1306 display( SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET ); // Force-sensitive resistor input #define FORCE_SENSOR_PIN 2 // ESP32 S3 Uno pin A0 (GPIO2) // LED pins used to indicate force level const int ledPins[8] = { 18, 17, 19, 20, 3, 14, 21, 46 // D2, D3, D4, D5, D6, D7, D8, D9 }; // Calibrated force sensor range const int FORCE_MIN = 0; const int FORCE_MAX = 4000; // 12-bit ADC (0-4095) // Exponential moving average filter float smoothValue = 0; const float alpha = 0.3; // Initialize hardware and display void setup() { Serial.begin(115200); // set the ADC attenuation to 11 dB (up to ~3.3V input) analogSetAttenuation(ADC_11db); // Configure LED outputs and turn all LEDs off. for (int i = 0; i < 8; i++) { pinMode(ledPins[i], OUTPUT); digitalWrite(ledPins[i], LOW); } // Initialize the OLED using I2C communication (SDA = GPIO8, SCL = GPIO9). if (!display.begin( SSD1306_SWITCHCAPVCC, 0x3C )) { Serial.println("OLED failed!"); // Stop execution if the OLED cannot be initialized. while (1); } display.clearDisplay(); display.setTextColor(SSD1306_WHITE); // Display startup screen. display.setTextSize(2); display.setCursor(20, 25); display.println("DIYables"); display.display(); delay(1500); // Initialize the filter with the first sensor reading // to prevent an incorrect initial value. smoothValue = analogRead(FORCE_SENSOR_PIN); } void loop() { // Read the current FSR value. int rawValue = analogRead(FORCE_SENSOR_PIN); // Apply exponential moving average filtering // to reduce sensor noise and fluctuations. smoothValue = alpha * rawValue + (1.0 - alpha) * smoothValue; int forceValue = (int)smoothValue; // Convert the sensor value into 8 force levels. int level = map( forceValue, FORCE_MIN, FORCE_MAX, 0, 8 ); level = constrain(level, 0, 8); // Turn on LEDs progressively according to the force level. for (int i = 0; i < 8; i++) { if (i < level) { digitalWrite(ledPins[i], HIGH); } else { digitalWrite(ledPins[i], LOW); } } // Output sensor data for monitoring and calibration. Serial.print("FSR = "); Serial.print(forceValue); Serial.print(" | Level = "); Serial.println(level); // Refresh OLED display. display.clearDisplay(); // Display title. display.setTextSize(2); display.setCursor(50, 0); display.println("FSR"); // Configure the force indicator as a battery-style bar. int barX = 10; int barY = 25; int barWidth = 108; int barHeight = 18; // Draw the outer bar. display.drawRect( barX, barY, barWidth, barHeight, SSD1306_WHITE ); // Draw the battery terminal. display.fillRect( barX + barWidth, barY + 5, 4, 8, SSD1306_WHITE ); // Calculate the filled portion based on the force level. int fillWidth = map( level, 0, 8, 0, barWidth - 4 ); if (fillWidth > 0) { display.fillRect( barX + 2, barY + 2, fillWidth, barHeight - 4, SSD1306_WHITE ); } // Display current force level. display.setTextSize(1); display.setCursor(5, 50); display.print("LEVEL: "); display.print(level); display.print("/8"); // Display project branding. display.setCursor(78, 50); display.print("DIYables"); display.display(); // Short delay for stable display updates. delay(30); }

WARNING

The demo uses D6 (GPIO3) and D9 (GPIO46) for two of the LEDs. These are boot strapping pins. The board reads them at startup to choose the boot mode. If the board does not boot or upload, unplug the LEDs on D6 and D9, upload the code, then plug them back in.

FAQ

Can a force sensor measure weight in grams with the ESP32 S3 Uno?

Not really. An FSR is good for detecting touch and comparing "light" and "hard" presses. Its output changes from sensor to sensor and drifts over time. For real weight, use a load cell with an HX711 amplifier.

Why does the ESP32 S3 Uno read 0 to 4095 instead of 0 to 1023?

The ESP32 S3 Uno has a 12-bit ADC, so analogRead() returns a number from 0 to 4095. The UNO R4 uses 0 to 1023 by default. If you copy limits from code for that board, multiply them by about 4, or the pressure levels will be wrong.

Why does the code call analogSetAttenuation(ADC_11db)?

It sets the ESP32 S3 Uno ADC input range to about 0V to 3.3V, so the full force sensor signal maps to 0 to 4095. Without it, the range is smaller and the reading reaches 4095 with only a light press. The UNO R4 does not need this line, because it is only for ESP32 boards. Keep the sensor output at 3.3V or less.

Why do I need the 10 kΩ resistor?

The resistor and the FSR make a voltage divider. Without it, A0 is floating when nobody presses the sensor, and the reading jumps around randomly. The 10 kΩ resistor pulls A0 down to 0 when there is no pressure.

Can I power the force sensor from 5V on the ESP32 S3 Uno?

No. With a hard press, the voltage on A0 gets close to the supply voltage. The ESP32 S3 Uno pins are not 5V tolerant, so 5V can damage the analog pin. Always use the 3.3V pin.

What if my project needs more pins than the Uno headers give?

The ESP32 S3 Uno has two extra rows of holes with more GPIOs. GPIO15 and GPIO16 support I/O, PWM and analog, so they are the best choice for a second or third force sensor. GPIO45 and GPIO35 to GPIO42 support I/O and PWM, so they work well for extra LEDs. GPIO47 and GPIO48 are output only with PWM, so never use them for a sensor. Solder pin headers to these holes and write the GPIO number in code. Be careful with two things. First, GPIO47 and GPIO48 may run at 1.8V instead of 3.3V on some modules (especially ones with "V" in the name, like R8V or R16V), so 3.3V devices can be damaged or act strangely. Second, GPIO0, GPIO3 (D6), GPIO45 and GPIO46 (D9) are boot strapping pins, and a wrong connection can stop the board from booting or uploading code. Use the other extra pins first.

Troubleshooting

Problem Possible Cause Solution
No COM port shows in Arduino IDE USB driver missing or charge-only cable Install the CP210x or CH340 driver and use a USB data cable
Upload fails or times out Board is not in download mode Hold the BOOT button, press and release RESET, then upload again
Reading is always 0 Sensor leg is not connected to 3.3V or A0 is wired to the wrong row Check that one leg goes to 3.3V and the other leg goes to A0 (GPIO2)
Reading jumps around with no pressure 10 kΩ pull-down resistor is missing Connect the 10 kΩ resistor between A0 and GND
Reading reaches 4095 with a light press Attenuation line is missing Keep analogSetAttenuation(ADC_11db) in setup()
Values change a lot for the same press Pressing near the edge or the sensor tail is bent Press the middle of the round area and do not bend the tail near the pins
Serial Monitor shows strange characters Wrong baud rate Set the Serial Monitor to 9600 baud (115200 for the demo code)
Demo board does not boot or upload LEDs on the boot strapping pins D6 or D9 Unplug the LEDs on D6 (GPIO3) and D9 (GPIO46) while uploading

Learn More

※ OUR MESSAGES

  • As freelancers, We are AVAILABLE for HIRE. See how to outsource your project to us
  • Please feel free to share the link of this tutorial. However, Please do not use our content on any other websites. We invested a lot of effort and time to create the content, please respect our work!