Real-Time Programming with C
7 mins read

Real-Time Programming with C

Explore real-time programming concepts using C, including real-time operating systems (RTOS), task scheduling, and event-driven programming for embedded systems.

Real-time programming involves writing software that meets specific timing requirements and responds promptly to external events. It is crucial for applications that demand precise timing, such as embedded systems, control systems, robotics, and telecommunications. This explanation will delve into real-time programming concepts using the C programming language, covering real-time operating systems (RTOS), task scheduling, and event-driven programming for embedded systems.

Real-Time Operating Systems (RTOS):

A Real-Time Operating System (RTOS) is an operating system designed to handle tasks with specific timing requirements and ensure that critical tasks are executed within their deadlines. RTOS is commonly used in embedded systems, robotics, industrial automation, and other applications where timely and predictable execution is crucial. Let’s explore RTOS in detail with a simple program and its output explanation.

Example: Real-Time Task Scheduling using FreeRTOS:

FreeRTOS is a popular open-source RTOS that provides task scheduling, synchronization mechanisms, and memory management. Here’s a simple example of a real-time task scheduling program using FreeRTOS on an Arduino board.

Program: Real-Time LED Blinking using FreeRTOS

#include <Arduino_FreeRTOS.h>
#include <semphr.h>

// Define a semaphore
SemaphoreHandle_t xSemaphore;

// Task handles
TaskHandle_t Task1_Handle;
TaskHandle_t Task2_Handle;

// Task function for blinking LED 1
void Task1(void *pvParameters) {
  while (1) {
    xSemaphoreTake(xSemaphore, portMAX_DELAY);
    digitalWrite(13, HIGH);
    vTaskDelay(pdMS_TO_TICKS(500));
    digitalWrite(13, LOW);
    vTaskDelay(pdMS_TO_TICKS(500));
    xSemaphoreGive(xSemaphore);
  }
}

// Task function for blinking LED 2
void Task2(void *pvParameters) {
  while (1) {
    xSemaphoreTake(xSemaphore, portMAX_DELAY);
    digitalWrite(12, HIGH);
    vTaskDelay(pdMS_TO_TICKS(300));
    digitalWrite(12, LOW);
    vTaskDelay(pdMS_TO_TICKS(300));
    xSemaphoreGive(xSemaphore);
  }
}

void setup() {
  // Create a semaphore
  xSemaphore = xSemaphoreCreateMutex();

  // Initialize LED pins
  pinMode(13, OUTPUT);
  pinMode(12, OUTPUT);

  // Create tasks
  xTaskCreate(Task1, "Task1", 128, NULL, 1, &Task1_Handle);
  xTaskCreate(Task2, "Task2", 128, NULL, 1, &Task2_Handle);

  // Start the FreeRTOS scheduler
  vTaskStartScheduler();
}

void loop() {
  // Empty loop (scheduler takes over)
}

Explanation:

  1. #include <Arduino_FreeRTOS.h>: Include the FreeRTOS library for Arduino.
  2. SemaphoreHandle_t xSemaphore;: Declare a semaphore variable.
  3. TaskHandle_t Task1_Handle; and TaskHandle_t Task2_Handle;: Task handles for task management.
  4. void Task1(void *pvParameters): Task function for blinking LED 1. It toggles LED 13 every 500 ms.
  5. void Task2(void *pvParameters): Task function for blinking LED 2. It toggles LED 12 every 300 ms.
  6. xSemaphoreTake(xSemaphore, portMAX_DELAY);: Acquire the semaphore to access shared resources.
  7. digitalWrite(13, HIGH);: Turn on LED 13.
  8. vTaskDelay(pdMS_TO_TICKS(500));: Delay the task for 500 ms.
  9. digitalWrite(13, LOW);: Turn off LED 13.
  10. xSemaphoreGive(xSemaphore);: Release the semaphore after task execution.
  11. void setup(): Setup function where tasks, semaphore, and LEDs are initialized.
  12. void loop(): Empty loop; the scheduler takes over task execution.

Output Explanation:

  • The program uses two tasks to control LEDs 13 and 12.
  • The xSemaphoreTake function is used to acquire the semaphore before accessing shared resources (LEDs).
  • Each task toggles its respective LED and then releases the semaphore using xSemaphoreGive.
  • The tasks alternate between accessing the LEDs based on the semaphore’s availability.
  • LED 13 blinks every 500 ms, and LED 12 blinks every 300 ms.

Task Scheduling:

Task scheduling is a fundamental concept in real-time programming and operating systems. It involves managing the execution of tasks or processes in a way that ensures efficient resource utilization and meets timing requirements. Task scheduling is crucial in real-time systems, where tasks have different priorities and deadlines. Let’s explore task scheduling in detail with a simple program and its output explanation.

Example: Task Scheduling using FreeRTOS:

FreeRTOS is an open-source real-time operating system that provides task scheduling, synchronization, and communication mechanisms. Here’s a simple example of task scheduling using FreeRTOS on an Arduino board.

Program: Task Scheduling with FreeRTOS

#include <Arduino_FreeRTOS.h>

// Task handles
TaskHandle_t Task1_Handle;
TaskHandle_t Task2_Handle;

// Task function for Task 1
void Task1(void *pvParameters) {
  while (1) {
    Serial.println("Task 1 is running...");
    vTaskDelay(pdMS_TO_TICKS(1000)); // Delay for 1000 ms (1 second)
  }
}

// Task function for Task 2
void Task2(void *pvParameters) {
  while (1) {
    Serial.println("Task 2 is running...");
    vTaskDelay(pdMS_TO_TICKS(500)); // Delay for 500 ms (0.5 seconds)
  }
}

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

  // Create tasks
  xTaskCreate(Task1, "Task1", 128, NULL, 1, &Task1_Handle);
  xTaskCreate(Task2, "Task2", 128, NULL, 1, &Task2_Handle);

  // Start the FreeRTOS scheduler
  vTaskStartScheduler();
}

void loop() {
  // Empty loop (scheduler takes over)
}

Explanation:

  1. #include <Arduino_FreeRTOS.h>: Include the FreeRTOS library for Arduino.
  2. TaskHandle_t Task1_Handle; and TaskHandle_t Task2_Handle;: Task handles for task management.
  3. void Task1(void *pvParameters): Task function for Task 1. It prints a message and delays for 1 second.
  4. void Task2(void *pvParameters): Task function for Task 2. It prints a message and delays for 0.5 seconds.
  5. Serial.begin(9600);: Initialize serial communication for debugging.
  6. xTaskCreate(Task1, "Task1", 128, NULL, 1, &Task1_Handle);: Create Task 1 with priority 1.
  7. xTaskCreate(Task2, "Task2", 128, NULL, 1, &Task2_Handle);: Create Task 2 with priority 1.
  8. vTaskStartScheduler();: Start the FreeRTOS scheduler to manage task execution.

Output Explanation:

  • The program uses two tasks: Task 1 and Task 2.
  • Task 1 prints “Task 1 is running…” every 1 second.
  • Task 2 prints “Task 2 is running…” every 0.5 seconds.
  • The tasks are scheduled based on their priorities, but the actual scheduling may vary depending on system load and other factors.

Expected Output:

Task 2 is running...
Task 2 is running...
Task 1 is running...
Task 2 is running...
Task 2 is running...
Task 1 is running...
...

Event-Driven Programming for Embedded Systems:

Event-driven programming is a programming paradigm where the flow of the program is determined by events, such as user actions or external signals. In embedded systems, event-driven programming is crucial for responding promptly to external stimuli and efficiently utilizing system resources. Let’s explore event-driven programming in detail with a simple program and its output explanation.

Example: Event-Driven LED Control using Arduino:

In this example, we will use event-driven programming to control an LED using a button press on an Arduino board. When the button is pressed, the LED will toggle its state.

Program: Event-Driven LED Control

const int buttonPin = 2; // Button connected to digital pin 2
const int ledPin = 13;   // LED connected to digital pin 13

volatile bool buttonPressed = false;

void setup() {
  pinMode(buttonPin, INPUT);
  pinMode(ledPin, OUTPUT);
  attachInterrupt(digitalPinToInterrupt(buttonPin), buttonInterrupt, CHANGE);
  Serial.begin(9600);
}

void loop() {
  if (buttonPressed) {
    digitalWrite(ledPin, !digitalRead(ledPin)); // Toggle LED state
    buttonPressed = false; // Reset buttonPressed flag
    Serial.println("Button pressed!");
  }
}

void buttonInterrupt() {
  buttonPressed = true; // Set buttonPressed flag
}

Explanation:

  1. const int buttonPin = 2; and const int ledPin = 13;: Define pin numbers for the button and LED.
  2. volatile bool buttonPressed = false;: A volatile flag to indicate if the button is pressed.
  3. void setup(): Initialize pins, attach interrupt, and begin serial communication.
  4. void loop(): Check the buttonPressed flag and toggle the LED state when the button is pressed.
  5. void buttonInterrupt(): An interrupt service routine (ISR) triggered when the button state changes.

Output Explanation:

  • When the button is pressed, the LED toggles its state.
  • Each button press triggers an interrupt, which sets the buttonPressed flag.
  • The loop() function checks the flag and toggles the LED if the flag is true.
  • The program prints “Button pressed!” to the serial monitor when the LED state changes.

Expected Output:

Button pressed!
Button pressed!
Button pressed!
...

Leave a Reply

Your email address will not be published. Required fields are marked *