5. Arduino Project Practice
5.1 Control an LED
In this practice, we will use Arduino to perform one of the most basic operations—turning an LED light on and off. We will learn how to control the LED using digital output and how to write code to make the LED blink.
5.1.1 Components of an LED
An LED (Light Emitting Diode) is a semiconductor light source, and its main structure includes the following components:
- Housing: Usually made of plastic or glass, used to protect internal components.
- Emitting Material: The core part of the LED, made from special semiconductor materials such as the common InGaN (Indium Gallium Nitride) or AlInGaP (Aluminum Indium Gallium Phosphide).
- Chip: The light-emitting diode chip that generates light.
- Leads: Metal wires that provide electrical connections.
- Solder Points: The soldered points that connect the LED chip to the leads.
- Electrodes: Responsible for connecting the semiconductor material to the external circuit, typically made of metal.
- Reflector Cavity: A structure used to enhance the light emission effect by reflecting the emitted light to the front.
5.1.2 Principle of LED Emission
The principle of LED (Light Emitting Diode) emission is based on semiconductor characteristics. In semiconductors, there are two types of charge carriers: electrons (in n-type semiconductors) and holes (in p-type semiconductors). When n-type and p-type semiconductor materials come into contact, a junction is formed at the interface. When an appropriate voltage is applied, holes and electrons in the junction can recombine and release energy. This energy is emitted in the form of photons, producing light.
5.1.3 Principle of LED Driving
LED driving refers to providing the appropriate current and voltage to the LED through a stable power source to ensure it operates properly and lights up. There are mainly two driving methods: constant current and constant voltage. The constant current drive, which limits the current, is the most common method because LEDs are sensitive to current; exceeding their rated current may cause damage. Constant current driving ensures a stable current, thereby ensuring the safety of the LED.
Driving an LED is relatively simple; you just need to connect the corresponding positive and negative terminals to the microcontroller's positive and negative terminals. The connection methods for LEDs can be divided into two types: sinking current and sourcing current.
- The current injection refers to the power supply current for the LED being provided externally, flooding the current into our MCU. The risk is that if there are changes in the external power supply, it may cause damage to the MCU's pins.
- The output current refers to the voltage and current provided by the MCU, outputting current to the LED. If the MCU's GPIO is used to directly drive the LED, the driving capability may be weak and might not provide sufficient current to drive the LED.
It is important to note that different colors of LEDs correspond to different voltages. The current should not be too high, and a current-limiting resistor of about 220 ohms to 10K ohms is usually required. The larger the resistance of the limiting resistor, the dimmer the LED will be.
5.1.4 LED light schematic diagram
In the schematic diagram of the development board, the output current connection method is used, but the output current provider is provided by an LM358 chip on the development board.
The LM358 is a widely used dual-channel operational amplifier (op-amp). It is commonly used in various electronic circuits to provide the function of amplifying signals. Each LM358 chip contains two independent operational amplifiers in a single IC package and can operate independently. It is favored for its cost-effectiveness, stability, ease of use, and wide operating voltage range.
We will look at the following circuit from the perspective of a comparator. In a comparator configuration, the operational amplifier is not used to provide precise gain as a linear amplifier but rather as a switch, meaning its output has only two states: high level (typically close to the supply voltage) or low level (close to ground voltage).
In this circuit, the LM358 is used as a comparator. The working principle of the comparator is as follows:
- When the voltage at the non-inverting input (pin 5) is greater than the voltage at the inverting input (pin 6), the output of the operational amplifier (pin 7) will be high.
- When the voltage at the non-inverting input (pin 5) is less than the voltage at the inverting input (pin 6), the output of the operational amplifier (pin 7) will be low.
In the schematic below, the inverting input (pin 6) is connected to the output (pin 7), forming a positive feedback loop. In a comparator configuration, this type of connection creates a switch with hysteresis, meaning that a significant voltage difference between the input terminals is required to change the output state. This helps stabilize the output and prevents frequent switching caused by noise or oscillations in the input voltages (further details on positive feedback circuits can be found online). In practical applications, this configuration of the LM358 will result in the LED lighting upwhen the GPIO output level is higher than the voltage at the connection point between the output and the inverting input. when the GPIO output level is lower than this point, the LED will turn off. Due to hysteresis, the actual turn-off level may be slightly lower than the level when the LED is on.
In the schematic, SCK corresponds to GPIO13. From the LED driving principle, we can see that we only need to control the GPIO13 pin of the development board to output a high level to light up the LED.
5.1.5 Introduction to API
In Arduino, you can set the GPIO13 pin to output mode by calling the pinMode(pin, mode)
function, and then use the digitalWrite(pin, value)
function to set the GPIO13 pin to output either a high or low level.
5.1.6 Setting Pin Mode
pinMode()
is a function in the Arduino programming language used to set the operational mode of a specified pin. Its syntax is as follows:
pinMode(pin,mode);
In this function, pin
refers to the pin number you want to configure; mode
specifies the operational mode, which can be one of the following:
- INPUT: Configures the specified pin as an input mode to receive external signals or sensor data. In this mode, the pin reads the voltage level of the external signal. Note that the pin may be floating, leading to unstable readings. To mitigate this, external pull-up or pull-down resistors can be used, or the built-in pull-up resistor can be enabled (see below).
- INPUT_PULLUP: Sets the pin to built-in pull-up input mode. In this mode, the pin is connected to an internal pull-up resistor, keeping the floating pin at a high level. The reading switches to LOW when the external level is low.
- OUTPUT: Configures the specified pin as an output mode to send electrical signals or control external devices. In this mode, the pin can output high (HIGH) or low (LOW) levels. This is used to drive LEDs, relays, and other external devices.
- INPUT_PULLDOWN: Sets the pin to built-in pull-down input mode. In this mode, Arduino connects a resistor to ground at the input to ensure the input pin is always at a low level. When the external circuit is unconnected or in a high-impedance state, the Arduino input pin remains at a low level.
Here’s an example code for using the pinMode
function:
// Set pin 6 as output mode
pinMode(6, OUTPUT);
// Set pin 2 as input mode
pinMode(2, INPUT);
2
3
4
In the above example, the first line of code sets GPIO pin 6 to output mode, allowing it to be used for controlling external devices. The second line sets GPIO pin 2 to input mode, enabling it to receive signals from external sensors.
5.1.7 Setting Pin Output
digitalWrite()
is a function in the Arduino programming language used to set the level of a digital pin. It allows you to change a pin's level to either HIGH or LOW. When the pin is set to OUTPUT mode, this function can affect the components connected to that pin.
The syntax of the function is:
digitalWrite(pin, value);
Pay attention:
pin
: The number of the digital pin you want to write to.value
: The level you want to set, which can beHIGH
orLOW
.HIGH
represents a high level, whileLOW
represents a low level.
For instance:
pinMode(13, OUTPUT); // Set pin 13 to OUTPUT mode
digitalWrite(13, HIGH); // Set digital pin 13 output to HIGH (high level)
2
In the above example, the first line of code sets pin 13 (GPIO13) to OUTPUT mode, and then the second line of code sets the voltage level of pin 13 to HIGH, resulting in an output of 3.3V at pin 13.
Note that if you do not first use the
pinMode()
function to set the pin to OUTPUT, calling thedigitalWrite()
function may have no effect.
❓What are digital pins?
Digital pins are a type of input/output (I/O) pin found in microcontrollers (not limited to Arduino) or other electronic devices. As the name suggests, digital pins handle binary, discrete levels, typically categorized as HIGH (high level, such as 5V or 3.3V) and LOW (low level, such as 0V or ground). The primary purpose of these pins is to communicate, control, or detect interactions with other digital devices or components.
5.1.8 Programming in Arduino
- Open Arduino IDE (Integrated Development Environment).
- Connect the Arduino development board to the USB port of the computer.
- Enter the following code in the IDE:
// Define the Arduino pin connected to the positive pole of the LED
const int ledPin = 13;
// The setup function runs when the Arduino board is restarted or powered on
void setup()
{
// Set the mode of ledPin pin to output mode
pinMode(ledPin, OUTPUT);
}
// The loop function continues to run in a loop after the setup is run.
void loop()
{
// Turn on the LED
digitalWrite(ledPin, HIGH);
// Wait for 1000 milliseconds (1 second)
delay(1000);
// turn off LED
digitalWrite(ledPin, LOW);
// Wait for 1000 milliseconds (1 second)
delay(1000);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
- Select the correct Arduino board type and port in the IDE. Note that the ports are not exactly the same. Please connect according to the port of your own development board. You can determine which port it is by repeatedly plugging and unplugging.
- Upload the code to the Arduino board (use the IDE's upload button).
5.1.9 Practice Outcome
When the Arduino board is powered and the above program is successfully uploaded, the LED in this example will begin to blink at 1-second intervals. That is, the LED will light up for 1 second and then turn off for 1 second, and this process will continuously repeat.
This simple experiment is a great start to learning about electronics and programming, and many complex projects start with controlling an LED light like this.
5.2 Digital input and output practice
In this practice, we will implement a simple project: when a button is pressed, an LED light will light up. This project will teach you how to configure the Arduino's digital inputs and outputs, and will show you how to use them in a real-world project.
Materials List
- 1 x ColorEasyDuino development board
- 1 x breadboard
- 1 x LED light
- 1 x 220Ω resistor
- 1 x button
- 2 x 10kΩ resistors (pull-up resistors for buttons, not necessarily required, but recommended)
- Some jumper Wires
5.2.1 Basics of Independent Keys
Independent keys are simple input devices widely used in various electronic devices to enable basic user interactions. They typically work based on a simple mechanical switch that triggers certain actions when pressed. Independent keys come in various sizes, shapes, and colors to facilitate user recognition and usage.
5.2.2 Structure of Independent Keys
The main structural components of an independent key include: button, casing, spring, contact points, conductive sheet, and pins. It consists of an elastic element (such as a spring or metal sheet) and a keycap. When the key is pressed by the user, the elastic element compresses, causing the keycap to press down and bringing the top of the button closer to or in contact with the base. When the user releases the button, the elastic element returns to its original shape, and the key returns to its initial position. Therefore, when the key is not pressed, the contact points are typically separated, and the circuit is open. When the key is pressed, the conductive sheet touches the contact points, thus forming a closed circuit.
5.2.3 Driving Principle of Independent Keys
The driving principle of an independent key is to enable the microcontroller to recognize the key's state. Since microcontrollers can detect high and low levels, most keys are connected with one end to a high level and the other to a GPIO pin, or one end to a low level and the other to a GPIO pin. By monitoring changes in the voltage level at the pins connected to the key, it can be determined whether the key is pressed.
5.2.4 Debouncing Measures
Mechanical keys can produce mechanical vibrations (similar to a spring) when closing and opening, leading to rapid fluctuations in the switch state, a phenomenon known as key bouncing. Debouncing measures can be categorized into software debouncing and hardware debouncing:
- Software Debouncing: This approach uses programming techniques to set a delay or timer, ensuring that the key state is read only once within a specified time frame, thereby avoiding the effects of bouncing on the program.
- Hardware Debouncing: This involves adding components such as resistors and capacitors to the key circuit to form an RC low-pass filter, which smooths out the key signal and reduces the impact of bouncing.
5.2.5 Hardware Connections
Step 1: Connect the LED
- Insert the longer leg of the LED (anode) into a slot on the breadboard.
- Connect one end of a 220Ω resistor to the shorter leg of the LED (cathode) and the other end to the GND pin on the Arduino.
- Use a jumper wire to connect the longer leg of the LED (anode) to a digital output pin on the Arduino, such as D13.
Step 2: Connect the Button
- Connect one pin of the button to GND.
- Connect the other pin of the button to a digital input pin on the Arduino, such as D2.
- (Optional) To ensure that the input reads high when the button is not pressed, you can add a 10kΩ resistor as a pull-up resistor, connecting the pin (not the one connected to GND) to +5V.
If your Arduino board has built-in pull-up resistor functionality, you can enable it in the software to eliminate the need for a physical pull-up resistor.
To represent the wiring in a schematic diagram:
In the above schematic diagram, one side of the button is connected to a high level of +5V through the pull-up resistor R1, while the other side is connected to GPIO pin 2. The other side of the circuit is connected to GND (low level). This simplifies the key circuit of the development board, resulting in the diagram below.
When the development board is powered on, the GPIO2 pin will be at a high level due to the pull-up resistor R1. Therefore, when the button is not pressed, GPIO2 defaults to a high level. When the button is pressed, it closes the circuit, connecting GPIO2 to GND. Thanks to the presence of R1, this does not create a short circuit, so GPIO2 changes to a low level.
5.2.6 Introduction to API
A General Workflow for Driving an Independent Key:
- Initialize the GPIO of the microcontroller as input.
- Detect the key state (either through polling or interrupt triggering).
- If bouncing occurs, apply debouncing measures.
- Execute the corresponding program code based on the key state.
- After completing the operation, wait for the next key trigger.
❓What are polling and interrupt triggering?
- Polling (also known as sequential detection) is a scanning method for key driving, where the code continuously checks the key state within a loop. When the key press is detected, the corresponding action is performed.
- Interrupt triggering utilizes the interrupt functionality of the microcontroller. When the key state changes, the microcontroller immediately responds, halting the current task and executing the key response program. This method is suitable for applications with high real-time requirements.
❓We know that we can read the voltage level on the key pin to determine whether the key is pressed. But how do we write the code to read it?
digitalRead()
is a function in Arduino programming used to read the voltage state from a digital pin. When the pin is set to input mode (INPUT
or INPUT_PULLUP
), you can use this function to read the current voltage level on that pin. The digitalRead()
function takes one parameter:
- Pin number: This is the number of the digital pin you want to read.
The value returned by digitalRead() will be either HIGH
(high level) or LOW
(low level). Here's an example using digitalRead()
:
int buttonState = digitalRead(2);
In this example, we read the value from pin number 2 (GPIO2). The returned value is stored in the variable buttonState
, which will be either HIGH
or LOW
, indicating whether the voltage level on that pin is high or low.
5.2.7 Programming in Arduino
- Open Arduino IDE (Integrated Development Environment).
- Connect the Arduino development board to the USB port of the computer.
- Enter the following code in the IDE:
// Define the pins connected to the LED and button
const int buttonPin = 2; // Button connected to digital pin 2
const int ledPin = 13; // LED connected to digital pin 13
// Variable to track button state
int buttonState = 0;
void setup() {
// Initialize LED pin as an output
pinMode(ledPin, OUTPUT);
// Initialize button pin as an input with pull-up resistor
pinMode(buttonPin, INPUT_PULLUP);
// Enable internal pull-up resistor if not using a physical one
}
void loop() {
// Read the button state
buttonState = digitalRead(buttonPin);
// If the button is pressed
if (buttonState == LOW) {
// Turn on the LED
digitalWrite(ledPin, HIGH);
} else {
// Otherwise, turn off the LED
digitalWrite(ledPin, LOW);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
- Select the correct Arduino board type and port in the IDE.
- Upload the code to the Arduino board (using the upload button in the IDE).
- Once the code upload is complete, try pressing the button to see the LED respond.
5.2.8 Practice Outcome
When the Arduino board is powered on and the above program is successfully uploaded, pressing the button will cause the LED to light up, while releasing the button will turn the LED off.
5.3 Time Management Practice
In Arduino programming, managing time accurately and efficiently is key to implementing various functions. Whether it's adding delays to a simple LED blinking example or scheduling tasks in more complex projects, time management plays a crucial role. This chapter aims to provide a detailed guide to time operations, covering everything from basic delays to more complex non-blocking time management techniques.
5.3.1 The Application of Delays
In Arduino or other microcontroller programming, delays are widely used for several reasons:
- Hardware Handling
Many hardware components require time to respond to a command. For instance, if you start a motor in a program and immediately check its status, you might get an incorrect reading because the motor may not have had enough time to start rotating. In such cases, you need to use the delay() function to allow the system to wait for a period, giving the motor sufficient time to respond. - User Interaction
Delays are often necessary to create effects in user interactions. For example, when a buzzer plays music, there needs to be a pause between notes. Similarly, when blinking an LED, a delay between the "on" and "off" states is required to control the blinking speed. - Energy Conservation
In some applications, such as battery-powered systems, maintaining high-speed operation for extended periods when not needed can significantly shorten battery life. In these cases, we can put the system into standby or low-power mode for a period until the next processing cycle arrives. - Timed Operations
In many projects, we often need to perform operations at specific times. For instance, in an automatic irrigation system, we might need to water the plants at certain times of the day. In interval measurements, we may need to collect data at regular intervals.
Although the delay function is very useful in many situations, it's important to be aware of its blocking nature. Over-relying on blocking delays can lead to the program being unresponsive to other events. To better perform multitasking programming on Arduino, we can also learn some non-blocking delay techniques.
❓What is Blocking Delay?
Blocking delay occurs when a certain operation or function requires a specific amount of time to complete, causing the program to pause execution until that operation finishes. During this time, the program is blocked. Blocking delays can slow down the program or even cause it to freeze. For example, imagine you want to boil water for tea. Normally, you would place the kettle on the stove and wait for the water to boil before using it. During this process, there is a blocking delay. When you put the kettle on the stove, the program can be seen as "waiting" for the water to boil. During this wait, you can't immediately get hot water for your tea; you must patiently wait for the water to reach boiling. During this time, you cannot do other unrelated tasks because you need to monitor the kettle and wait for the right moment. Even if a fire breaks out in your home, you are still waiting for the water to boil.
In Arduino, there are two common mechanisms for time operations: using the delay()
function for simple delays, and using millis()
or micros()
for non-blocking delays. Below, we will detail these mechanisms and how to apply them in Arduino projects.
5.3.2 Using delay()
function
The delay()
function pauses the Arduino for a specified number of milliseconds. During this time, the program does not execute any other code, making it a blocking operation. This function is suitable for simple programs and small projects, but it is not ideal for situations that require concurrent task execution.
Syntax:
delay(milliseconds);
Parameters:milliseconds
:The duration for which the program is interrupted, in milliseconds. Example using delay()
:
// Define the Arduino pin connected to the LED's positive terminal
const int ledPin = 13;
// The setup function runs when the Arduino board is reset or powered on
void setup()
{
// Set the mode of the ledPin to OUTPUT
pinMode(ledPin, OUTPUT);
}
// The loop function runs continuously after setup
void loop()
{
// Turn on the LED
digitalWrite(ledPin, HIGH);
// Wait for 1000 milliseconds (1 second)
delay(1000);
// Turn off the LED
digitalWrite(ledPin, LOW);
// Wait for 1000 milliseconds (1 second)
delay(1000);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
In this example, the LED turns on and off every 1 second.
5.3.3 Using millis()
for Non-Blocking Operations
The millis()
function returns the number of milliseconds since the Arduino board was powered on or last reset. The return value of this function is of type unsigned long
.
Advantages of Using millis()
:
- You can execute other code while waiting.
- It avoids the blocking nature of
delay()
.
Example of Using millis()
for Timing:
unsigned long previousMillis = 0; // Store the last update time
const long interval = 1000; // Set the interval time (1 second)
void setup() {
}
void loop() {
unsigned long currentMillis = millis(); // Get the current time
if (currentMillis - previousMillis >= interval) { // Check if 1 second has passed
previousMillis = currentMillis; // Save the current time
// Perform timed actions here
}
// Other code can be added here to execute between timed actions
}
2
3
4
5
6
7
8
9
10
11
12
13
14
In the example above, we use millis()
to track time intervals. If the current time differs from the last recorded time by 1 second or more, the program executes the timed action and updates the previousMillis
variable.
5.3.4 Using micros()
for More Accurate Timing
Similar to millis()
, the micros()
function returns the number of microseconds since the program started, but with higher precision.
Note: The value returned by the
micros()
function will overflow and restart after about 70 minutes.
Example:
void setup() {
Serial.begin(9600);
}
void loop() {
unsigned long timeMicros = micros();
// Execute operations...
// You can then use timeMicros to determine the time spent in microseconds
}
2
3
4
5
6
7
8
5.3.5 Reminders for Timing Functions
- Since
millis()
andmicros()
use theunsigned long
data type, the time will overflow (reset to 0) after approximately 50 days (millis()
) or 70 minutes (micros()
). This needs to be taken into account during programming. - When performing operations that take a long time, avoid using
delay()
, as it will block the execution of other code. In situations where the program needs to remain responsive, using non-blocking delays based onmillis()
is more suitable.
This concludes the detailed introduction to Arduino's timing control features. Mastering these functions can help you write faster, more reliable, and more complex Arduino applications. Feel free to experiment with the three methods mentioned above to control the LED's on and off timing for 1 second.
5.4 Analog Input and Output Practice
In this practice, we will use a variable resistor (such as a potentiometer) as an analog input to read the analog value (voltage) and use PWM to control an LED as an analog output to adjust its brightness.
Materials List
- 1 x Development board
- 1 x Breadboard
- 1 x LED
- 1 x 220Ω Resistor
- 1 x 10kΩ Potentiometer
- Jumper wires (several)
5.4.1 Introduction to Analog Input
Analog input is one of the core features of Arduino and many other microcontrollers. Unlike digital input, which can only read simple high (usually 5V or 3.3V) and low (0V) states, analog input can read varying voltage values from sensors or other devices.
Our development board is equipped with a built-in Analog-to-Digital Converter (ADC), featuring six analog input pins (A0 to A5). Each analog input pin can read continuous voltage values ranging from 0V to 5V and convert them into a digital value between 0 and 1023 (assuming a 10-bit ADC). This process is known as analog-to-digital conversion. Here are some key points about analog input:
- Resolution: The board’s 10-bit ADC provides 2^10 = 1024 different voltage levels. This means it can distinguish changes of approximately 4.88 mV (Vref/1024), where Vref is typically 5V, depending on the supply voltage of the board.
- Voltage Reference: By default, the reference voltage for analog inputs is 5V (on 5V powered Arduino boards), but this value can be changed programmatically or using an external reference.
- Reading Values: You can read the voltage value of an analog pin using the analogRead(pin) function, where pin is the number of the analog pin you wish to read (e.g., A0, A1, etc.).
- Applications: Analog input pins can be used to read data from various types of sensors, such as temperature, humidity, light intensity, sound intensity, and position (using a potentiometer).
Analog inputs help create interactive projects that respond to changes in the external environment. They are key components in collecting data from the physical world and play a crucial role in systems that make data-driven decisions.
When programming, it's important to remember that the process of reading analog input may take some time, which could impact system performance during high-speed or frequent data readings. However, in many cases, the speed of analog readings is sufficient for most conventional sensor applications.
5.4.2 Introduction to Analog Output
Analog input allows us to read continuous values from various sensors, while analog output refers to the ability to generate a range of values rather than just 0 and 1 (on or off). 。However, most microcontrollers, including Arduino, cannot directly produce true analog voltage outputs. Instead, they use Pulse Width Modulation (PWM) to simulate analog output.
Pulse Width Modulation (PWM)
Pulse Width Modulation (PWM) is a method of controlling analog signals in which the microcontroller simulates analog output by varying the proportion of time the signal is high within a certain time period. This proportion is commonly referred to as the duty cycle. This method approximates continuous voltage levels by quickly toggling the digital pins of the microcontroller (on/off) and controlling the signal's duty cycle.
For example: Imagine you have an LED and a switch. If you toggle the switch on and off at a speed that is too fast for the naked eye to perceive, the LED will be on half the time and off half the time. To an observer, it will appear that the LED is glowing at half brightness. This is the basic principle of PWM. If you keep the switch off for most of the time, the LED will appear dimmer; conversely, if you keep the switch on most of the time, the LED will appear brighter. This is the process of PWM adjusting the duty cycle to control brightness.
Key Points Related to Analog Output:
- Duty Cycle: The duty cycle indicates how long the signal is high (usually 5V or 3.3V) relative to the entire cycle. For example, if a PWM signal has a duty cycle of 50%, the signal is high for half the time and low for the other half.
- Frequency: The frequency of a PWM signal refers to how many complete cycles occur in a second. For instance, the PWM frequency on Arduino boards is typically around 490 Hz.
- Applications: PWM output can be used in applications such as LED brightness control, motor speed control, temperature management of heating elements, and other scenarios requiring variable voltage.
- Function: In Arduino, the
analogWrite(pin, value)
function is used to set PWM output, wherepin
is the specified PWM output pin, andvalue
is a number between 0 and 255 representing the relative amount of duty cycle (0 indicates 0%, and 255 indicates 100%).
Reminders:
- While PWM can simulate analog output, it does not produce a true continuous analog signal. For specific applications (like generating precise audio signals), true analog output may be required, necessitating the use of an external Digital-to-Analog Converter (DAC).
- Since PWM signals are inherently still digital signals (high-frequency “on” and “off”), certain applications may require a low-pass filter to smooth the output signal, making it closer to a true analog signal, especially when fine control without PWM noise is desired.
- Only certain Arduino pins can generate PWM signals. Typically, these pins are marked with a “~” symbol on the Arduino board.
Analog output (via PWM) is a highly effective method for microcontrollers to simulate varying voltage levels. This technology greatly enhances the ability of microcontrollers to handle analog signals and address complex tasks.
5.4.3 Hardware Connections
Step 1: Connect the LED
- Insert the longer leg (anode) of the LED into a slot on the breadboard.
- Connect a 220Ω resistor from the shorter leg (cathode) of the LED to the GND pin on the Arduino.
- Use a jumper wire to connect the longer leg (anode) of the LED to any PWM digital output pin on the Arduino, for example, D9.
Note: Be mindful of pin selection; PWM output pins are typically marked with a “~” symbol.
Step 2: Connect the Potentiometer
- Connect one terminal of the potentiometer to +5V.
- Connect the other terminal to GND.
- Connect the middle pin (wiper) of the potentiometer to any analog input pin on the Arduino, for example, A0.
Analog input pins are available from A0 to A5.
5.4.4 Software Setup
Open the Arduino IDE and enter the following code:
// Define the analog input pin connected to the potentiometer
const int potPin = A0;
// Define the digital pin connected to the LED, which needs to support PWM
const int ledPin = 9;
void setup() {
// Initialize the LED pin as an output
pinMode(ledPin, OUTPUT);
}
void loop() {
// Read the value from the potentiometer (between 0 and 1023)
int potValue = analogRead(potPin);
// Map the read analog value to the PWM range (between 0 and 255)
int ledBrightness = map(potValue, 0, 1023, 0, 255);
// et the brightness of the LED
analogWrite(ledPin, ledBrightness);
// Delay for 100 milliseconds to see the brightness change
delay(100);
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
In the code above, there's a line with a function that might be unfamiliar:
c// Map the read analog value to the PWM range (between 0 and 255) int ledBrightness = map(potValue, 0, 1023, 0, 255);
1
2In Arduino, the
map()
function is used to map a number from one range to another. Here’s what each parameter means:a.
potValue
is the current value read from the analog input, which may come from something like a potentiometer (rotary position sensor) or other analog sensors.b.
0
is the minimum possible value ofpotValue
, corresponding to the minimum voltage from the analog input (usually 0V).c.
1023
is the maximum possible value ofpotValue
, corresponding to the maximum voltage from the analog input (in a 10-bit ADC, this is usually the maximum digital representation for 5V or 3.3V).
d.0
is the minimum value of the mapped range, which is the value you want to mappotValue
's minimum to.
e.255
is the maximum value of the mapped range, which is the value you want to mappotValue
's maximum to.
This line of code thus converts the value read from the analog input pin (assumed to be between 0 and 1023) to a value between 0 and 255. This is commonly used to convert a 10-bit analog input value into an 8-bit value suitable for PWM output (usinganalogWrite
), asanalogWrite
accepts values from 0 to 255 to represent the duty cycle of the PWM. The mapping process is linear, meaning ifpotValue
is 512, the mapped value will be about 128, since 512 is roughly half of 1023, and similarly, 128 is half of 255.
- Copy and paste the above code into the Arduino IDE.
- Connect your Arduino board to the computer.
- Select the correct board and port in the IDE.
- Upload the code to your Arduino board.
5.4.5 Practice Outcome
After uploading, when you rotate the potentiometer, you should see the brightness of the LED change accordingly. By turning the potentiometer, the voltage change at its wiper is read through the analog input and converted into a digital value. This digital value is then mapped and adjusted to output a PWM signal to the LED, thereby altering its brightness.
5.5 Interrupt Service Practice
In Arduino, interrupts are a powerful feature that allows the microcontroller to immediately pause the current task when a specified event occurs and execute what is known as an Interrupt Service Routine (ISR). After completing this special function, the microcontroller returns to the point where it was interrupted to continue execution. This is particularly useful for responding to fast events, such as input from external devices.
5.5.1 Basic Concepts of Interrupts
In the world of microprocessors or microcontrollers, an interrupt is a special event that interrupts and temporarily suspends the currently running program to handle a specific condition or event. Examples include pressing a button, a timer reaching a set time, or receiving data from a serial port. Interrupts are a crucial concept in computer systems, enabling an asynchronous response to these particular situations. To illustrate, imagine you're coding, and suddenly a phone call comes in. You stop coding to answer the call, discuss the matter, and then resume coding. In this analogy, the phone call acts as an interrupt, disrupting your current activity, while answering and discussing are the actions handled by the interrupt service routine (ISR).
Interrupts are typically classified into two types: hardware interrupts and software interrupts.
Hardware interrupts are usually triggered by physical events from external devices, such as pressing a button, reaching a timer’s limit, or data arriving at a serial port. When such events occur, the microprocessor immediately pauses its current task and jumps to a predefined ISR to respond to the event.
Software interrupts, on the other hand, are triggered by software instructions and are generally used for handling more complex processing tasks. For instance, system calls in operating systems make use of software interrupts.
5.5.2 Introduction to External Interrupts
In the chapter on digital input and output, we conducted a button experiment, where we implemented the function to read the GPIO input. However, the code constantly monitors changes at the IO input, and if we add a large amount of code afterward, it would take a considerable amount of time to poll the button detection part, thus lowering efficiency. This is especially inefficient in specific situations, such as when a button is only pressed once a day to trigger a function, wasting a lot of time in real-time monitoring of the button’s status. To address this issue, we introduce the concept of external interrupts. As the name suggests, the relevant function is only executed when the button is pressed (causing an interrupt). This approach greatly conserves CPU resources, which is why interrupts are widely applied in practical projects.
An external interrupt is a type of hardware interrupt triggered by events outside the microcontroller. Certain pins on the microcontroller are designed to respond to specific events, such as a button press or a change in a sensor signal. These designated pins are usually referred to as “external interrupt pins.”
When an external interrupt event occurs, the currently running program is immediately halted and jumps to the corresponding Interrupt Service Routine (ISR) for processing. Once the ISR is completed, the program resumes from the point where it was interrupted.
For embedded systems and real-time systems, external interrupts are critical as they allow the system to respond to external events instantly, significantly improving system efficiency and responsiveness.
Arduino boards typically have only 2 external interrupts, which are connected to digital pins 2 and 3.The attachInterrupt()
function is used to define an interrupt and link it to an ISR.
5.5.3 The Role and Advantages of External Interrupts
The interrupt function in Arduino development offers the following roles and advantages:
- Real-time Response to External Events:Interrupts allow your Arduino to respond immediately when an external event is detected. These external events could be triggered by sensors, buttons, switches, incoming signals, etc. With external interrupts, these events can be captured and responded to in real-time, without the need for constant polling or waiting.
- Conserving Computing Resources: External interrupts enable you to offload the task of handling external events to the chip’s hardware, thereby conserving processor resources. Compared to software polling, external interrupts reduce the load on the processor, allowing it to allocate resources more efficiently to handle more complex tasks.
- Precise Event Capture: The interrupt function allows highly precise capture of external events. By configuring the interrupt trigger type (such as rising edge, falling edge, any level, low level hold, high level hold, etc.), you can adapt to different external events. When an event occurs, the currently running program is immediately interrupted, and the interrupt service routine (ISR) is executed.
- High-priority Processing: External interrupts can be set to high-priority handling, taking precedence over the currently running program. This is useful for critical events requiring immediate response, such as urgent notifications or sensor detections. When an external event is triggered, the processor switches immediately to execute the ISR, ensuring timely and accurate handling to avoid processing delays.
In summary, the interrupt function brings numerous advantages to Arduino projects, including real-time response, resource conservation, precise event capture, high-priority handling, and multi-interrupt processing. This provides a more flexible, efficient way to manage external events, helping to build more robust and reliable applications.
5.5.4 Hardware Connection
Step 1: Connecting the LEDs
- Insert the long leg (anode positive) of the LED into one of the slots on the breadboard.
- Connect one end of the 220Ω resistor to the short (cathode-negative) leg of the LED and connect the other end to the Arduino's GND connector.
- Use a jumper to connect the long (anode) leg of the LED to the digital output port of the Arduino, e.g. D13.
Step 2: Connecting the Buttons
- Connect one pin of the button to GND.
- Connect the other pin to one of the Arduino's external interrupt pins, pin 2 or pin 3.
- (Optional) To ensure that the input is high when the button is not pressed, you can add a 10kΩ resistor as a pull-up resistor to connect this pin of the button (not the one connected to GND) to +5V.
5.5.5 Introduction to API
Development boards like the Arduino Uno typically have only 2 external interrupts connected to digital pins 2 and 3. use the attachInterrupt() function to define an interrupt and associate it to an ISR.
Syntax:
attachInterrupt(interruptNum, ISR, mode);
Parameter Description:
interruptNum
: This is the external interrupt number, there are only two pins supported by the Arduino development board, GPIO2 (interrupt number 0) and GPIO3 (interrupt number 1). For most Arduino boards, you can directly use thedigitalPinToInterrupt(pin)
macro to convert the digitalpin
to the corresponding interrupt number.ISR
: the function called when the interrupt is triggered.mode
: specifies what type of pin state change triggers an interrupt. Commonly used modes are:LOW
: triggered when the pin is low (not recommended as it will continuously trigger interrupts).CHANGE
: triggered when the pin level changes.RISING
: triggered when the pin level rises (from low to high).FALLING
: triggered when the pin level falls (from high to low).
The external interrupts of Arduino have the modes of rising edge trigger, falling edge trigger, low level trigger, and level change trigger.
The rising and falling edge triggers are as follows:
When the pin is set as an external interrupt pin, it will enter the interrupt callback function and execute the corresponding program when the configured trigger mode is detected on the pin.
5.5.6 Programming in Arduino
- Open the Arduino IDE (Integrated Development Environment).
- Connect the Arduino board to the USB port of your computer.
- Enter the following code in the IDE:
const int buttonPin = 2; // External interrupt pin connected to digital pin 2
const int LEDPin = 13; // Debug LED connected to digital pin 13
volatile bool buttonPressed = false; // Shared variable marked with volatile keyword
bool led_flag = false;//LED state
void setup()
{
pinMode(buttonPin, INPUT_PULLUP); // Set input with internal pull-up resistor
pinMode(LEDPin , OUTPUT); // Set output mode
//Enable interrupt mode on pin 2, executing function handleInterrupt on falling edge
attachInterrupt(digitalPinToInterrupt(buttonPin), handleInterrupt, FALLING);
}
void loop()
{
if( buttonPressed == true )
{
digitalWrite(LEDPin, led_flag=!led_flag);
buttonPressed = false; // Reset status flag
}
// Execute other tasks
}
void handleInterrupt()
{
buttonPressed = true; // Update shared variable to indicate button has been pressed
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
- Select the correct Arduino board type and port in the IDE.
- Upload the code to the Arduino board (using the upload button in the IDE).
- Once the code upload is complete, try pressing the button to see the LED respond.
Notes
Illustration based on the interrupt callback function button_ISR() used in the example above. There are a few things to keep in mind when using interrupts in Arduino:
a. Try to ensure that the interrupt program is as small as possible b. Avoid using blocking functions (such as delay()
) in the interrupt handler function, and use non-blocking delay methods for operations that require delay ( micros()
function) to ensure normal execution of the interrupt and system stability. This is because the delay()
function blocks the entire system, including the normal execution of the interrupt. When an interrupt is triggered, the handler function should be executed as soon as possible to ensure a timely response and avoid interrupt backlog; c. Variables shared with the main program should be added with the volatile
keyword; d. d. When using interrupts in Arduino, you should try to avoid using the print function of the Serial
serial object in the interrupt handler function.When using the Serial
print function in the interrupt handler function, it will lead to the following problems:
- Time delay: The
Serial
function is usually a time-consuming operation, it will block the execution time of the interrupt, resulting in a delay in the interrupt response. This can lead to loss of other important interrupt events during an interrupt or cause system instability. - Buffer Overflow: The
Serial
objects use a buffer internally to store the data to be sent. Frequent calls to the Serial print function during an interrupt handler may result in a buffer overflow, causing data loss or unpredictable behavior.
To avoid these problems, it is recommended that the Serial
Print function be avoided in interrupt handlers. If you need to output debugging information in the interrupt handler function, you can use other methods, such as setting flag bits, checking the flag bits in the main loop and printing.
❓What is volatile?
volatile
is a keyword used to inform the compiler that the variable it declares may be changed by factors outside the program. Its purpose is to ensure that variables defined as volatile
are re-read from memory every time they are accessed, rather than using cached values, thereby ensuring the correctness of the program.
Variables declared as volatile
can be modified by interrupt service routines (ISRs), multi-threaded tasks, or similar operations. For these needs, the normal variable definition method is optimized by the compiler to minimize memory read and write operations. Therefore, for certain variables (such as a peripheral register), the compiler may use caching to improve program efficiency. In this case, if the variable is not declared with the volatile
keyword, when its value is changed by external factors, the program may use the already cached variable value instead of the latest value, leading to errors in the program.
Practice Outcome
In this example, whenever pin 2 detects a falling edge (button pressed), the handleInterrupt
function is triggered, setting the button pressed status flag totrue
. Then, in the loop()
, we check this flag and perform the LED toggle operation.
5.6 Serial Communication Protocol Practice
Serial communication protocol is a method for transmitting data between computers, microcontrollers, or other devices. Serial communication refers to a communication method where data is transmitted bit by bit between peripherals and processors through data signal wires, ground wires, and control wires. Although the transmission speed is lower than parallel transmission, serial communication allows for data to be sent on one wire while receiving data on another wire.This method uses fewer data wires, which can save communication costs in long-distance communication. In Arduino projects, serial communication is very common and important; it can be used for data transmission between devices, outputting debug information, and communicating with computers or other serial devices.
5.6.1 Basic Concepts of Serial Communication
Serial communication uses two pins, TX (transmit) and RX (receive), to send and receive data. The Arduino UNO and many other Arduino boards have built-in serial communication functionality, allowing them to communicate with computers via USB or use digital pins (like 0 and 1) for serial communication with other devices.
5.6.2 Introduction to Serial Communication
The serial communication protocol defines the rules and formats for data exchange over the serial interface. Common serial communication protocols include ASCII, Modbus, RS-232, and others. The protocol specifies the frame structure of the data, data format, checksum methods, etc., ensuring that both the sender and receiver follow the same rules for data exchange, thus achieving correct transmission and parsing of data.
Serial communication transmits one bit at a time. Each character transmission always begins with a start bit and ends with a stop bit, with no fixed time interval requirements between characters. Each character is preceded by one start bit (low level), followed by 7 data bits, a parity bit, and finally a stop bit. After the stop bit, there can be an indefinite number of idle bits, with both the stop bit and idle bits defined as high level.
Serial communication parameters include baud rate, data bits, parity bits, and stop bits. These parameters describe the basic specifications for transmitting data. For example, the baud rate defines the rate at which data is transmitted, data bits determine the number of bits contained in each data byte, parity bits are used for error detection in data, and stop bits indicate the end of data transmission.
- Baud Rate: A parameter that measures communication speed, representing the number of bits transmitted per second.
- Data Bits: A parameter that measures the actual data bits in communication, indicating the number of bits included in a single information packet.
- Stop Bits: Used to indicate the last bit of a single information packet, with typical values of 1, 1.5, and 2 bits. Since data is transmitted over a communication line, each device has its own clock, and it is very likely that synchronization issues may arise during communication. Stop bits not only indicate the end of transmission but also provide an opportunity to correct clock synchronization. The more stop bits, the greater the tolerance for clock synchronization discrepancies, but the data transmission rate will also be slower.
- Parity Bit: Represents a simple method for error checking.
5.6.3 Serial Communication Modes
Serial communication modes are divided into three types: simplex, half-duplex, and full-duplex modes.
- Simplex: At any given time during communication, information can only flow from A to B, or from B to A.
- Half-Duplex: At any given time during communication, information can flow from A to B and from B to A, but only one direction of transmission can occur at a time.
- Full-Duplex: At any given time during communication, there are bidirectional signal transmissions present from A to B and from B to A.
5.6.4 The Role and Advantages of Serial Communication
Serial communication is one of the most common communication interfaces between computers and external devices, playing a significant role and having a wide range of applications. In the field of computing, the importance of serial communication can be highlighted in several aspects:
- Data Transmission: Serial communication is a commonly used data transmission interface. Through serial ports, computers can exchange and communicate data with various external devices. Whether it’s sensors, actuators, displays, printers, or other external devices, serial communication enables data transmission and control.
- Remote Control and Monitoring: Serial communication is widely used in remote control and monitoring applications. Through serial connections, computers can remotely control the actions of devices and monitor their status and data in real-time. This is crucial in industrial control, automation systems, and remote monitoring scenarios.
- Debugging and Troubleshooting: Serial communication is an essential tool for debugging and troubleshooting. It allows computers to communicate with embedded systems, microcontrollers, etc., enabling real-time monitoring and debugging of programs, outputting debug information, locating errors, and diagnosing system statuses and faults.
- Hardware Connection: Serial communication can serve as a bridge for connecting computers with various external devices. It allows the connection and control of various external devices, such as sensors, actuators, and peripherals. Serial ports provide stable data transmission and bidirectional communication capabilities.
- Communication Protocols: Serial communication protocols define the specifications and agreements for data transmission between computers and external devices. By defining different protocols, data exchange and communication between different devices can be achieved. Common serial communication protocols include UART, RS-232, and RS-485.
In summary, serial communication plays a vital role in the communication between computers and external devices. It is a key tool for data transmission, remote control and monitoring, debugging, and troubleshooting, serving as a bridge for connecting and communicating between computers and external devices.
5.6.5 Hardware Connection
This case utilizes the onboard CH340 USB-to-serial chip on the development board. Connect the development board to the computer to test the serial communication functionality.
The CH340 is a USB-to-serial chip commonly used for the USB-to-serial functionality in microcontrollers, single-chip microcomputers, and Arduino devices, and it can also be used for USB data transmission and reception. When using the CH340 module, it is necessary to install the corresponding driver to enable the computer to recognize the serial output from the CH340 chip. For Windows systems, the driver usually installs automatically; for Mac and Linux systems, the appropriate driver must be downloaded and installed to ensure functionality.
INFO
Compressed Package
The CH340 module is relatively convenient to use; however, since our development board already has the CH340 module integrated, we can simply use a data cable to connect the development board to the computer. Once the computer and development board are connected, communication with the microcontroller can be achieved by sending commands via the serial port. The advantages include a simple interface, low cost, and user-friendly drivers, making it widely used in development processes and various projects requiring communication with computers.
5.6.6 Introduction to API
In terms of software, Arduino provides the Serial
library to implement serial communication. This library offers various methods to send and receive data.
Initialize Serial Port
Use the Serial.begin(baudRate)
method to initialize serial communication, where baudRate
specifies the data transmission rate (bit rate), such as 9600, 115200, etc. This rate must match that of the receiver.
void setup() {
Serial.begin(9600); // Set the baud rate to 9600
}
2
3
Send Data
You can use Serial.print()
and Serial.println()
to send data. Theprint
method sends data without adding a newline character, while println adds a newline character at the end of the data.
void loop() {
Serial.println("Hello, world!"); // Send string and add newline
delay(1000); // Send once per second
}
2
3
4
Receive Data
Use Serial.available()
to check if there is data to read. If this function returns 0, it indicates that there is no data to read. If there is, Serial.read()
can be used to read a single byte of data.
void loop() {
if (Serial.available() > 0) {
char received = Serial.read(); // Read and store one byte of data
Serial.print("Received: ");
Serial.println(received); // Display the received data
}
}
2
3
4
5
6
7
Advanced Reading
Serial.readString()
: Reads the characters received via the serial port until a timeout occurs. This method depends on the timeout set bysetTimeout()
.Serial.readStringUntil(terminator)
: Reads serial data until a specified terminator character is encountered or a timeout occurs.Serial.parseInt()
: Reads data from the serial port and parses it as anint
type. This is very convenient for receiving numeric data.Serial.parseFloat()
: Reads data from the serial port and parses it as afloat
type. This is suitable for situations where floating-point numbers need to be handled.
5.6.7 Porgramming in Arduino
Below is a simple example demonstrating how to send and receive data:
void setup() {
Serial.begin(9600); // Initialize the serial port
}
void loop() {
// Send data
Serial.println("Sending data...");
delay(1000); // Wait for one second
// Check if there is data available to read
if (Serial.available() > 0) {
String receivedData = Serial.readStringUntil('\n'); // Read data until a newline character
Serial.print("Received: ");
Serial.println(receivedData); // Print the received data
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
5.6.8 Practice Outcome
In this example, the Arduino device sends a message every second and checks for incoming data from other devices. If there is data available, it reads and prints that data.
The Arduino IDE includes a simple serial debugging assistant, which can be opened from the top right corner of the IDE.
Once opened, set the baud rate to 9600 to communicate with the development board via serial.
5.7. Sensor Application Practice
5.7.1 0.96-inch IIC Monochrome Screen
5.7.1.1 Module Source
Purchase Link:
https://item.taobao.com/item.htm?spm=a1z10.5-c-s.w4002-23284685151.19.1ffe61919S9gQy&id=40809409804
Baidu Netdisk Download Link:
https://pan.baidu.com/s/1xy2zH8-hs-S8-_AcVtBP_g
Password:0jhj
5.7.1.2 Specification parameters
Operating voltage: 3.3V
Operating current: 9MA
Module size: 27.3 x 27.8 MM
Pixel Size: 128(H) x 64(V)RGB
Driver chip: SSD1306
Communication protocol: IIC
Number of Pins: 4 Pin (2.54mm pitch row of pins)
5.7.1.3 Hardware Connection
- VCC: Connect to 3.3V or 5V of the development board (depending on the voltage requirement of the OLED screen, most SSD1306 modules support 3.3V and 5V).
- GND: Connect to GND of the development board.
- SCL: Connect to the A5 or SCL pin of the development board.
- SDA: Connect to A4 or SDA pin of the development board.
5.7.1.4 Usage Method
Install the library file (skip this step if you have already installed it)
- Open the Arduino IDE.
- Select “Tools” > “Manage Libraries...”.
- Search for “Adafruit SSD1306” and “Adafruit GFX”, and then install these two libraries respectively.
Enter the code
/******************************************************************************
* Test Hardware: LCSC ColorEasyDuino Development Board
* Version Number: V1.0
* Modified By: www.lckfb.com
* Modification Date: March 28, 2024
* Function Overview:
*****************************************************************************
* Open-source development board hardware and software information and related projects hardware and software information on official website
* Development board official website: www.lckfb.com
* Technical support resident forum, any technical problems are welcome at any time to exchange learning
* LCSC Forum: club.szlcsc.com
* Follow our Bilibili account: [立创开发板], stay toned to our latest news!
* We focus on cultivating Chinese engineers rather than profiting from board sales.
******************************************************************************/
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
// Define screen width and height
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
// Create an Adafruit_SSD1306 object. The parameter is the reset pin; since many modules don’t use this, pass -1.
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
void setup() {
// Initialize the OLED display
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // 0x3C is the I2C address for most OLED screens; if it doesn’t work, try 0x3D
Serial.println(F("SSD1306 allocation failed"));
for(;;); // Infinite loop
}
display.clearDisplay();
display.setTextSize(1); // Set text size
display.setTextColor(SSD1306_WHITE); // Set text color
display.setCursor(0,0); // Set text start position
display.println(F("Hello, world!"));
display.setTextSize(2);
display.setCursor(0,10);
display.println(F("SSD1306"));
display.display(); // Render all drawing operations
}
void loop() {
// No need for repeating code here
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
5.7.1.5 Usage Testing
5.7.2 DHT11 Temperature and Humidity Sensor
The DHT11 digital temperature and humidity sensor is a composite sensor with calibrated digital signal output. It offers low cost, long-term stability, and the ability to measure both relative humidity and temperature. Data collection for temperature and humidity can be achieved using just a single data line.
5.7.2.1 Module Source
Purchase Link:
DHT11 Temperature Module | Humidity Module | Temperature and Humidity Module | DHT11 Sensor
Baidu Netdisk download link:
https://pan.baidu.com/s/1HQEL699-Yl5Jh3Hp87_FlQ
Password:2sgq
5.7.2.2 Specification parameters
Operating voltage: 3-5.5V
Operating current: 1MA
Measurement resolution: 8 bit
Communication protocol: Single bus
Number of pins: 3 Pin (2.54mm pitch row of pins)
5.7.2.3 Hardware Connection
VCC to 5V of the development board
GND to GND of the board
DATA to a digital pin (e.g., pin 2) on the development board.
The DHT11 typically has a separate data line, and an optional pull-up resistor connected to VCC. some modules may already include this pull-up resistor.
5.7.2.4 Usage Method
Installing the library
You need to install the library for reading DHT11 data.Adafruit provides a good library that can be installed using the Arduino IDE's library manager.
- Open the Arduino IDE.
- Go to Tools > Manage Libraries.
- Search for DHT sensor library and install it (by Adafruit).
Enter code
/******************************************************************************
* Test Hardware: LCSC ColorEasyDuino Development Board
* Version Number: V1.0
* Modified By: www.lckfb.com
* Modification Date: April 8, 2024
* Function Overview:
*****************************************************************************
* Open-source development board hardware and software information and related projects hardware and software information on official website
* Development board official website: www.lckfb.com
* Technical support resident forum, any technical problems are welcome at any time to exchange learning
* LCSC Forum: club.szlcsc.com
* Follow our Bilibili account: [立创开发板], stay toned to our latest news!
* We focus on cultivating Chinese engineers rather than profiting from board sales.
******************************************************************************/
#include "DHT.h"
#define DHTPIN 2 // Defines the DHT11 data pin to be connected to Arduino pin 2
#define DHTTYPE DHT11 // Define the DHT type as DHT11
DHT dht(DHTPIN, DHTTYPE);
void setup() {
Serial.begin(9600);
Serial.println("DHT11 Temperature and Humidity test:");
// Initialize the DHT11 sensor
dht.begin();
}
void loop() {
// wait a few seconds between readings (DHT11 readings are relatively slow)
delay(2000);
// Read the temperature and humidity values
float h = dht.readHumidity();
float t = dht.readTemperature();
// check if reading failed and read the temperature and humidity values.
if (isnan(h) || isnan(t)) {
Serial.println("Failed to read DHT11!");
return;
}
// Output the read temperature and humidity.
Serial.print("Humidity: ");
Serial.print(h);
Serial.print(" %\t");
Serial.print("Temperature: ");
Serial.print(t);
Serial.println(" °C ");
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
5.7.2.5 Usage Testing
5.7.3 HC-05 Bluetooth Module
The HC-05 Bluetooth Serial Communication Module is a data transmission module based on Bluetooth Specification V2.0 with EDR (Enhanced Data Rate). Operating in the 2.4GHz ISM wireless frequency band, it uses GFSK modulation. The module's maximum transmission power is 4dBm, with a receive sensitivity of -85dBm, and it includes an onboard PCB antenna, enabling communication over distances of up to 10 meters. With a stamp hole design and compact dimensions of 27mm × 13mm × 2mm, it easily integrates into embedded systems. The module also features an LED indicator for visual confirmation of Bluetooth connection status. Using the CSR BC417 chip, the HC-05 supports AT commands, allowing users to flexibly modify its role (master or slave mode), baud rate, device name, and other parameters.
5.7.3.1 Module Source
5.7.3.2 Specifications parameters
Operating Voltage: 3.6-6V
Supply Current: 40mA
Transmission Power: 4dBm (maximum)
Reference Range: 10 meters
Control Method: Serial
Number of Pins: 6 Pins (2.54mm pitch header)
5.7.3.3 User Instructions
Before using the HC-05 Bluetooth module, you need to know the baud rate of the Bluetooth module to control it effectively. Connect the Bluetooth module to the development board, with the module's TX connected to the development board's RX and the RX connected to the TX. Before plugging it into the computer, hold down the button on the module while powering it on. Once connected to the computer and powered, the light on the module will blink slowly, indicating that the HC-05 has entered AT command mode, with a default baud rate of 38400. This mode is referred to as "Original Mode," where it remains in AT command mode continuously.
Once in AT command mode, the main task is to set the mode to slave control, which means waiting for the phone to connect to our Bluetooth module, primarily controlled by the phone. When sending commands, it is important to note that each command must be followed by \r\n or the "Send New Line" option must be checked; otherwise, the commands will not be recognized.
Key Command Descriptions
Testing Command:
Command | Response | Parameters |
---|---|---|
AT | OK | None |
Setting/Querying - Module Role:
Setting/Querying - Serial Parameters:
After the configuration is complete, power off the Bluetooth module and then power it back on. The light on the module will blink rapidly, indicating that it is in normal working status. Turn on the Bluetooth feature on your phone to search for devices, and you will find our Bluetooth module named: HC-05. When connecting, you will need to enter the PIN code, which we previously checked in AT mode as 1234.
After connecting to the cell phone successfully, the light on the module enters into a slow blinking state, indicating that it has been connected successfully. Open the Bluetooth communication software on the cell phone side and test whether it can transfer data with the computer.
5.7.3.4 Hardware Connection
- HC-05 VCC to Development Board 5V
- HC-05 GND to Development Board GND
- HC-05 TXD to Development Board Pin 2
- HC-05 RXD to Development Board Pin 3
5.7.3.5 Usage Method
The following simple example demonstrates how to set up the development board to listen to the HC-05 module via serial communication. When data is received from the paired device, the development board will send the received data back (echo test).
Note that the baud rate of the Bluetooth module should not be set to 115200 or higher; otherwise, communication will not be possible.
/******************************************************************************
* Test Hardware: LCSC ColorEasyDuino Development Board
* Version Number: V1.0
* Modified By: www.lckfb.com
* Modification Date: April 11, 2024
* Function Overview:
*****************************************************************************
* Open-source development board hardware and software information and related projects hardware and software information on official website
* Development board official website: www.lckfb.com
* Technical support resident forum, any technical problems are welcome at any time to exchange learning
* LCSC Forum: club.szlcsc.com
* Follow our Bilibili account: [立创开发板], stay toned to our latest news!
* We focus on cultivating Chinese engineers rather than profiting from board sales.
******************************************************************************/
#include <SoftwareSerial.h>
// Pin 2 is RX, connected to HC-05's TXD
// Pin 3 is TX, connected to HC-05's RXD
SoftwareSerial BT(2, 3);
char val;
void setup() {
pinMode(2,INPUT);
pinMode(3,OUTPUT);
Serial.begin(9600);
Serial.println("BT is ready!");
BT.begin(9600);
}
void loop() {
//Send data from the serial monitor to the mobile app via Bluetooth
if (Serial.available()) {
val = Serial.read();
BT.print(val);
}
//Send data received from the Bluetooth app to the serial monitor
if (BT.available()) {
val = BT.read();
Serial.print(val);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
5.7.3.6 Usage Testing
Send "hello lckfb" with phone, and then receive "hello."
5.7.4 SG90 Servo Motor
5.7.4.1 Module Source
Purchase Link: https://detail.tmall.com/item.htm?abbucket=0&id=615779197448&ns=1&spm=a21n57.1.0.0.6f6f523cXTHwFh
Baidu Netdisk download link: https://pan.baidu.com/s/1QsTIKnoQsOTCkeYLLTTjTA?pwd=8889
Password:8889
5.7.4.2 Specification parameters
Operating Voltage: 3V ~ 7.2V Driving Current: Working Torque: 1.6KG/CM Control Method: PWM Rotation Angle: 180 degrees
5.7.4.3 User Instruction
When purchasing, you need to distinguish whether your servo can turn 180 degrees, or 360 degrees. 360 degree servos are not able to control the angle, only the rotation speed.
The SG90 servo has a relatively slow speed, typically around 0.22/60 degrees or 0.18/60 degrees. Therefore, if you change the width of the control pulse too quickly, the servo may not respond in time. If you need a faster response, a higher-speed servo will be required.
5.7.4.4 Hardware Connection
- The signal wire (usually orange or yellow) connects to the PWM output pin 9 on the development board.
- The power wire (red) connects to the 5V pin on the development board.
- The ground wire (brown or black) connects to the GND pin on the development board.
5.7.4.5 Usage Method
- Include the Servo library: First, you need to include the Servo library in the Arduino IDE.
- Define Servo objects: Then, define one or more Servo objects, each representing a servo motor.
- Attach the servo to a pin: Use the attach() function to attach the servo object to the pin connected to the control signal wire.
- Control the servo: Use the write() function to rotate the servo to a specified angle (0 to 180 degrees).
#include <Servo.h>
Servo myservo; // Create a servo object to control the SG90
void setup() {
myservo.attach(9); // Connect the servo's signal wire to digital pin 9
}
void loop() {
for (int pos = 0; pos <= 180; pos += 1) {
myservo.write(pos); // Rotate from 0 degrees to 180 degrees
delay(15); // Allow time for the servo to reach the new position
}
for (int pos = 180; pos >= 0; pos -= 1) {
myservo.write(pos); // Rotate back from 180 degrees to 0 degrees
delay(15); // Allow time for the servo to reach the new position
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
This example code makes the servo slowly rotate from 0 degrees to 180 degrees and then back to 0 degrees. The delay(15)
statement ensures that the servo has enough time to reach the new position.
5.7.4.6 Usage Testing
For more details, please read the module migration manual.