Skip to content

loopstick/ESP32_V2_Tutorial

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Hands-on ESP32 Tutorial

This tutorial created by Sudhu Tewari 2025

  • from materials originally created by: Michael Shiloh and Judy Castro for Teach Me To Make

Tutorial overview

The tutorial will focus on getting you up and running quickly, so that you will understand the basic procedures for working with your ESP32 (specifically the Adafruit ESP32 Feather v2) and the Arduino IDE and can explore further on your own.

We will cover how to install Arduino on your laptop; how to understand, modify, and write Arduino programs; how to connect input devices and sensors to your ESP32 and read them from a program; and how to connect actuators (LEDs, motors, speakers) and control them from a program. Other topics will be covered as interest dictates and time permits.

Additional Resources

What is Arduino anyway?

What is ESP32?

Start Here

First steps: Verifying correct installation

  1. Connect ESP32 via USB cable

    • Windows? Might see “New Hardware Discovered” and later might see “New Hardware Ready for Use”.
    • Mac OS X? Might see “New Network Interface Found”. Click “Network Preferences…”,  click “Apply”, and when it finishes, click “Close”. It doesn’t matter if the configuration fails.
    • Linux? Nothing to do here
  2. Open Arduino software (IDE)

  3. Select Tools -> Board

    • You have a Adafruit ESP32 Feather.
  4. Select Tools -> Serial Port

    • Windows? Chose the largest COM number
    • Mac OS X? Choose dev/cu.usbserial******* or /dev/cu.SLAB_USDtoUART
    • Linux? There is only one choice
  5. Open File->Examples->Basics->Blink

    • Click “Upload”
    • Look for errors in the bottom window of the program
    • Look for an amber LED blinking rapidly and a red LED blinking slowly on the other side of the USB connector

Is this thing really on?

Copy the code below into a new Arduino sketch or download and open this example sketch: HelloWorld.ino

/*
  Hello World
  A "Hello, World!" program generally is a computer program that
	outputs or displays the message "Hello, World!".
	Such a program is very simple in most programming languages,
	and is often used to illustrate the basic syntax of a programming language.
	It is often the first program written by people learning to code
*/

void setup() {
//initialize serial communications at 9600 baud rate
Serial.begin(9600);
}

void loop(){
//send 'Hello, world!' over the serial port
Serial.println("Hello, world!");
//wait 100 milliseconds so we don't drive ourselves crazy
delay(1000);
}

The Serial commands allow Arduino to send a message to your laptop. In order to see this message you need to open the Serial Monitor by clicking on the magnifying glass near the top right corner.

a little code anatomy:

  • the setup() function is called when a sketch starts.

    • Use it to initialize variables, pin modes, start using libraries, etc.
    • The setup() function will only run once, after each powerup or reset of the Arduino board.
  • the loop() function does precisely what its name suggests, and loops consecutively through your list of instructions to control the Arduino.

    • Arduino only executes one instruction at a time

More on specific functions and variables soon! Let's make something happen in the real world first.

How to use Arduino to turn something ON and OFF

How does the program (sketch) do this? (all described in the Blink tutorial)

/*
  Blink

  Turns an LED on for one second, then off for one second, repeatedly.

  Most Arduino boards have an on-board LED you can control.
  On the ESP32 Feather V2 it is attached to digital pin 13

  This example code is modified from.
  https://www.arduino.cc/en/Tutorial/BuiltInExamples/Blink
*/

int led = 13;  // define a variable to hold the pin number of the internal LED

// the setup function runs once when you press reset or power the board
void setup() {
  // initialize digital pin "led" as an output.
  pinMode(led, OUTPUT);
}

// the loop function runs over and over again forever
void loop() {
  digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);                       // wait for a second
  digitalWrite(led, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);                       // wait for a second
}

Where is the LED that we're turning on and off???

feather v2 builtin LED some more code anatomy - info about an Arduino Sketch

Exercise:
  • combine HelloWorld and Blink to make a program that shows it's working with physical and digital output.

Connecting to your Microcontroller - Pinouts

In order to connect inputs or outputs to your microcontroller you need to know where the GPIO (general-purpose input/output) pins are!

feather v2 pinout

feather v2 pinout

Using a solderless Breadboard to connect your microcontroller to other things (LEDs, motors, speakers, sensors, etc.)

The Solderless Breadboard

Breadboard

Breadboard underside

Breadboard top and bottom

Use the breadboard to add an external LED.

Here’s a picture showing how to connect the LED and resistor on the breadboard:

LED_Breadboard2

Here is another view of this circuit:

ESP32_LED_01

Use the Blink sketch: File -> Examples -> Basics -> Blink

Does the LED on the breadboard blink? (think about why)

Exercise:

Move LED to a different pin (e.g. pin 12). See if you can figure out how to do this on your own

Now the LED won’t blink until you change the program, since the program is only turning pin 13 on and off. Change the program to control pin 8.

Exercise:

If you changed the program to control only pin 8, then the built-in LED on pin 13 is no longer blinking. Can you change the program to make them both blink?

Are we limited to LEDs? No; we could replace the LED (and its resistor) with any other suitable device, with some considerations. We’ll learn more about this later.

How to read a switch from a GPIO: digitalRead()

  • Switches

  • digitalRead()

    ESP32_BTN_LED

    /*
    DigitalReadSerial
    Reads a digital input on pin A0, prints the result to the Serial Monitor
    This example code is in the public domain.
    http://www.arduino.cc/en/Tutorial/DigitalReadSerial
    */
    
      // A0 has the pushbutton attached to it. Give it a name:
      int pushButton = A0;
    
      // the setup routine runs once when you press reset:
      void setup() {
       // initialize serial communication at 9600 bits per second:
    	Serial.begin(9600);
       // make the pushbutton's pin an input:
    	pinMode(pushButton, INPUT);
      }
    
      // the loop routine runs over and over again forever:
      void loop() {
       // read the input pin:
    	int buttonState = digitalRead(pushButton);
       // print out the state of the button:
       Serial.println(buttonState);
       delay(1);        // delay in between reads for stability
      }
Exercises:
  • Write an IF statement to turn the LED on when the button is pushed.
  • Write an IF statement to toggle the LED when the button is pushed a certain number of times.

How to use a sensor: analogRead()

So far we’ve only used Arduino as an output device, to control something in the physical world (the LED). The other way of interfacing to the physical world is as an input device, using a sensor to get information about the physical world. We’ll start with a photoresistor, also called a light dependent resistor or LDR. It’s a resistor whose resistance depends on the light: the more light, the lower the resistance. (The resistor we used above with the LED is a fixed resistor.) The LDR indicates the amount of light by changing its resistance, but Arduino can not measure resistance. But, Arduino can measure voltage! Fortunately, we can easily convert a varying resistance to a varying voltage using a fixed resistor to create a voltage divider. This time the fixed resistor needs a larger resistance, so select a 10k ohm resistor and build the circuit below. You don’t need to remove the LED circuit as there should be room on your breadboard for both, and we’ll use the LED again later.

CircuitExample

Open and upload this sketch: File->Examples->Basics->AnalogReadSerial

How do you know if anything is working? Arduino might be reading the sensor, but is it telling you anything?

Arduino is connected to your computer, so they can communicate - just like we did earlier with Hello World, but now your Ardunio is sending sensor DATA!

  • this line: cpp Serial.println(sensorValue); allows Arduino to send a message to your laptop. In order to see this message you need to open the Serial Monitor by clicking on the magnifying glass near the top right corner. Read the Arduino AnalogRead tutorial to find out more. Also see File->Examples->Communication for more examples of other types of Serial communication).

Now that we've got sensor data coming in (as a range of values) what can we do with the data?

  • ESP32 can measure varying voltage levels between 0 V and 3.3 V.
    • The voltage measured is assigned to a value between 0 and 4095
      • 0V corresponds to 0, and 3.3V corresponds to 4095.
      • Any voltage between 0 V and 3.3 V will be given the corresponding value.
    • We could do some math to calculate the voltage we're measuring: File->Examples->Basics->AnalogReadVoltage
      • we'll need to do some different math to re-configure the stock Arduino example for ESP32
        • Arduino inputs range from 0-1024

That's nice, but what if we want to use the sensor data to control some kind of physical reaction (light, heat, motion) to the data?

Exercise:

Use an IF statement to turn your LED on and off according to the data coming from the LDR.

What other kinds of sensors are there?

IMPORTANT NOTE:

  • When looking for sensors to use
    • be aware that ESP32 is a 3.3V system.
    • Many microcontrollers and sensors are made to run on 5v
      • 5V WILL KILL YOUR ESP32!
    • It is possible to convert 5V sensor outputs to 3.3v
    • It is even easier to use 3.3V compatible sensors

More on Sensors in the near future

Let's shift our focus, now, for a moment, to outputting a range of voltages. Then we'll put the input and output together to get real world input to control real world output.

Sensor ranges, calibration, and mapping

analogWrite(): Controlling speed or brightness

  • If digitalWrite() can turn an LED on and off, and analogRead() can read a range of values, what would you guess analogWrite() might do?

    • You guessed it!
  • analogWrite outputs PWM

    • PWM = pulse width modulation
    • this allows us, effectively, to output any voltage between minimum
      • minimum = 0 volts = 0 in code
      • maximum = 3.3 volts (ESP32) = 255 (@8bit resolution)
  • Arduino: analogWrite() only works on certain pins.

  • ESP32 can output PWM on ANY pin.

Analog Output - PWM - Major Difference between Arduino and ESP32

  • ESP32 uses different functions to call PWM output

    • ledcAttachPin(GPIO, channel)
    • ledcWrite(channel, dutycycle)
  • 16 PWM channels (0-15)

    • variable PWM frequency (5000 is plenty for LEDs)
    • variable duty cycle
      • 8 bits = 0-255
      • this is how you control the intensity of the output
/*
 * PWM example code
 */

// the number of the LED pin
const int ledPin = 12;  // 12 corresponds to GPIO16

// setting PWM properties
// variable PWM frequency (5000 is plenty for LEDs)
const int freq = 5000;
// 16 PWM channels available (0-15)
const int ledChannel = 0;
// 8 bits = 0-255
const int resolution = 8;

void setup(){
  // configure LED PWM functionalitites
  ledcSetup(ledChannel, freq, resolution);

  // attach the channel to the GPIO to be controlled
  ledcAttachPin(ledPin, ledChannel);
}

void loop(){
  // increase the LED brightness
  for(int dutyCycle = 0; dutyCycle <= 255; dutyCycle++){   
    // changing the LED brightness with PWM
    ledcWrite(ledChannel, dutyCycle);
    delay(15);
  }

  // decrease the LED brightness
  for(int dutyCycle = 255; dutyCycle >= 0; dutyCycle--){
    // changing the LED brightness with PWM
    ledcWrite(ledChannel, dutyCycle);   
    delay(15);
  }
}
Exercises:

ESP32_AnalogWrite

Exercises:

RGB LEDs

RGB LEDs are really handy for non-text, non-serial debug and they make really pretty colors!

ESP32_LED_RGB

  • Generally we use a slightly larger resistor (150 ohm) for the RED component and the same slightly smaller resistor values (100 ohm) for the GREEN and BLUE components.

  • for our circuit let's use:

    • 470 ohm for RED
      • color bands-> yellow, purple, black, black, brown
    • 430 ohm for GREEN and BLUE
      • color bands-> yellow, orange, black, black, brown
    • We're using common CATHODE RGB LEDs
  • RGB LED Test Code

  • RGB LED code example using analogWrite()

Some other online information about RGB LEDs

Multi-Tasking - DITCH the DELAY!

  • Using delay() to control timing is probably one of the very first things you learned when experimenting with the Arduino. Timing with delay() is simple and straightforward, but it does cause problems down the road when you want to add additional functionality. The problem is that delay() is a "busy wait" that monopolizes the processor.

  • During a delay() call, you can’t respond to inputs, you can't process any data and you can’t change any outputs. Delay() ties up 100% of the processor. So, if any part of your code uses a delay(), everything else is dead in the water for the duration.

What else can PWM do?

  • PWM also works well to control the speed of a motor.
    • However now we need to consider whether our motor is compatible with our GPIO output "levels".

Interlude: Ohm's Law!

GPIO outputs: Voltage and current

  • When used as outputs, two things must be considered: the voltage and the current. Our ESP32 can deliver 3.3v, and at most 12 or 28mA (250mA maximum for all channels - according to Adafruit).
  • The voltage is determined by the source, but the current is determined by whatever we’re trying to control. In the case of LEDs, they only need 20 mA or less. The motor we have might take more than 40 mA. In the worst case, when it’s stalled, it might want a 200 mA.
  • The important thing to realize is that the microcontroller does not have the ability to limit this current. It will try to deliver whatever is asked of it, even if it overheats and damages itself.
  • If we want to control a device that might take more than 40 mA, we have to use an intermediary.

Can we hook it up like this, with the motor wired directly to the microcontroller??

  • Yes!!

  • Will it probably damage the microcontroller?

    • YES! aka 爆炸!
  • Should we use an intermediary to control the high current?

    • YES!!!!!

Controlling large loads with a transistor

The transistor is like a bicycle gear: you control it with a small amount of current, and it in turn can control a lot more current. The transistor also allows us to use a higher voltage than the 3.3V the ESP32 can deliver.

Use a transistor to control a higher current for a motor.

  • There are hundreds of transisors that will work for this application.
  • never assume the pinout of a transistor or IC.
    • ALWAYS look up the pinout before applying power.
      • or else 爆炸

Here's the pinout for a TIP 120 Darlington transistor, rated for up to 60V and 5A

You can test this with any of the code above for driving an LED:

  • just send an analogWrite to pin 12.

It's important to note that we are now using USB as the power source for the motor.

  • For small motors this is probably okay.
  • For larger motors that require more current (>500ma), your computer will probably complain about a device using too much power and will disconnect the USB.
  • It is a much better practice to get in the habit of using a separate power source for the motor.

References:


H-Bridge Motor Driver

  • The H-Bridge is a circuit that allows us to control the direction of a motor as well as its speed.

Hbridge GIF

L298N H-Bridge Motor Driver

  • The L298N is a popular H-Bridge motor driver that can be used with the Arduino.
  • The L298N has 2 H-Bridges, which means it can control 2 motors.
  • The L298N can handle up to 2A per channel, and up to 35V.

notes:

  • on many L298N modules, the power input is labeled 12v

    • but it can handle up to 35v
    • and it can run as low as 4.5v
  • since motors take a significant amount of current, we'll use a separate power source for the motor(s)

    • this external source can be a power supply or a battery pack (or USB for SMALL motors)
    • the microcontroller will send data to the Hbridge to switch on/off the larger voltage/current
  • We can power the motor(s) with an external power supply

    • match the power supply voltage to the motor voltage
    • you'll also need to consider the motor's current draw and provide sufficient amperage
    • the manufacturer's specification should provide this information

L298N H-Bridge Motor Driver with 5v

When using 5V or less for motor voltage (muscles) or less we must also provide 5V to the L298 IC (brains).

  • we can get 5v from the USB pin on our ESP32V2
    • note: this only works if you have USB connected to a USB power source (computer or charging brick)

L298N H-Bridge Motor Driver with 7-24V

  • When using more than 7V the L298N can get the 5v it needs to operate from an onboard voltage regulator
    • most voltage regulators need about 2v more than their output voltage
      • in this special case we can --probably-- use the L298's onboard voltage regulator to provide 5V for our ESP32

ESP32V2_L298N_Simple

Hbridge example code:


NeoPixels (low-current)

NeoPixels are individually addressable (WS2812B) RGB LEDs that can be chained together to create a string of lights. They are very bright and can be used to create a wide range of colors. They are available in a variety of form factors, including strips, rings, and matrices. They are typically controlled by a single data line and can be powered by 5V. That said, our Arduino can only supply a limited amount of current, so we need to be careful when powering neoPixels.

If you want to understand addressable LEDs (aka neoPixels), read this guide!!

We can start with a simple test to get familiar with the NeoPixel library. When we're ready to control larger numbers of NeoPixels, we'll need to consider power requirements and how to power them safely.

NeoPixel example code:

If you are using more than 8 neopixels you must power them with an external power supply!

  • or else 爆炸

Also, it is very worthwhile to follow the Best Practices given in the Adafruit NeoPixel Uberguide


Servo

Servo motors are a simple and easy way to add motion to your Arduino project.

  • They 'know' their own position which makes them easy to control
  • they are not that powerful (although larger, more power servos do exist)

Servo motors have three wires: power, ground, and signal. The power wire is typically red, the ground wire is typically black or brown, and the signal wire is typically yellow, orange or white.

Since the ESP32 can supply limited current at only 3.3V, and servos draw considerable power, we will connect servo power to the USB pin of the ESP32 to use 5v from our computer.

We -could- connect servo power to the BAT (battery) pin of the ESP32, but this is ONLY appropriate for SMALL servos and will draw down the battery power quickly.

We can also connect servo power to a separate external power source (as long as we connect all of the grounds (ESP32, servo, and external power). In this example, we just connect ESP32 ground to servo ground.

The servo signal pin connects to any available GPIO pins on the ESP32 (in this example, we use pin 14).

Servo_Potentiometer_v2_bb.png

The 'standard' Arduino servo library doesn't work with ESP32 so we'll need to install another library: https://docs.arduino.cc/libraries/esp32servo/

  • Use library manager in Arduino IDE
  • or download the library .zip file and unzip into your Arduino/libraries folder

Servo example code:

Note: Min and Max angles Different servos require different pulse widths to vary servo angle, but the range is an approximately 500-2500 microsecond pulse every 20ms (50Hz). In general, hobbyist servos sweep 180 degrees, so the lowest number in the published range for a particular servo represents an angle of 0 degrees, the middle of the range represents 90 degrees, and the top of the range represents 180 degrees. So for example, if the range is 1000us to 2000us, 1000us would equal an angle of 0, 1500us would equal 90 degrees, and 2000us would equal 1800 degrees. If you find that your servo does not move from 0 to 180 degrees, adjust the min and max values in the code to match your needs. In the example above this adjustment has been made to match the micro servos in your kits.


Let's Go Crazy (Let's Get Nuts)*

ESP32V2_MotorServoNeoPixel_bb.png

Let's combine circuits and code for the DC motor, servo, and Neopixel!! In this example EVERYTHING is running on 5V from from power supply and we're using the L298 terminal block as a way to connect ALL the power and grounds leads to one another.

example code:


Roopa's excellent ESP32 V2 webAPI example (including how to connect to Berkeley IoT)

https://github.com/roopa-ramanujam/ESP32-web-api-example



More to explore


Resources!!!

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published