EXPERIMENT NO.1 to 10

Embedded Systems Lab Manual – Experiments 1 to 10

Embedded Systems Lab Manual

Experiment No. 1 – Interfacing Button (Switch) Controlled LEDs with an Embedded Core

Title

Interfacing a Push Button (Switch) to Control LEDs Using Arduino Uno

Aim

To interface a push button switch with an Arduino Uno and control an LED based on the button's state.

Objective

  • To understand digital input and output on the Arduino Uno.
  • To learn how to interface a push button with a microcontroller.
  • To control an LED using a button press.

Components Required

  • Arduino Uno
  • Push Button (Tactile Switch)
  • LED
  • 220 Ω Resistor (for LED)
  • 10 kΩ Resistor (for pull-down resistor, if not using internal pull-up)
  • Breadboard
  • Jumper Wires
  • USB Cable

Theory

A push button is a digital input device that can be either in the HIGH or LOW state. When the button is pressed, it changes the input signal received by the Arduino. The Arduino reads this signal using a digital input pin and controls the LED connected to a digital output pin.

In this experiment, when the button is pressed, the Arduino turns the LED ON. When the button is released, the LED turns OFF. The Arduino continuously checks the state of the button using the digitalRead() function and controls the LED using the digitalWrite() function.

Circuit Connections

ComponentArduino Connection
LED Anode (+)Digital Pin 8 through 220 Ω resistor
LED Cathode (–)GND
Push ButtonOne terminal to Digital Pin 2
Push ButtonOther terminal to +5 V
10 kΩ ResistorBetween Digital Pin 2 and GND (Pull-down resistor)

Observation

Button StateLED State
ReleasedOFF
PressedON

Result

The push button was successfully interfaced with the Arduino Uno. The LED turned ON when the button was pressed and turned OFF when the button was released, demonstrating successful digital input and output interfacing.

Applications

  • Home automation switches
  • Industrial control systems
  • Security alarm systems
  • User input interfaces
  • Electronic toys and gaming devices

Precautions

  1. Use the correct resistor values to protect the LED.
  2. Ensure all wiring connections are secure.
  3. Verify the polarity of the LED before connecting.
  4. Upload the program only after checking the circuit connections.
  5. Avoid short circuits on the breadboard.

Conclusion

The experiment successfully demonstrated how to interface a push button with an Arduino Uno to control an LED. It illustrates the use of digital input and output operations in Arduino and forms the basis for implementing more advanced embedded system projects involving user interaction.

Program

int led = 13;
int btn = 7;
static int led_state, prev_btn_data;

void setup() {
  // put your setup code here, to run once:
  pinMode(led, OUTPUT);
  pinMode(btn, INPUT_PULLUP);
}

void loop() {
  // put your main code here, to run repeatedly:
  int btn_data = digitalRead(btn);
  if (btn_data == LOW && btn_data != prev_btn_data)
  {
    led_state = !led_state;
  }
  digitalWrite(led, led_state);
  prev_btn_data = btn_data;
}

Output

Experiment 1 simulation output – LED controlled by push button
Wokwi simulation: LED ON after button press

Experiment No. 2 – Interfacing a DHT22 Temperature and Humidity Sensor

Aim

To interface a DHT22 temperature and humidity sensor with an Arduino Uno.

Objectives

  • To understand the working principle of the DHT22 sensor.
  • To interface the DHT22 sensor with Arduino Uno.
  • To display temperature and humidity readings on the Serial Monitor.

Apparatus Required

  • Arduino Uno
  • DHT22 (AM2302) Temperature and Humidity Sensor
  • 10 kΩ Resistor (pull-up resistor, if using a bare sensor)
  • Breadboard
  • Jumper Wires
  • USB Cable
  • Computer with Arduino IDE

Theory

The DHT22 (AM2302) is a digital sensor capable of measuring both temperature and relative humidity. It provides calibrated digital output, eliminating the need for analog-to-digital conversion. Compared to the DHT11, the DHT22 offers higher accuracy and a wider operating range.

Specifications:

  • Temperature Range: –40°C to 80°C
  • Temperature Accuracy: ±0.5°C
  • Humidity Range: 0–100% RH
  • Humidity Accuracy: ±2–5% RH
  • Operating Voltage: 3.3 V to 6 V
  • Sampling Rate: One reading every 2 seconds

The sensor communicates with the Arduino using a single-wire digital communication protocol.

Circuit Connections

DHT22 PinArduino Uno
VCC5V
DATADigital Pin 7
GNDGND
10 kΩ ResistorBetween VCC and DATA (if required)

Procedure

  1. Connect the DHT22 sensor to the Arduino Uno as per the circuit diagram.
  2. Open the Arduino IDE.
  3. Install the DHT Sensor Library by Adafruit using the Library Manager.
  4. Select Arduino Uno as the board and choose the correct COM port.
  5. Upload the program to the Arduino.
  6. Open the Serial Monitor and set the baud rate to 9600.
  7. Observe the temperature and humidity readings.
  8. Change the surrounding temperature or humidity and observe the updated values.

Observation

Sr. No.Temperature (°C)Humidity (%RH)
   
   
   

Result

The DHT22 sensor was successfully interfaced with the Arduino Uno. The system accurately measured and displayed the ambient temperature (°C) and relative humidity (%RH) on the Serial Monitor.

Program

#include <DHT.h>
#define DHTPIN 7
#define DHTTYPE DHT22

DHT dht(DHTPIN, DHTTYPE);
float hum;
float temp;

void setup() {
  Serial.begin(9600);
  dht.begin();
}

void loop() {
  delay(2000);
  hum = dht.readHumidity();
  temp = dht.readTemperature();
  Serial.print("Humidity:");
  Serial.print(hum);
  Serial.println("%");
  Serial.print("Temperature:");
  Serial.print(temp);
  Serial.println("Celcius");
  delay(1000);
}

Output

Experiment 2 circuit with DHT22 and Arduino Uno
Wokwi simulation of DHT22 interfacing
Humidity:40.00%
Temperature:24.00Celcius
Humidity:40.00%
Temperature:24.00Celcius
Humidity:40.00%
Temperature:24.00Celcius
Humidity:40.00%

Experiment No. 3 – Interfacing a 16×2 I2C LCD with Arduino Uno

Aim

To interface a 16×2 I2C LCD with the Arduino Uno and display text on the LCD.

Objective

  • To understand the working of an I2C LCD module.
  • To interface the I2C LCD with the Arduino Uno.
  • To display text on the LCD using the LiquidCrystal_I2C library.

Components Required

  • Arduino Uno
  • 16×2 I2C LCD Module
  • Jumper wires

Theory

An I2C LCD is a standard 16×2 LCD fitted with an I2C interface module (PCF8574). Unlike a parallel LCD that requires multiple data pins, the I2C LCD uses only two communication lines:

  • SDA (Serial Data)
  • SCL (Serial Clock)

This reduces the number of Arduino pins required and simplifies wiring. The default I2C address of the LCD is usually 0x27 (sometimes 0x3F).

Circuit Connections

I2C LCD PinArduino Uno Pin
GNDGND
VCC5V
SDAA4
SCLA5

Procedure

  1. Open the Wokwi Simulator.
  2. Create a new Arduino Uno project.
  3. Add an I2C LCD (16×2) component.
  4. Connect the LCD to the Arduino:
    • VCC → 5V
    • GND → GND
    • SDA → A4
    • SCL → A5
  5. Copy and paste the Arduino program into the code editor.
  6. Start the simulation.
  7. Observe the displayed message on the LCD.

Observation Table

LCD LineDisplayed Text
Line 1 
Line 2 

Result

The 16×2 I2C LCD was successfully interfaced with the Arduino Uno. The desired text was displayed correctly on the LCD.

Applications

  • Temperature and humidity monitoring
  • Digital clocks
  • Smart home systems
  • Industrial automation
  • IoT-based monitoring systems
  • Embedded system user interfaces

Program

#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 16, 2);

int led = 13;
int btn = 7;
static int led_state, prev_btn_data;

void setup() {
  lcd.init();
  lcd.backlight();
  pinMode(led, OUTPUT);
  pinMode(btn, INPUT_PULLUP);
}

void loop() {
  int btn_data = digitalRead(btn);
  if (btn_data == LOW && btn_data != prev_btn_data)
  {
    led_state = !led_state;
  }
  digitalWrite(led, led_state);
  lcd.setCursor(0, 0);
  lcd.print("LED STATE:");
  lcd.print(led_state);
  prev_btn_data = btn_data;
}

Output

Experiment 3 I2C LCD displaying LED STATE:1
LCD displaying "LED STATE:1"

Experiment No. 4 – Interfacing a Relay Module with Arduino Uno

Aim

To interface a relay module with an Arduino Uno and use it to control an LED.

Objectives

  • To understand the working of a relay.
  • To learn how Arduino controls external devices through a relay.
  • To switch an LED ON and OFF using a relay.

Components Required

  • Arduino Uno
  • 5V Relay Module
  • LED
  • 220 Ω Resistor
  • Breadboard
  • Jumper Wires
  • USB Cable

Theory

A relay is an electrically operated switch that allows a low-power circuit (Arduino) to control a higher-power circuit. The relay module contains an electromagnetic coil which, when energized by the Arduino, changes the position of the switch contacts. In this experiment, the relay is used to switch an LED ON and OFF. The Arduino sends a digital signal to the relay module, causing the relay to activate and control the LED.

Circuit Connections

Relay Module to Arduino

Relay Module PinArduino Uno Pin
VCC5V
GNDGND
INDigital Pin 7

LED Connection

  • Relay COM → 5V
  • Relay NO (Normally Open) → LED Anode (+)
  • LED Cathode (–) → 220 Ω Resistor → GND

Procedure

  1. Connect the relay module to the Arduino Uno as per the circuit.
  2. Connect the LED through the relay contacts using a 220 Ω resistor.
  3. Open the Arduino IDE.
  4. Write or paste the program and select the correct board and COM port.
  5. Upload the program to the Arduino Uno.
  6. Observe the relay clicking and the LED turning ON and OFF every second.

Observation

  • The relay switches ON and OFF at one-second intervals.
  • The LED glows when the relay is activated and turns OFF when the relay is deactivated.
  • A clicking sound from the relay indicates successful switching.

Result

The relay module was successfully interfaced with the Arduino Uno, and the LED was controlled through the relay. This demonstrates how Arduino can operate external devices using a relay.

Program

const int relayPin = 7;

void setup() {
  pinMode(relayPin, OUTPUT);
}

void loop() {
  digitalWrite(relayPin, HIGH);
  delay(1000);
  digitalWrite(relayPin, LOW);
  delay(1000);
}

Output

Experiment 4 relay module controlling an LED
Wokwi simulation of relay-controlled LED

Experiment No. 5 – Interfacing a DC Motor with Arduino Uno for Speed and Direction Control

1. Aim

To interface a DC motor with an Arduino Uno and control its speed and direction of rotation using a motor driver.

2. Apparatus Required

  • Arduino Uno
  • DC motor
  • L293D motor driver IC/module
  • External DC power supply/battery
  • Connecting wires
  • Breadboard
  • USB cable
  • Computer with Arduino IDE

3. Theory

A DC motor converts electrical energy into mechanical energy and rotates when a suitable voltage is applied across its terminals.

The direction of rotation of a DC motor can be changed by reversing the polarity of the voltage applied to its terminals. Since an Arduino Uno cannot directly supply the current required by a DC motor, a motor driver such as L293D is used between the Arduino and the motor.

The L293D acts as an interface between the low-power Arduino output and the motor. It allows the motor to rotate in both directions.

Direction Control

The direction of the motor is controlled using the input pins of the motor driver:

IN1IN2Motor Direction
LOWLOWStop
HIGHLOWClockwise
LOWHIGHAnticlockwise
HIGHHIGHStop/Brake

Speed Control

The speed of the motor can be controlled using PWM (Pulse Width Modulation). Arduino generates a PWM signal using the analogWrite() function. The PWM duty cycle determines the average voltage supplied to the motor:

  • analogWrite(0) → Motor OFF
  • analogWrite(128) → Approximately 50% duty cycle
  • analogWrite(255) → Approximately 100% duty cycle

Thus, changing the PWM value changes the speed of the motor.

4. Circuit Connections

For one DC motor using an L293D:

Arduino UnoL293DFunction
Pin 9 (PWM)EN1Speed control
Pin 8IN1Direction control
Pin 7IN2Direction control
—OUT1Motor terminal 1
—OUT2Motor terminal 2
5VVCC1Logic supply
External motor supplyVCC2Motor supply
GNDGNDCommon ground

The two motor terminals are connected to OUT1 and OUT2 of the L293D.

Important: The Arduino ground and the motor-driver ground must be connected together. The motor should preferably be powered from a suitable external supply rather than directly from an Arduino I/O pin.

Procedure

  1. Connect the L293D motor driver to the Arduino Uno according to the circuit connections.
  2. Connect the DC motor to the output terminals of the L293D.
  3. Connect a suitable external power supply to the motor supply input.
  4. Ensure that the Arduino and motor-driver grounds are common.
  5. Connect the Arduino Uno to the computer using a USB cable.
  6. Open the Arduino IDE and enter the program.
  7. Select the appropriate Arduino Uno board and COM port.
  8. Upload the program to the Arduino.
  9. Observe the motor rotating in the clockwise direction.
  10. Observe the motor stopping and then rotating in the anticlockwise direction.
  11. Observe the change in motor speed when different PWM values are applied.

8. Observation

PWM ValueApprox. Duty CycleMotor Speed
00%OFF
6425%Low
12850%Medium
19275%High
255100%Maximum

The motor rotates in one direction when IN1 is HIGH and IN2 is LOW. Reversing these signals causes the motor to rotate in the opposite direction.

9. Result

The DC motor was successfully interfaced with the Arduino Uno using an L293D motor driver. The direction of rotation was controlled by digital signals, while the speed was controlled by PWM generated by the Arduino.

Program A – Speed and Direction Control using Potentiometer

const int potPin = A0;

void setup()
{
  pinMode(11, OUTPUT);
  pinMode(9, OUTPUT);
}

void loop()
{
  int potValue = analogRead(potPin);
  analogWrite(9, 0);
  analogWrite(11, potValue);
  delay(4000);
  analogWrite(9, 0);
  analogWrite(11, 0);
  delay(2000);
  analogWrite(9, potValue);
  analogWrite(11, 0);
  delay(4000);
}

Output A

Experiment 5 – DC motor with L293D and potentiometer
Tinkercad simulation: L293D, DC motor and potentiometer

Program B – Direction Control

void setup()
{
  pinMode(11, OUTPUT);
  pinMode(9, OUTPUT);
}

void loop()
{
  digitalWrite(11, HIGH);
  digitalWrite(9, LOW);
  delay(1000); // Wait for 1000 millisecond(s)

  digitalWrite(11, LOW);
  digitalWrite(9, LOW);
  delay(1000);

  digitalWrite(11, LOW);
  digitalWrite(9, HIGH);
  delay(1000);
}

Output B

Experiment 5 – DC motor direction control
Tinkercad simulation: direction control

Experiment No. 6 – Interfacing a Stepper Motor (to Move by a Particular Angle) with an Embedded Core

Aim

To control a stepper motor using an Arduino and the Stepper library by rotating it one revolution in the clockwise direction and one revolution in the anticlockwise direction, with a delay of 500 milliseconds between the rotations.

Components Required

  • Arduino board
  • Stepper motor
  • Motor driver (if required by the motor)
  • Connecting wires
  • USB cable
  • Arduino IDE

Circuit Connections

Stepper Motor PinsArduino Pins
IN1Pin 8
IN2Pin 9
IN3Pin 10
IN4Pin 11

Note: The connections depend on the stepper motor and driver being used.

Working Principle

The program uses the Arduino Stepper library to control the rotation of a stepper motor. The number of steps per revolution is set to 200, and the motor speed is configured to 60 RPM.

The setup() function initializes serial communication at 9600 baud and sets the motor speed. In the loop() function, the motor rotates one revolution clockwise using myStepper.step(stepsPerRevolution). After a delay of 500 milliseconds, it rotates one revolution in the opposite direction using myStepper.step(-stepsPerRevolution).

This process repeats continuously, allowing the motor to rotate alternately in both directions.

Observation

  • The stepper motor is initialized with 200 steps per revolution.
  • The motor speed is set to 60 RPM.
  • The motor rotates one complete revolution in the clockwise direction.
  • A delay of 500 milliseconds occurs between the rotations.
  • The motor then rotates one complete revolution in the anticlockwise direction.
  • The clockwise and anticlockwise rotation cycle repeats continuously.

Result

The stepper motor was successfully controlled using the Arduino Stepper library. The motor rotated one revolution clockwise and one revolution anticlockwise, with a delay of 500 milliseconds between the two movements.

Conclusion

The experiment demonstrates the control of a stepper motor using an Arduino and the Stepper library. The motor's speed and direction of rotation were controlled by setting the RPM and the number of steps. The experiment successfully demonstrated bidirectional motor rotation and the use of programmed delays to control motor movement.

Program

#include <Stepper.h>

const int stepsPerRevolution = 200;  // change this to fit the number of steps per revolution
                                     // for your motor

// initialize the stepper library on pins 8 through 11:
Stepper myStepper(stepsPerRevolution, 8, 9, 10, 11);

void setup() {
  // set the speed at 60 rpm:
  myStepper.setSpeed(60);
  // initialize the serial port:
  Serial.begin(9600);
}

void loop() {
  // step one revolution in one direction:
  Serial.println("clockwise");
  myStepper.step(stepsPerRevolution);
  delay(500);

  // step one revolution in the other direction:
  Serial.println("counterclockwise");
  myStepper.step(-stepsPerRevolution);
  delay(500);
}

Output

Experiment 6 stepper motor simulation (200 steps)
Wokwi simulation of the stepper motor
clockwise
counterclockwise
clockwise
counterclockwise
clockwise

Experiment No. 7 – Implementation of Power Management in STM32 Blue Pill

Aim

To implement power management in the STM32 Blue Pill using Sleep mode, with an LED connected to PC13 and a push button connected to PA0.

Components Required

  • STM32 Blue Pill (STM32F103C8T6)
  • LED
  • 220 Ω resistor
  • Push button
  • Jumper wires

Circuit Connections

ComponentSTM32 Pin
LEDPC13
Push ButtonPA0
LED other terminalGND
Push button other terminal3.3 V

PA0 is configured with an internal pull-down resistor.

Working Principle

When the STM32 is operating normally, the LED connected to PC13 is turned ON. After a short delay, the microcontroller enters Sleep mode using the WFI instruction. In Sleep mode, the CPU stops executing instructions.

When the push button connected to PA0 is pressed, an external interrupt is generated. The interrupt wakes the STM32 from Sleep mode, and the program continues execution. Thus, the push button acts as the wake-up source.

Observation

  • Initially, the LED connected to PC13 turns ON.
  • After 1 second, the STM32 enters Sleep mode.
  • The CPU waits for an interrupt.
  • When the PA0 push button is pressed, an interrupt is generated.
  • The STM32 wakes up and continues program execution.
  • The LED then changes state.

Result

The power-management operation of the STM32 Blue Pill was successfully simulated in Wokwi using PC13 as the LED output and PA0 as the push-button wake-up input.

Conclusion

The experiment demonstrates how Sleep mode and external interrupts can be used to reduce CPU activity and save power in an STM32-based embedded system. The push button connected to PA0 provides an effective wake-up mechanism.

Program

#include <Arduino.h>
#define LED_PIN PC13
#define BTN_PIN PA0

volatile bool wakeup = false;

void wakeUp() {
  wakeup = true;
}

void setup() {
  Serial.begin(115200);
  pinMode(LED_PIN, OUTPUT);
  pinMode(BTN_PIN, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(BTN_PIN), wakeUp, FALLING);
}

void loop() {
  digitalWrite(LED_PIN, LOW);
  delay(1000);
  digitalWrite(LED_PIN, HIGH);
  delay(1000);
  wakeup = false;
  while (!wakeup) {
    __WFI();
  }
}

Output

Experiment 7 STM32 Blue Pill with LED and push button
Wokwi simulation of the STM32 Blue Pill

Experiment No. 8 – Creating Multiple Tasks Using FreeRTOS

1. Aim

To create multiple tasks using FreeRTOS and understand the multitasking capability of an RTOS by executing different tasks concurrently.

2. Objective

After completing this experiment, you will be able to:

  • Understand the concept of tasks in FreeRTOS.
  • Create multiple tasks using xTaskCreate().
  • Understand task scheduling.
  • Use vTaskDelay() to control task execution.
  • Observe how FreeRTOS allows multiple tasks to share the CPU.
  • Understand the difference between sequential execution and RTOS-based multitasking.

3. Requirements

For a simple simulation, you can use:

  • Arduino Uno / ESP32 / STM32
  • Wokwi simulator
  • FreeRTOS library
  • LEDs
  • Resistors
  • Serial Monitor

4. Theory

What is an RTOS? RTOS (Real-Time Operating System) is an operating system designed to execute tasks within predictable timing constraints.

Examples: FreeRTOS, Zephyr, ThreadX, VxWorks.

FreeRTOS is widely used in embedded systems because it provides mechanisms for:

  • Task management
  • Scheduling
  • Inter-task communication
  • Synchronization
  • Timers
  • Memory management

What is a Task? A task is an independent unit of execution. For example, an embedded system may have:

  • Task 1 → Blink LED
  • Task 2 → Read Sensor
  • Task 3 → Send data through Serial

FreeRTOS manages these tasks using its scheduler.

5. Multitasking Concept

Suppose we create three tasks:

  • Task 1 → LED 1 blinking
  • Task 2 → LED 2 blinking
  • Task 3 → Display message on Serial Monitor

The CPU switches between these tasks according to the FreeRTOS scheduler. All three tasks execute under the control of the FreeRTOS scheduler.

Observation

It is observed that multiple tasks can be created and managed by FreeRTOS. When one task is delayed or blocked, the scheduler allows other ready tasks to execute. Therefore, different operations appear to run concurrently.

Result

Thus, multiple tasks were successfully created using FreeRTOS. The multitasking capability of FreeRTOS was demonstrated by simultaneously controlling two LEDs and periodically displaying messages through the Serial Monitor.

Code

#include <Arduino.h>
#include <Arduino_FreeRTOS.h>

#define LED1 2
#define LED2 3

void Task1(void *parameter)
{
  pinMode(LED1, OUTPUT);
  while (1)
  {
    digitalWrite(LED1, HIGH);
    Serial.println("Task 1: LED 1 ON");
    vTaskDelay(pdMS_TO_TICKS(500));
    digitalWrite(LED1, LOW);
    Serial.println("Task 1: LED 1 OFF");
    vTaskDelay(pdMS_TO_TICKS(500));
  }
}

void Task2(void *parameter)
{
  pinMode(LED2, OUTPUT);
  while (1)
  {
    digitalWrite(LED2, HIGH);
    Serial.println("Task 2: LED 2 ON");
    vTaskDelay(pdMS_TO_TICKS(1000));
    digitalWrite(LED2, LOW);
    Serial.println("Task 2: LED 2 OFF");
    vTaskDelay(pdMS_TO_TICKS(1000));
  }
}

void Task3(void *parameter)
{
  while (1)
  {
    Serial.println("Task 3: FreeRTOS Multitasking running...");
    vTaskDelay(pdMS_TO_TICKS(2000));
  }
}

void setup()
{
  Serial.begin(115200);
  xTaskCreate(Task1, "LED1 Task", 128, NULL, 1, NULL);
  xTaskCreate(Task2, "LED2 Task", 128, NULL, 1, NULL);
  xTaskCreate(Task3, "Serial Task", 256, NULL, 1, NULL);
}

void loop()
{
  // FreeRTOS scheduler runs tasks automatically
}

Output

Experiment 8 two LEDs on Arduino Uno controlled by FreeRTOS tasks
Wokwi simulation with two LEDs on pins 2 and 3
Task 2: LED 2 ON
Task 1: LED 1 ON
Task 1: LED 1 OFF
Task 2: LED 2 OFF
Task 1: LED 1 ON
Task 1: LED 1 OFF
Task 3: FreeRTOS Multitasking running...

Experiment No. 9 – Queue Management in FreeRTOS

Aim

To write a program to illustrate the queue management features of FreeRTOS, including creating a queue, sending data to the queue, receiving data from the queue, and demonstrating communication between tasks.

Objectives

  • To understand the concept of queues in FreeRTOS.
  • To create and initialize a queue.
  • To send data from one task to another using a queue.
  • To receive data from a queue.
  • To understand task synchronization using queues.

Theory

A queue in FreeRTOS is an inter-task communication mechanism used to transfer data between tasks. A queue follows the FIFO (First-In, First-Out) principle.

A queue can be created using:

QueueHandle_t xQueueCreate( UBaseType_t uxQueueLength,
                            UBaseType_t uxItemSize );

Important queue functions include:

  • xQueueCreate() – Creates a queue.
  • xQueueSend() – Sends an item to the queue.
  • xQueueReceive() – Receives an item from the queue.
  • uxQueueMessagesWaiting() – Returns the number of items currently in the queue.
  • vQueueDelete() – Deletes a queue.

Queues are particularly useful when one task produces data and another task consumes it. They also provide synchronization between tasks.

Working

  1. A queue capable of storing 5 integer values is created using xQueueCreate().
  2. The Producer Task generates integer data and sends it to the queue using xQueueSend().
  3. The Consumer Task waits for data using xQueueReceive().
  4. When data is available, the consumer receives and displays it.
  5. If the queue becomes full, xQueueSend() can fail after the specified timeout.
  6. portMAX_DELAY allows the consumer task to wait until an item becomes available.
  7. The FreeRTOS scheduler manages the execution of both tasks.

Result

The program successfully demonstrates FreeRTOS queue management by creating a queue and using it for communication between a producer task and a consumer task. The experiment demonstrates queue creation, data insertion, data retrieval, FIFO operation, and task synchronization.

Conclusion

Thus, the queue management features of FreeRTOS were successfully illustrated. Queues provide a safe and efficient mechanism for exchanging data between tasks and are widely used in real-time embedded applications.

Program

#include <Arduino.h>
#include <Arduino_FreeRTOS.h>
#include <queue.h>
#include <semphr.h>
#include <stdlib.h>

// Queue and synchronization handles
QueueHandle_t dataQueue;
SemaphoreHandle_t serialMutex;
SemaphoreHandle_t receivedSemaphore;

// Task declarations
void ProducerTask(void *pvParameters);
void ConsumerTask(void *pvParameters);

void setup()
{
  Serial.begin(9600);

  // Queue stores 5 integers
  dataQueue = xQueueCreate(5, sizeof(int));

  // Mutex protects Serial output
  serialMutex = xSemaphoreCreateMutex();

  // Consumer signals when a number is received
  receivedSemaphore = xSemaphoreCreateBinary();

  if (dataQueue == NULL ||
      serialMutex == NULL ||
      receivedSemaphore == NULL)
  {
    Serial.println("Queue or semaphore creation failed!");
    while (1);
  }

  Serial.println("Queue created successfully.");
  Serial.println("Enter numbers separated by spaces or commas:");

  xTaskCreate(ProducerTask, "Producer", 128, NULL, 1, NULL);
  xTaskCreate(ConsumerTask, "Consumer", 128, NULL, 1, NULL);
}

void loop()
{
  // FreeRTOS tasks run independently
}

// Producer Task: Read and send numbers one at a time
void ProducerTask(void *pvParameters)
{
  char input[12];
  int index = 0;

  while (1)
  {
    while (Serial.available() > 0)
    {
      char ch = Serial.read();

      if (ch == ' ' || ch == ',' ||
          ch == '\n' || ch == '\r' || ch == '\t')
      {
        if (index > 0)
        {
          input[index] = '\0';
          int number = atoi(input);
          index = 0;

          // Display entered number
          xSemaphoreTake(serialMutex, portMAX_DELAY);
          Serial.print("Entered: ");
          Serial.println(number);
          xSemaphoreGive(serialMutex);

          // Send number to queue
          if (xQueueSend(dataQueue, &number,
                         portMAX_DELAY) == pdPASS)
          {
            // Wait until Consumer receives it
            xSemaphoreTake(receivedSemaphore, portMAX_DELAY);
          }
        }
      }
      else if (ch >= '0' && ch <= '9')
      {
        if (index < 11)
        {
          input[index++] = ch;
        }
      }
    }
    vTaskDelay(pdMS_TO_TICKS(10));
  }
}

// Consumer Task: Receive and acknowledge each number
void ConsumerTask(void *pvParameters)
{
  int receivedNumber;

  while (1)
  {
    if (xQueueReceive(dataQueue, &receivedNumber,
                      portMAX_DELAY) == pdPASS)
    {
      xSemaphoreTake(serialMutex, portMAX_DELAY);
      Serial.print("Received: ");
      Serial.println(receivedNumber);
      xSemaphoreGive(serialMutex);

      // Notify Producer that this number was received
      xSemaphoreGive(receivedSemaphore);
    }
  }
}

Experiment No. 10 – Task Synchronization Using Binary and Counting Semaphores

Aim

To write and execute a FreeRTOS program in Wokwi that demonstrates task synchronization using:

  • Binary Semaphore
  • Counting Semaphore

The experiment shows how semaphores allow multiple FreeRTOS tasks to coordinate access to shared resources and events.

Software/Hardware Requirements

  • Wokwi online simulator
  • ESP32 development board
  • FreeRTOS (included with the ESP32 Arduino framework)
  • Arduino IDE-compatible code

Theory

Binary Semaphore

A binary semaphore can have only two states:

  • Available (1)
  • Not available (0)

It is commonly used for task synchronization. For example, one task can generate an event and give the semaphore, while another task waits for that event.

In FreeRTOS:

xSemaphoreGive(binarySemaphore);

is used to release/give the semaphore, while:

xSemaphoreTake(binarySemaphore, portMAX_DELAY);

waits until the semaphore becomes available.

Counting Semaphore

A counting semaphore can have a value ranging from 0 to a specified maximum count. It is useful when there are multiple identical resources or multiple events that need to be counted.

For example, if a counting semaphore has a maximum count of 3, three semaphore tokens can be available simultaneously.

xSemaphoreCreateCounting(3, 0);

Here: 3 = maximum count, 0 = initial count.

Circuit in Wokwi

Use an ESP32 with two LEDs:

ComponentESP32 Pin
Binary Semaphore LEDGPIO 2
Counting Semaphore LEDGPIO 4

Connect each LED through a 220 Ω resistor to GND.

Observation

  • The binary semaphore synchronizes the binary producer and binary consumer tasks.
  • The binary consumer executes only after the producer gives the semaphore.
  • The counting semaphore maintains a count of available tokens.
  • The maximum counting semaphore value in this experiment is 3.
  • FreeRTOS tasks execute concurrently under the control of the FreeRTOS scheduler.
  • LEDs provide a visual indication that the corresponding consumer task has received a semaphore.

Result

The program was successfully designed to demonstrate task synchronization using Binary and Counting Semaphores in FreeRTOS. The binary semaphore was used to synchronize an event between two tasks, while the counting semaphore was used to maintain multiple semaphore tokens. The experiment can be implemented and simulated using an ESP32 in Wokwi.

Conclusion

This experiment demonstrates that semaphores are important synchronization mechanisms in FreeRTOS. A binary semaphore is suitable when a task needs to signal a single event, whereas a counting semaphore is useful when multiple events or resources must be tracked. Using these mechanisms prevents tasks from operating without the required synchronization and makes multitasking systems more reliable.

Program

#include <Arduino.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"

// Semaphore handles
SemaphoreHandle_t binarySemaphore;
SemaphoreHandle_t countingSemaphore;

// LED pins
#define BINARY_LED 2
#define COUNTING_LED 4

// ----------------------------------------------------
// Task 1: Generates events for Binary Semaphore
// ----------------------------------------------------
void binaryProducer(void *parameter)
{
  while (1)
  {
    Serial.println("Binary Producer: Event generated");

    // Give binary semaphore
    xSemaphoreGive(binarySemaphore);

    vTaskDelay(pdMS_TO_TICKS(2000));
  }
}

// ----------------------------------------------------
// Task 2: Waits for Binary Semaphore
// ----------------------------------------------------
void binaryConsumer(void *parameter)
{
  while (1)
  {
    // Wait for binary semaphore
    if (xSemaphoreTake(binarySemaphore, portMAX_DELAY) == pdTRUE)
    {
      Serial.println("Binary Consumer: Semaphore received");

      digitalWrite(BINARY_LED, HIGH);
      vTaskDelay(pdMS_TO_TICKS(500));
      digitalWrite(BINARY_LED, LOW);
    }
  }
}

// ----------------------------------------------------
// Task 3: Generates events for Counting Semaphore
// ----------------------------------------------------
void countingProducer(void *parameter)
{
  while (1)
  {
    Serial.println("Counting Producer: Adding token");

    // Give counting semaphore
    if (xSemaphoreGive(countingSemaphore) == pdTRUE)
    {
      Serial.println("Counting Semaphore: Token added");
    }
    else
    {
      Serial.println("Counting Semaphore: Maximum count reached");
    }

    vTaskDelay(pdMS_TO_TICKS(1000));
  }
}

// ----------------------------------------------------
// Task 4: Takes tokens from Counting Semaphore
// ----------------------------------------------------
void countingConsumer(void *parameter)
{
  while (1)
  {
    // Wait for a counting semaphore token
    if (xSemaphoreTake(countingSemaphore, portMAX_DELAY) == pdTRUE)
    {
      Serial.println("Counting Consumer: Token received");

      digitalWrite(COUNTING_LED, HIGH);
      vTaskDelay(pdMS_TO_TICKS(300));
      digitalWrite(COUNTING_LED, LOW);
      vTaskDelay(pdMS_TO_TICKS(700));
    }
  }
}

// ----------------------------------------------------
// Setup
// ----------------------------------------------------
void setup()
{
  Serial.begin(115200);

  pinMode(BINARY_LED, OUTPUT);
  pinMode(COUNTING_LED, OUTPUT);

  // Create Binary Semaphore
  binarySemaphore = xSemaphoreCreateBinary();

  // Create Counting Semaphore
  // Maximum count = 3
  // Initial count = 0
  countingSemaphore = xSemaphoreCreateCounting(3, 0);

  if (binarySemaphore == NULL || countingSemaphore == NULL)
  {
    Serial.println("Semaphore creation failed!");
    while (1);
  }

  Serial.println("Semaphores created successfully.");

  // Create FreeRTOS tasks
  xTaskCreate(binaryProducer,   "Binary Producer",   2048, NULL, 1, NULL);
  xTaskCreate(binaryConsumer,   "Binary Consumer",   2048, NULL, 1, NULL);
  xTaskCreate(countingProducer, "Counting Producer", 2048, NULL, 1, NULL);
  xTaskCreate(countingConsumer, "Counting Consumer", 2048, NULL, 1, NULL);
}

// ----------------------------------------------------
// Loop
// ----------------------------------------------------
void loop()
{
  // FreeRTOS tasks perform the actual work.
  vTaskDelay(pdMS_TO_TICKS(1000));
}

Post a Comment

0 Comments
* Please Don't Spam Here. All the Comments are Reviewed by Admin.