C - Tutorial Pages 119 211
C - Tutorial Pages 119 211
This project reads the value of the touch sensor and prints it out.
Component List
Breadboard x1
Jumper M/M x1
Related knowledge
Touch sensor
ESP32's touch sensor supports up to 10 GPIO channels as capacitive touch pins. Each pin can be used
separately as an independent touch switch or be combined to produce multiple touch points. The following
table is a list of available touch pins on ESP32.
Name of touch sensing signal Functions of pins GPIO number
T0 GPIO4 GPIO4
T1 GPIO0 GPIO0
T2 GPIO2 GPIO2
T3 MTDO GPIO15
T4 MTCK GPIO13
T5 MTDI GPIO12
T6 MTMS GPIO14
T7 GPIO27 GPIO27
T8 32K_XN GPIO33
T9 32K_XP GPIO32
The touch pin number is already defined in ESP32's code base. For example, in the code, you can use T0 to
represent GPIO4.
The electrical signals generated by touch are analog data, which are converted by an internal ADC converter.
You may have noticed that all touch pins have ADC functionality.
The hardware connection method is shown in the following figure.
Circuit
Schematic diagram
Hardware connection. If you need any support, please feel free to contact us via: [email protected]
Sketch
Sketch_10.1_TouchRead
Download the code to ESP32-WROVER, open the serial monitor, and set the baud rate to 115200. As shown
in the following figure,
Touched by hands, the value of the touch sensor will change. The closer the value is to zero, the more
obviously the touch action will be detected. The value detected by the sensor may be different in different
environments or when different people touch it. The code is very simple, just look at Reference.
Reference
uint16_t touchRead(uint8_t pin);
Read touch sensor value. (values close to 0 mean touch detected)
In this project, we will use ESP32's touch sensor to create a touch switch lamp.
Component List
Breadboard x1
Circuit
Schematic diagram
Hardware connection. If you need any support, please feel free to contact us via: [email protected]
Sketch
Sketch_10.2_TouchLamp
Download the code to ESP32-WROVER, open the serial monitor, and set the baud rate to 115200. As shown
in the following figure,
With a touch pad, the state of the LED changes with each touch, and the detection state of the touch sensor
is printed in the serial monitor.
25 }
26
27 void reverseGPIO(int pin) {
28 digitalWrite(pin, ! digitalRead(pin));
29 }
The closer the return value of the function touchRead() is to 0, the more obviously the touch is detected. This
is not a fixed value, so you need to define a threshold that is considered valid (when the value of the sensor
is less than this threshold). Similarly, a threshold value is to be defined in the release state, and a value in
between is considered an invalid disturbance value.
2 #define PRESS_VAL 14 //Set a threshold to judge touch
3 #define RELEASE_VAL 25 //Set a threshold to judge release
In loop(), first determine whether the touch was detected. If yes, print some messages, flip the state of the
LED, and set the flag bit isProcessed to true to avoid repeating the program after the touch was successful.
11 if (touchRead(T0) < PRESS_VAL) {
12 if (! isProcessed) {
13 isProcessed = true;
14 Serial.println("Touch detected! ");
15 reverseGPIO(PIN_LED);
16 }
17 }
It then determines if the touch key is released, and if so, prints some messages and sets the isProcessed to
false to avoid repeating the process after the touch release and to prepare for the next touch probe.
19 if (touchRead(T0) > RELEASE_VAL) {
20 if (isProcessed) {
21 isProcessed = false;
22 Serial.println("Released! ");
23 }
24 }
In this project, we will make a soft light. We will use an ADC Module to read ADC values of a potentiometer
and map it to duty cycle of the PWM used to control the brightness of a LED. Then you can change the
brightness of a LED by adjusting the potentiometer.
Component List
Breadboard x1
Circuit
Schematic diagram
Hardware connection. If you need any support, please feel free to contact us via: [email protected]
Sketch
Sketch_11.1_Softlight
Download the code to ESP32-WROVER, by turning the adjustable resistor to change the input voltage of
GPIO25, ESP32 changes the output voltage of GPIO4 according to this voltage value, thus changing the
brightness of the LED.
The following is the code:
1 #define PIN_ANALOG_IN 4
2 #define PIN_LED 25
3 #define CHAN 0
4 void setup() {
5 ledcSetup(CHAN, 1000, 12);
6 ledcAttachPin(PIN_LED, CHAN);
7 }
8
9 void loop() {
10 int adcVal = analogRead(PIN_ANALOG_IN); //read adc
11 int pwmVal = adcVal; // adcVal re-map to pwmVal
12 ledcWrite(CHAN, pwmVal); // set the pulse width.
13 delay(10);
14 }
In the code, read the ADC value of potentiometer and map it to the duty cycle of PWM to control LED
brightness.
In this project, 3 potentiometers are used to control the RGB LED and in principle it is the same as the Soft
Light project. Namely, read the voltage value of the potentiometer and then convert it to PWM used to control
LED brightness. Difference is that the original project only controlled one LED, but this project required (3)
RGB LEDs.
Component List
Breadboard x1
Circuit
Schematic diagram
Hardware connection. If you need any support, please feel free to contact us via: [email protected]
Sketch
Sketch_11.2_SoftColorfulLight
Download the code to ESP32-WROVER, rotate one of the potentiometers, then the color of RGB LED will
change.
If you have any concerns, please contact us via: [email protected]
In the code you can read the ADC values of the 3 potentiometers and map it into a PWM duty cycle to control
the 3 LED elements to vary the color of their respective RGB LED.
Component List
Breadboard x1
Circuit
Schematic diagram
Hardware connection. If you need any support, please feel free to contact us via: [email protected]
Sketch
Sketch_11.3_Soft_Rainbow_Light
Download the code to ESP32-WROVER, rotate the handle of the potentiometer, and the color of the lamp
ring will change.
The overall logical structure of the code is the same as the previous project rainbow light, except that the
starting point of the color in this code is controlled by potentiometer.
A photoresistor is very sensitive to the amount of light present. We can take advantage of the characteristic
to make a nightlight with the following function: when the ambient light is less (darker environment) the LED
will automatically become brighter to compensate and when the ambient light is greater (brighter
environment) the LED will automatically dim to compensate.
Component List
Breadboard x1
Component knowledge
Photoresistor
A photoresistor is simply a light sensitive resistor. It is an active component that decreases resistance with
respect to receiving luminosity (light) on the component's light sensitive surface. A photoresistor’s resistance
value will change in proportion to the ambient light detected. With this characteristic, we can use a
photoresistor to detect light intensity. The photoresistor and its electronic symbol are as follows.
The circuit below is used to detect the change of a photoresistor’s resistance value:
In the above circuit, when a photoresistor’s resistance vale changes due to a change in light intensity, the
voltage between the photoresistor and resistor R1 will also change. Therefore, the intensity of the light can
be obtained by measuring this voltage.
Circuit
The circuit of this project is similar to project Soft Light. The only difference is that the input signal is changed
from a potentiometer to a combination of a photoresistor and a resistor.
Schematic diagram
Hardware connection. If you need any support, please feel free to contact us via: [email protected]
Sketch
The circuit used is similar to the project Soft Light. The only difference is that the input signal of the AIN0 pin
of ADC changes from a potentiometer to a combination of a photoresistor and a resistor.
Sketch_12.1_Nightlamp
Download the code to ESP32-WROVER, if you cover the photoresistor or increase the light shining on it, the
brightness of the LED changes accordingly.
If you have any concerns, please contact us via: [email protected]
Reference
constrain(amt,low,high)
#define constrain(amt,low,high) ((amt)<(low)? (low):((amt)>(high)? (high):(amt)))
Constrain the value amt between low and high.
Chapter 13 Thermistor
In this chapter, we will learn about thermistors which are another kind of resistor
A thermistor is a type of resistor whose resistance value is dependent on temperature and changes in
temperature. Therefore, we can take advantage of this characteristic to make a thermometer.
Component List
Breadboard x1
Component knowledge
Thermistor
A thermistor is a temperature sensitive resistor. When it senses a change in temperature, the resistance of the
thermistor will change. We can take advantage of this characteristic by using a thermistor to detect
temperature intensity. A thermistor and its electronic symbol are shown below.
1 1
Rt = R ∗ EXP[ B ∗ ( − ) ]
T2 T1
Where:
Rt is the thermistor resistance under T2 temperature;
R is the nominal resistance of thermistor under T1 temperature;
EXP[n] is nth power of E;
B is for thermal index;
T1, T2 is Kelvin temperature (absolute temperature). Kelvin temperature=273.15 + Celsius temperature.
For the parameters of the thermistor, we use: B=3950, R=10k, T1=25.
The circuit connection method of the thermistor is similar to photoresistor, as the following:
We can use the value measured by the ADC converter to obtain the resistance value of thermistor, and then
we can use the formula to obtain the temperature value.
Therefore, the temperature formula can be derived as:
1 𝑅𝑡
T2 = 1/( + ln( )/𝐵)
T1 R
Circuit
The circuit of this project is similar to the one in the last chapter. The only difference is that the photoresistor
is replaced by the thermistor.
Schematic diagram
Hardware connection. If you need any support, please feel free to contact us via: [email protected]
Sketch
Sketch_13.1_Thermometer
Download the code to ESP32-WROVER, the terminal window will display the current ADC value, voltage value
and temperature value. Try to “pinch” the thermistor (without touching the leads) with your index finger and
thumb for a brief time, you should see that the temperature value increases.
If you have any concerns, please contact us via: [email protected]
In the code, the ADC value of ADC module A0 port is read, and then calculates the voltage and the resistance
of thermistor according to Ohms Law. Finally, it calculates the temperature sensed by the thermistor,
according to the formula.
This project uses the function in esp-idf to get more accurate temperature value. The circuit is exactly the
same as the last project.
Sketch
Sketch_13.2_Thermometer
Download the code to ESP32-WROVER, the terminal window will display the current ADC value, voltage value
and temperature value. Try to “pinch” the thermistor (without touching the leads) with your index finger and
thumb for a brief time, you should see that the temperature value increases.
If you have any concerns, please contact us via: [email protected]
22 adc2_config_channel_atten((adc2_channel_t)channel, atten);
23 }
24
25 //Characterize ADC
26 adc_chars = (esp_adc_cal_characteristics_t*)calloc(1,
27 sizeof(esp_adc_cal_characteristics_t));
28 esp_adc_cal_value_t val_type = esp_adc_cal_characterize(unit, atten, ADC_WIDTH_BIT_12,
29 DEFAULT_VREF, adc_chars);
30
31 }
32
33 void loop() {
34 uint32_t adc_reading = 0;
35 //Multisampling
36 for (int i = 0; i < NO_OF_SAMPLES; i++) {
37 if (unit == ADC_UNIT_1) {
38 adc_reading += adc1_get_raw((adc1_channel_t)channel);
39 }
40 else {
41 int raw;
42 adc2_get_raw((adc2_channel_t)channel, ADC_WIDTH_BIT_12, &raw);
43 adc_reading += raw;
44 }
45 }
46 adc_reading /= NUM_OF_SAMPLES;
47 //Convert adc_reading to voltage in mV
48 uint32_t voltage = esp_adc_cal_raw_to_voltage(adc_reading, adc_chars);
49 //printf("Raw: %d\tVoltage: %dmV\n", adc_reading, voltage);
50
51 double vol = voltage / 1000.0f;
52 double Rt = 10 * vol / (3.3 - vol); //calculate resistance value of thermistor
53 double tempK = 1 / (1 / (273.15 + 25) + log(Rt / 10) / 3950.0); //calculate temperature
54 (Kelvin)
55 double tempC = tempK - 273.15; //calculate temperature (Celsius)
56 Serial.printf("ADC value : %d,\tVoltage : %.2fV, \tTemperature : %.2fC\n", adc_reading,
vol, tempC);
57
58 delay(1000);
59 }
The part of the code that captures the ADC is consistent with the previous potentiometer section, and the
part that calculates the temperature is consistent with the previous project.
Chapter 14 Joystick
In the previous chapter, we have learned how to use rotary potentiometer. Now, let's learn a new electronic
module joystick which working on the same principle as rotary potentiometer.
In this project, we will read the output data of a joystick and display it to the Terminal screen.
Component List
Breadboard x1
Component knowledge
Joystick
A joystick is a kind of input sensor used with your fingers. You should be familiar with this concept already as
they are widely used in gamepads and remote controls. It can receive input on two axes (Y and or X) at the
same time (usually used to control direction on a two dimensional plane). And it also has a third direction
capability by pressing down (Z axis/direction).
X
Y
This is accomplished by incorporating two rotary potentiometers inside the joystick Module at 90 degrees of
each other, placed in such a manner as to detect shifts in direction in two directions simultaneously and with
a push button switch in the “vertical” axis, which can detect when a User presses on the Joystick.
When the joystick data is read, there are some differences between the axes: data of X and Y axes is analog,
which needs to use the ADC. The data of the Z axis is digital, so you can directly use the GPIO to read this
data or you have the option to use the ADC to read this.
Circuit
Schematic diagram
Hardware connection. If you need any support, please feel free to contact us via: [email protected]
Sketch
In this project’s code, we will read the ADC values of X and Y axes of the joystick, and read digital quality of
the Z axis, then display these out in terminal.
Sketch_14.1_Joystick
Download the code to ESP32-WROVER, open the serial port monitor, the baud rate is 115200, as shown in
the figure below, shift (moving) the joystick or pressing it down will make the data change.
In the code, configure xyzPins[2] to pull-up input mode. In loop(), use analogRead () to read the value of
axes X and Y and use digitalRead () to read the value of axis Z, then display them.
8 int xVal = analogRead(xyzPins[0]);
9 int yVal = analogRead(xyzPins[1]);
10 int zVal = digitalRead(xyzPins[2]);
11 Serial.printf("X,Y,Z: %d,\t%d,\t%d\n", xVal, yVal, zVal);
12 delay(500);
Now let’s learn how to use the 74HC595 IC chip to make a flowing water light using less GPIO.
Component List
Breadboard x1
Related knowledge
74HC595
A 74HC595 chip is used to convert serial data into parallel data. A 74HC595 chip can convert the serial data
of one byte into 8 bits, and send its corresponding level to each of the 8 ports correspondingly. With this
characteristic, the 74HC595 chip can be used to expand the IO ports of a ESP32. At least 3 ports are required
to control the 8 ports of the 74HC595 chip.
Circuit
Schematic diagram
Hardware connection. If you need any support, please feel free to contact us via: [email protected]
Sketch
In this project, we will make a flowing water light with a 74HC595 chip to learn about its functions.
Sketch_15.1_FlowingLight2
Download the code to ESP32-WROVER. You will see that LED bar graph starts with the flowing water pattern
flashing from left to right and then back from right to left.
If you have any concerns, please contact us via: [email protected]
13 // Define a one-byte variable to use the 8 bits to represent the state of 8 LEDs of LED bar
14 graph.
15 // This variable is assigned to 0x01, that is binary 00000001, which indicates only one LED
16 light on.
17 byte x = 0x01; // 0b 0000 0001
18 for (int j = 0; j < 8; j++) { // Let led light up from right to left
19 writeTo595(LSBFIRST, x);
20 x <<= 1; // make the variable move one bit to left once, then the bright LED move one step
21 to the left once.
22 delay(50);
23 }
24 delay(1000);
25 x = 0x80; //0b 1000 0000
26 for (int j = 0; j < 8; j++) { // Let led light up from left to right
27 writeTo595(LSBFIRST, x);
28 x >>= 1;
29 delay(50);
30 }
31 delay(1000);
32 }
33 void writeTo595(int order, byte _data ) {
34 // Output low level to latchPin
35 digitalWrite(latchPin, LOW);
36 // Send serial data to 74HC595
37 shiftOut(dataPin, clockPin, order, _data);
38 // Output high level to latchPin, and 74HC595 will update the data to the parallel output
39 port.
40 digitalWrite(latchPin, HIGH);
41 }
In the code, we configure three pins to control the 74HC595 chip and define a one-byte variable to control
the state of the 8 LEDs (in the LED bar graph Module) through the 8 bits of the variable. The LEDs light ON
when the corresponding bit is 1. If the variable is assigned to 0x01, that is 00000001 in binary, there will be
only one LED ON.
17 x=0x01;
In the loop(), use “for” loop to send x to 74HC595 output pin to control the LED. In "for" loop, x will shift one
bit to the LEFT in one cycle, then when data of x is sent to 74HC595, the LED that is turned ON will move one
bit to the LEFT once.
18 for (int j = 0; j < 8; j++) { // Let led light up from right to left
19 writeTo595(LSBFIRST, x);
20 x <<= 1;
21 delay(50);
22 }
In second “for” loop, the situation is the same. The difference is that x is shift from 0x80 to the RIGHT in order.
The subfunction writeTo595() is used to write data to 74HC595 and immediately output on the port of
74HC595.
Reference
<< operator
"<<" is the left shift operator, which can make all bits of 1 byte shift by several bits to the left (high) direction
and add 0 on the right (low). For example, shift binary 00000001 by 1 bit to left:
byte x = 1 << 1;
← ← ← ← ← ← ←
← 0 0 0 0 0 0 0 1 ← 0
The result of x is 2(binary 00000010).
0 0 0 0 0 0 1 0
There is another similar operator" >>". For example, shift binary 00000001 by 1 bit to right:
byte x = 1 >> 1;
→ → → → → → →
0 → 0 0 0 0 0 0 0 1 →
The result of x is 0(00000000).
0 0 0 0 0 0 0 0
Parameters
dataPin: the pin on which to output each bit. Allowed data types: int.
clockPin: the pin to toggle once the dataPin has been set to the correct value. Allowed data types: int.
bitOrder: which order to shift out the bits; either MSBFIRST or LSBFIRST. (Most Significant Bit First, or, Least
Significant Bit First).
value: the data to shift out. Allowed data types: byte.
We will use 74HC595 to control 7-segment display and make it display hexadecimal character "0-F".
Component List
Breadboard x1
Component knowledge
7-segment display
A 7-segment display is a digital electronic display device. There is a figure "8" and a decimal point represented,
which consists of 8 LEDs. The LEDs have a common anode and individual cathodes. Its internal structure and
pin designation diagram is shown below:
As we can see in the above circuit diagram, we can control the state of each LED separately. Also, by combining
LEDs with different states of ON and OFF, we can display different characters (Numbers and Letters). For
example, to display a “0”: we need to turn ON LED segments A, B, C, D, E and F, and turn OFF LED segments
G and DP.
In this project, we will use a 7-Segment Display with a common anode. Therefore, when there is an input low
level to a LED segment the LED will turn ON. Defining segment “A” as the lowest level and segment “DP” as
the highest level, from high to low would look like this: “DP”, “G”, “F”, “E”, “D”, “C”, “B”, “A”. Character "0"
corresponds to the code: 1100 0000b=0xc0.
For detailed code values, please refer to the following table (common anode).
CHAR DP G F E D C B A Hex ASCII
0 1 1 0 0 0 0 0 0 0xc0 1100 0000
1 1 1 1 1 1 0 0 1 0xf9 1111 1001
2 1 0 1 0 0 1 0 0 0xa4 1010 0100
3 1 0 1 1 0 0 0 0 0xb0 1011 0000
4 1 0 0 1 1 0 0 1 0x99 1001 1001
5 1 0 0 1 0 0 1 0 0x92 1001 0010
6 1 0 0 0 0 0 1 0 0x82 1000 0010
7 1 1 1 1 1 0 0 0 0xf8 1111 1000
8 1 0 0 0 0 0 0 0 0x80 1000 0000
9 1 0 0 1 0 0 0 0 0x90 1001 0000
A 1 0 0 0 1 0 0 0 0x88 1000 1000
B 1 0 0 0 0 0 1 1 0x83 1000 0011
C 1 1 0 0 0 1 1 0 0xc6 1100 0110
D 1 0 1 0 0 0 0 1 0xa1 1010 0001
E 1 0 0 0 0 1 1 0 0x86 1000 0110
F 1 0 0 0 1 1 1 0 0x8e 1000 1110
Circuit
Schematic diagram
Hardware connection. If you need any support, please feel free to contact us via: [email protected]
Sketch
In this section, the 74HC595 is used in the same way as in the previous section, but with different values
transferred. We can learn how to master the digital display by sending the coded value of "0" - "F".
Sketch_16.1_7_Segment_Display
Verify and upload the code, and you'll see a 1-bit, 7-segment display displaying 0-f in a loop.
Component List
Breadboard x1
Component knowledge
The internal electronic circuit is shown below, and all 8 LED cathode pins of each 7-segment display are
connected together.
Display method of 4 digit 7-segment display is similar to 1 digit 7-segment display. The difference between
them is that the 4-digit displays each Digit is visible in turn, one by one and not together. We need to first
send high level to the common end of the first digit display, and send low level to the remaining three
common ends, and then send content to 8 LED cathode pins of the first Digit Display. At this time, the first 7-
segment display will show visible content and the remaining three will be OFF.
Similarly, the second, third and fourth 7-segment displays will show visible content in turn by scanning the
display. Although the four number characters are displayed in turn separately, this process is so fast that it is
imperceptible to the naked eye. This is due to the principle of optical afterglow effect and the vision
persistence effect in human sight. This is how we can see all 4 number characters at the same time. However,
if each number character is displayed for a longer period, you will be able to see that the number characters
are displayed separately.
Circuit
Schematic diagram
Hardware connection:
Sketch
In this code, we use the 74HC595 IC chip to control the 4-digit 7-segment display, and use the dynamic
scanning method to show the changing number characters.
Sketch_16.2_4_Dight_7-Segment_Display
Compile and upload code to ESP32-WROVER, then the digital tube displays as shown.
The usage of the writeData function is the same as in the previous two sections, so it won't be covered again
here.
41 void writeData(int value) {
42 // Make latchPin output low level
43 digitalWrite(latchPin, LOW);
44 // Send serial data to 74HC595
45 shiftOut(dataPin, clockPin, LSBFIRST, value);
46 // Make latchPin output high level, then 74HC595 will update data to parallel output
47 digitalWrite(latchPin, HIGH);
48 }
In the loop function, because there are four digital tubes, a “for loop” is used to display the values of each
one in turn. For example, when i =0, turn ON the first digital tube to display the first value, then turn ON the
second digital tube to display the second value, until all four digital tubes display their own values. Because
the displaying time from the first number to the fourth number is so short, it may display many times in one
second, but our eyes can't keep up with the speed of the digital tube, so we look as if the digital tube is
displaying different Numbers at the same time.
20 void loop() {
21 for (int i = 0; i < 4; i++) {
22 // Select a single 7-segment display
23 electDigitalDisplay(i);
24 // Send data to 74HC595
25 writeData(num[i]);
26 delay(5);
27 // Clear the display content
28 writeData(0xff);
29 }
30 }
If you want to display the decimal point, make the highest bit of each array become 0, which can be
implemented easily by num[i]&0x7f.
45 shiftOut(dataPin,clockPin, LSBFIRST, value & 0x7f);
In this project, we will use two 74HC595 IC chips to control a monochrome (one color) (8X8) LED matrix to
make it display both simple graphics and characters.
Component List
Breadboard x1
Component knowledge
LED Matrix
A LED matrix is a rectangular display module that consists of a uniform grid of LEDs. The following is an 8X8
monochrome (one color) LED matrix containing 64 LEDs (8 rows by 8 columns).
In order to facilitate the operation and reduce the number of ports required to drive this component, the
positive poles of the LEDs in each row and negative poles of the LEDs in each column are respectively
connected together inside the LED matrix module, which is called a common anode. There is another
arrangement type. Negative poles of the LEDs in each row and the positive poles of the LEDs in each column
are respectively connected together, which is called a common cathode.
The LED matrix that we use in this project is a common anode LED matrix.
Connection mode of common anode Connection mode of common cathode
Here is how a common anode LED matrix works. First, choose 16 ports on ESP32 board to connect to the 16
ports of LED matrix. Configure one port in columns for low level, which makes that column the selected port.
Then configure the eight port in the row to display content in the selected column. Add a delay value and
then select the next column that outputs the corresponding content. This kind of operation by column is
called scan. If you want to display the following image of a smiling face, you can display it in 8 columns, and
each column is represented by one byte.
1 2 3 4 5 6 7 8
0 0 0 0 0 0 0 0
0 0 1 1 1 1 0 0
0 1 0 0 0 0 1 0
1 0 1 0 0 1 0 1
1 0 0 0 0 0 0 1
1 0 0 1 1 0 0 1
0 1 0 0 0 0 1 0
0 0 1 1 1 1 0 0
Then, to save the number of GPIO, we use a 74HC595. When the first column is turned ON, set the lights that
need to be displayed in the first column to "1", otherwise to "0", as shown in the above example, where the
value of the first column is 0x1c. This value is sent to 74HC595 to control the display of the first column of the
LED matrix. Following the above idea, turn OFF the display of the first column, then turn ON the second
column, and then send the value of the second column to 74HC595 ...... Until each column is displayed, the
LED matrix is displayed again from the first column.
Circuit
In circuit of this project, the power pin of the 74HC595 IC chip is connected to 3.3V. It can also be connected
to 5V to make LED matrix brighter.
Schematic diagram
Hardware connection:
Sketch
The following code will make LED matrix display a smiling face, and then display scrolling character "0-F".
Download the code to ESP32-WROVER, and the LED matrix display a smiling face, and then display characters
"0 to F" scrolling in a loop on the LED matrix.
Sketch_16.3_LED_Matrix
The following is the program code:
1 int latchPin = 2; // Pin connected to ST_CP of 74HC595(Pin12)
2 int clockPin = 4; // Pin connected to SH_CP of 74HC595(Pin11)
3 int dataPin = 15; // Pin connected to DS of 74HC595(Pin14)
4
5 // Define the pattern data for a smiling face
6 const int smilingFace[] = { //"^ⅴ^"
7 0x1C, 0x22, 0x51, 0x45, 0x45, 0x51, 0x22, 0x14
8 };
9 // Define the data of numbers and letters, and save them in flash area
10 const int data[] PROGMEM = {
11 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // " "
12 0x00, 0x00, 0x21, 0x7F, 0x01, 0x00, 0x00, 0x00, // "1"
13 0x00, 0x00, 0x23, 0x45, 0x49, 0x31, 0x00, 0x00, // "2"
14 0x00, 0x00, 0x22, 0x49, 0x49, 0x36, 0x00, 0x00, // "3"
15 0x00, 0x00, 0x0E, 0x32, 0x7F, 0x02, 0x00, 0x00, // "4"
16 0x00, 0x00, 0x79, 0x49, 0x49, 0x46, 0x00, 0x00, // "5"
17 0x00, 0x00, 0x3E, 0x49, 0x49, 0x26, 0x00, 0x00, // "6"
18 0x00, 0x00, 0x60, 0x47, 0x48, 0x70, 0x00, 0x00, // "7"
19 0x00, 0x00, 0x36, 0x49, 0x49, 0x36, 0x00, 0x00, // "8"
20 0x00, 0x00, 0x32, 0x49, 0x49, 0x3E, 0x00, 0x00, // "9"
21 0x00, 0x00, 0x3E, 0x41, 0x41, 0x3E, 0x00, 0x00, // "0"
22 0x00, 0x00, 0x3F, 0x44, 0x44, 0x3F, 0x00, 0x00, // "A"
23 0x00, 0x00, 0x7F, 0x49, 0x49, 0x36, 0x00, 0x00, // "B"
24 0x00, 0x00, 0x3E, 0x41, 0x41, 0x22, 0x00, 0x00, // "C"
25 0x00, 0x00, 0x7F, 0x41, 0x41, 0x3E, 0x00, 0x00, // "D"
26 0x00, 0x00, 0x7F, 0x49, 0x49, 0x41, 0x00, 0x00, // "E"
27 0x00, 0x00, 0x7F, 0x48, 0x48, 0x40, 0x00, 0x00 // "F"
28 };
29
30 void setup() {
31 // set pins to output
32 pinMode(latchPin, OUTPUT);
33 pinMode(clockPin, OUTPUT);
34 pinMode(dataPin, OUTPUT);
35 }
36
37 void loop() {
38 // Define a one-byte variable (8 bits) which is used to represent the selected state of 8
39 column.
40 int cols;
41 // Display the static smiling pattern
42 for (int j = 0; j < 500; j++ ) { // repeat 500 times
43 cols = 0x01;
44 for (int i = 0; i < 8; i++) { // display 8 column data by scanning
45 matrixRowsVal(smilingFace[i]);// display the data in this column
46 matrixColsVal(~cols); // select this column
47 delay(1); // display them for a period of time
48 matrixRowsVal(0x00); // clear the data of this column
49 cols <<= 1; // shift "cols" 1 bit left to select the next column
50 }
51 }
52 // Display the dynamic patterns of numbers and letters
53 for (int i = 0; i < 128; i++) {
54 for (int k = 0; k < 10; k++) { // repeat image of each frame 10 times.
55 cols = 0x01; // Assign binary 00000001. Means the first column is selected.
56 for (int j = i; j < 8 + i; j++) { // display image of each frame
57 matrixRowsVal(pgm_read_word_near(data + j));// display the data in this column
58 matrixColsVal(~cols); // select this column
59 delay(1); // display them for a period of time
60 matrixRowsVal(0x00); // close the data of this column
61 cols <<= 1; // shift "cols" 1 bit left to select the next column
62 }
63 }
64 }
65 }
66
67 void matrixRowsVal(int value) {
68 // make latchPin output low level
69 digitalWrite(latchPin, LOW);
70 // Send serial data to 74HC595
71 shiftOut(dataPin, clockPin, LSBFIRST, value);
72 // make latchPin output high level, then 74HC595 will update the data to parallel output
73 digitalWrite(latchPin, HIGH);
74 }
76
77 void matrixColsVal(int value) {
78 // make latchPin output low level
79 digitalWrite(latchPin, LOW);
80 // Send serial data to 74HC595
81 shiftOut(dataPin, clockPin, MSBFIRST, value);
82 // make latchPin output high level, then 74HC595 will update the data to parallel output
83 digitalWrite(latchPin, HIGH);
84 }
The first “for” loop in the “while” loop is used to display a static smile. Displaying column information from left
to right, one column at a time with a total of 8 columns. This repeats 500 times to ensure sufficient display
time.
40 int cols;
41 // Display the static smiling pattern
42 for (int j = 0; j < 500; j++ ) { // repeat 500 times
43 cols = 0x01; // Assign 0x01(binary 00000001) to the variable, which represents the first
44 column is selected.
45 for (int i = 0; i < 8; i++) { // display 8 column data by scanning
46 matrixRowsVal(smilingFace[i]); // display the data in this column
47 matrixColsVal(~cols); // select this column
48 delay(1); // display them for a period of time
49 cols <<= 1; // shift "cols" 1 bit left to select the next column
50 }
51 }
The second “for” loop is used to display scrolling characters "0 to F", for a total of 17* 8 = 144 columns.
Displaying the 0-8 column, then the 1-9 column, then the 2-10 column...... and so on…128-136 column in
consecutively to achieve the scrolling effect. The display of each frame is repeated a certain number of times
and the more repetitions, the longer the single frame display will be and the slower the scrolling movement.
52 // Display the dynamic patterns of numbers and letters
53 for (int i = 0; i < 128; i++) {
54 for (int k = 0; k < 10; k++) { // repeat image of each frame 10 times.
55 cols = 0x01; // Assign binary 00000001. Means the first column is selected.
56 for (int j = i; j < 8 + i; j++) { // display image of each frame
57 matrixRowsVal(pgm_read_word_near(data + j));// display the data in this column
58 matrixColsVal(~cols); // select this column
59 delay(1); // display them for a period of time
60 matrixRowsVal(0x00); // close the data of this column
61 cols <<= 1; // shift "cols" 1 bit left to select the next column
62 }
63 }
64 }
The amount of pins of ESP32 is limited, so you need to find ways to save pins. If you use ESP32’s GPIO to
control the lattice without using 74HC595, you need 16 pins for the use of LED matrix. In this example, we
use two 74HC595 to drive the LED matrix, requiring only three pins, so that we could save the rest of 13
pins.
In this project, we will use a push button switch indirectly to control the motor via a relay.
Component List
Breadboard x1
Component knowledge
Relay
A relay is a safe switch which can use low power circuit to control high power circuit. It consists of
electromagnet and contacts. The electromagnet is controlled by low power circuit and contacts are used in
high power circuit. When the electromagnet is energized, it will attract contacts.
The following is a schematic diagram of a common relay and the feature and circuit symbol of a 5V relay used
in this project:
Diagram Feature: Symbol
Pin 5 and pin 6 are connected to each other inside. When the coil pins 3 and 4 get connected to 5V power
supply, pin 1 will be disconnected to pin 5&6 and pin 2 will be connected to pin 5&6. So pin 1 is called close
end, pin 2 is called open end.
Inductor
The symbol of Inductance is “L” and the unit of inductance is the “Henry” (H). Here is an example of how
this can be encountered: 1H=1000mH, 1mH=1000μH.
An inductor is an energy storage device that converts electrical energy into magnetic energy. Generally, it
consists of winding coil, with a certain amount of inductance. Inductors hinder the change of current passing
through it. When the current passing through it increases, it will attempt to hinder the increasing trend of
current; and when the current passing through it decreases, it will attempt to hinder the decreasing trend of
current. So the current passing through inductor is not transient.
The reference circuit for relay is as follows. The coil of relays can be equivalent to that of inductors, when the
transistor disconnects power supply of the relay, the current in the coil of the relay can't stop immediately,
causing an impact on power supply. So a parallel diode will get connected to both ends of relay coil pin in
reversing direction, then the current will pass through diode, avoiding the impact on power supply.
Motor
A motor is a device that converts electrical energy into mechanical energy. Motor consists of two parts: stator
and rotor. When motor works, the stationary part is stator, and the rotating part is rotor. Stator is usually the
outer case of motor, and it has terminals to connect to the power. Rotor is usually the shaft of motor, and can
drive other mechanical devices to run. Diagram below is a small DC motor with two pins.
When a motor gets connected to the power supply, it will rotate in one direction. Reverse the polarity of
power supply, then the motor rotates in opposite direction.
+ - - +
Circuit
Schematic diagram
Hardware connection. If you need any support, please feel free to contact us via: [email protected]
Note: the motor circuit uses A large current, about 0.2-0.3A without load.We recommend that you
use a 9V battery to power the extension board.
Sketch
Download the code to ESP32-WROVER. When the DC motor is connected to a power supply, it will rotate in
one direction. If you reverse the polarity of the power supply, the DC motor will rotate in opposite direction.
+ - - +
The following is the program code:
1 int relayPin = 13; // the number of the relay pin
2 int buttonPin = 15; // the number of the push button pin
3
4 int buttonState = HIGH; // Record button state, and initial the state to high level
5 int relayState = LOW; // Record relay state, and initial the state to low level
6 int lastButtonState = HIGH; // Record the button state of last detection
7 long lastChangeTime = 0; // Record the time point for button state change
8
9 void setup() {
10 pinMode(buttonPin, INPUT_PULLUP); // Set push button pin into input mode
11 pinMode(relayPin, OUTPUT); // Set relay pin into output mode
12 digitalWrite(relayPin, relayState); // Set the initial state of relay into "off"
13 }
14 void loop() {
15 int nowButtonState = digitalRead(buttonPin);// Read current state of button pin
16 // If button pin state has changed, record the time point
17 if (nowButtonState ! = lastButtonState) {
18 lastChangeTime = millis();
19 }
20 // If button state changes, and stays stable for a while, then it should have skipped the
21 bounce area
22 if (millis() - lastChangeTime > 10) {
23 if (buttonState ! = nowButtonState) { // Confirm button state has changed
24 buttonState = nowButtonState;
25 if (buttonState == LOW) { // Low level indicates the button is pressed
26 relayState = ! relayState; // Reverse relay state
27 digitalWrite(relayPin, relayState); // Update relay state
28 }
29 }
30 }
31 lastButtonState = nowButtonState; // Save the state of last button
32 }
In Chapter 2, the pressing and releasing of the button will result in mechanical vibrating. If we don't solve this
problem, some unexpected consequences may happen to the procedure. Click here to return to Chapter 2
Button & LED
To eliminate the vibrating, we record the electrical level of the button with nowButtonState, and the time point
for the last change of pin level with lastChangeTime If the state of the button changes, it will record the time
point of the change.
15 int nowButtonState = digitalRead(buttonPin);// Read current state of button pin
16 // If button pin state has changed, record the time point
17 if (nowButtonState ! = lastButtonState) {
18 lastChangeTime = millis();
19 }
If the state of the pin changes and keeps stable for a period of time, it can be considered as a valid key state
change, update the key state variable buttonState, and determine whether the key is pressed or released
according to the current state.
15 // If button state changes, and stays stable for a while, then it should have skipped the
16 bounce area
17 if (millis() - lastChangeTime > 10) {
18 if (buttonState ! = nowButtonState) { // Confirm button state has changed
19 buttonState = nowButtonState;
20 if (buttonState == LOW) { // Low level indicates the button is pressed
21 relayState = ! relayState; // Reverse relay state
22 digitalWrite(relayPin, relayState); // Update relay state
23 }
24 }
25 }
26 lastButtonState = nowButtonState; // Save the state of last button
Component List
Breadboard x1
Component knowledge
L293D
L293D is an IC chip (Integrated Circuit Chip) with a 4-channel motor drive. You can drive a unidirectional DC
motor with 4 ports or a bi-directional DC motor with 2 ports or a stepper motor (stepper motors are covered
later in this Tutorial).
When using L293D to drive DC motor, there are usually two connection options.
The following connection option uses one channel of the L239D, which can control motor speed through
the PWM, However the motor then can only rotate in one direction.
The following connection uses two channels of the L239D: one channel outputs the PWM wave, and the
other channel connects to GND, therefore you can control the speed of the motor. When these two channel
signals are exchanged, not only controls the speed of motor, but also can control the steering of the motor.
GND
GND
In practical use the motor is usually connected to channel 1 and 2 by outputting different levels to in1 and
in2 to control the rotational direction of the motor, and output to the PWM wave to Enable1 port to control
the motor’s rotational speed. If the motor is connected to channel 3 and 4 by outputting different levels to
in3 and in4 to control the motor's rotation direction, and output to the PWM wave to Enable2 pin to control
the motor’s rotational speed.
Circuit
Use caution when connecting this circuit, because the DC motor is a high-power component, do not use the
power provided by the ESP32 to power the motor directly, which may cause permanent damage to your
ESP32! The logic circuit can be powered by the ESP32 power or an external power supply, which should share
a common ground with ESP32.
Schematic diagram
Hardware connection. If you need any support, please feel free to contact us via: [email protected]
Note: the motor circuit uses A large current, about 0.2-0.3A without load.We recommend that you
use a 9V battery to power the extension board.
Sketch
Sketch_17.2_Control_Motor_by_L293D
Download code to ESP32-WROVER, rotate the potentiometer in one direction and the motor speeds up
slowly in one direction. And then rotate the potentiometer in the other direction and the motor will slow down
to stop. And then rotate it in an inverse direction to accelerate the motor.
2048
number 2048 as the midpoint. If the value of ADC is less than 2048, make the motor rotate in one direction.
If the value of ADC is greater than 2048, make the motor rotate in the other direction. Subtract 2048 from the
ADC value and take the absolute value and use this result as the speed of the motor.
20 int potenVal = analogRead(A0);// Convert the voltage of rotary potentiometer into digital
21 rotationSpeed = potenVal - 2048;
22 if (potenVal > 2048)
23 rotationDir = true;
24 else
25 rotationDir = false;
26 // Calculate the motor speed
27 rotationSpeed = abs(potenVal - 2048);
28 //Control the steering and speed of the motor
29 driveMotor(rotationDir, constrain(rotationSpeed,0,2048));
30 }
Set the accuracy of the PWM to 11 bits and range from 0 to 2047 to control the rotation speed of the motor.
15 ledcSetup(channel,1000,11); //Set PWM to 11 bits, range is 0-2047
Function driveMotor is used to control the rotation direction and speed of the motor. The dir represents
direction while spd refers to speed.
34 void driveMotor(boolean dir, int spd) {
35 // Control motor rotation direction
36 if (rotationDir) {
37 digitalWrite(in1Pin, HIGH);
38 digitalWrite(in2Pin, LOW);
39 }
40 else {
41 digitalWrite(in1Pin, LOW);
42 digitalWrite(in2Pin, HIGH);
43 }
44 // Control motor rotation speed
45 ledcWrite(channel, spd);
46 }
Chapter 18 Servo
Previously, we learned how to control the speed and rotational direction of a motor. In this chapter, we will
learn about servos which are a rotary actuator type motor that can be controlled to rotate to specific angles.
Component List
Breadboard x1
Component knowledge
Servo
Servo is a compact package which consists of a DC motor, a set of reduction gears to provide torque, a sensor
and control circuit board. Most servos only have a 180-degree range of motion via their “horn”. Servos can
output higher torque than a simple DC motor alone and they are widely used to control motion in model cars,
model airplanes, robots, etc. Servos have three wire leads which usually terminate to a male or female 3-pin
plug. Two leads are for electric power: positive (2-VCC, Red wire), negative (3-GND, Brown wire), and the
signal line (1-Signal, Orange wire), as represented in the Servo provided in your Kit.
We will use a 50Hz PWM signal with a duty cycle in a certain range to drive the Servo. The lasting time of
0.5ms-2.5ms of PWM single cycle high level corresponds to the servo angle 0 degrees - 180 degree linearly.
Part of the corresponding values are as follows:
High level time Servo angle
0.5ms 0 degree
1ms 45 degree
1.5ms 0 degree
2ms 45 degree
2.5ms 180 degree
When you change the servo signal value, the servo will rotate to the designated angle.
Circuit
Use caution when supplying power to the servo, it should be 5V. Make sure you do not make any errors when
connecting the servo to the power supply.
Schematic diagram
Hardware connection. If you need any support, please feel free to contact us via: [email protected]
Sketch
Use the ESP32Servo library to control the servo motor and let the servo motor rotate back and forth.
Sketch_18.1_Servo_Sweep
Compile and upload the code to ESP32-WROVER, the servo will rotate from 0 degrees to 180 degrees and
then reverse the direction to make it rotate from 180 degrees to 0 degrees and repeat these actions in an
endless loop.
Component List
Breadboard x1
Circuit
Use caution when supplying power to the servo, it should be 5V. Make sure you do not make any errors when
connecting the servo to the power supply.
Schematic diagram
Hardware connection. If you need any support, please feel free to contact us via: [email protected]
Sketch
Sketch_18.2_Servo_Sweep
Compile and upload the code to ESP32-WROVER, twist the potentiometer back and forth, and the servo
motor rotates accordingly.