Операционная система реального времени FreeRTOS – это простая, легкая в использовании, надежная ОС, оптимизированная для Arduino IDE. В предыдущей статье мы рассмотрели, как использовать многозадачтость FreeRTOS в Arduino IDE. В этом проекте мы покажем, как использовать семафоры FreeRTOS для совместного использования и защиты физических ресурсов.

В среде Arduino IDE и среде доступно множество драйверов и библиотек, но среда Arduino ограничена простыми базовыми функциями setup() и loop() и не поддерживает эффективную многозадачность. В этой статье описывается использование мьютекс-семафоров в рамках простой в использовании и надежной реализации FreeRTOS, которая включена в Arduino IDE в качестве библиотеки и позволяет использовать лучшие функции обеих сред.
Большинство операционных систем позволяют одновременно выполнять несколько программ или потоков. Это называется многозадачностью. В действительности каждое ядро процессора может работать только с одной программой в любой момент времени. Часть операционной системы, называемая планировщиком, отвечает за решение, какую программу запускать и когда, и обеспечивает иллюзию одновременного выполнения, быстро переключаясь между каждой программой.
Традиционные планировщики реального времени, такие как планировщик, используемый в FreeRTOS, достигают детерминизма, позволяя пользователю назначать приоритет каждому потоку выполнения. Затем планировщик использует приоритет, чтобы узнать, какой поток выполнения будет запущен следующим. В FreeRTOS поток выполнения называется задачей.
Когда две или более задач совместно используют один аппаратный ресурс, такой как последовательный порт, может возникнуть ситуация, когда планировщик переведет в фоновый режим одну задачу перед завершением последовательного вывода, а другая задача начнется и может обеспечить некоторый последовательный вывод, который будет организован поверх вывода первой задачи.
Этой ситуации можно избежать, используя семафор (также называемый флагом) для защиты аппаратного ресурса и предотвращения его использования до тех пор, пока он не будет выпущен задачей, использующей его.
Мьютексные семафоры – это двоичные семафоры, которые включают механизм наследования приоритетов. В то время как бинарные семафоры являются лучшим выбором для реализации синхронизации (между задачами или между задачами и прерыванием), мьютексные семафоры являются лучшим выбором для реализации простого взаимного исключения. В этом примере мы будем использовать мьютексный семафор для защиты нашего последовательного порта.
При взаимном исключении мьютекс действует как токен, который используется для защиты ресурса. Когда задача желает получить доступ к ресурсу, она должна сначала получить или «взять» токен. По завершении работы с ресурсом он должен «вернуть» токен, предоставив другим задачам возможность получить доступ к тому же ресурсу.
В предыдущей статье мы описали, как установить библиотеку FreeRTOS для Arduino IDE и проверить, что она работает правильно. Если вы еще не сделали этот шаг, сделайте это сейчас.
Теперь либо загрузите файл AnalogRead_DigitalRead.ino в Arduino IDE, либо скопируйте и вставьте приведенный ниже код в новый файл, который вы должны соответствующим образом назвать и сохранить. В скетче есть несколько шагов для создания и использования мьютексного семафора для защиты последовательного порта. Соответствующая данному скетчу схема подключения приведена далее.

Теперь, когда задача желает использовать функции Serial.println() последовательного порта, она должна убедиться, что она заранее «приняла» семафор последовательного порта. Когда задача с последовательным портом завершается, она должна «отдать» семафор, чтобы другие задачи могли получить доступ к порту.
#include <Arduino_FreeRTOS.h>
#include <semphr.h>
SemaphoreHandle_t xSerialSemaphore;
void TaskDigitalRead( void *pvParameters );
void TaskAnalogRead( void *pvParameters );
void setup() {
Serial.begin(9600);
if ( xSerialSemaphore == NULL )
{
xSerialSemaphore = xSemaphoreCreateMutex();
if ( ( xSerialSemaphore ) != NULL )
xSemaphoreGive( ( xSerialSemaphore ) );
}
xTaskCreate(
TaskDigitalRead
, (const portCHAR *)"DigitalRead"
, 128
, NULL
, 2
, NULL );
xTaskCreate(
TaskAnalogRead
, (const portCHAR *) "AnalogRead"
, 128
, NULL
, 1
, NULL );
}
void loop()
{
}
void TaskDigitalRead( void *pvParameters __attribute__((unused)) )
{
uint8_t pushButton = 2;
pinMode(pushButton, INPUT);
for (;;)
{
int buttonState = digitalRead(pushButton);
if ( xSemaphoreTake( xSerialSemaphore, ( TickType_t ) 5 ) == pdTRUE )
{
Serial.println(buttonState);
xSemaphoreGive( xSerialSemaphore );
}
vTaskDelay(1);
}
}
void TaskAnalogRead( void *pvParameters __attribute__((unused)) )
{
for (;;)
{
int sensorValue = analogRead(A0);
if ( xSemaphoreTake( xSerialSemaphore, ( TickType_t ) 5 ) == pdTRUE )
{
Serial.println(sensorValue);
xSemaphoreGive( xSerialSemaphore );
}
vTaskDelay(1);
}
}
© digitrode.ru