Содержание

OSA : Бинарные семафоры

Введение

Бинарные семафоры - системные переменные, способные принимать значения "0" и "1". Это самый простой способ обмена информацией между задачами, а также для синхронизации между ними. Для экономии RAM в OSA все бинарные семафоры являются битовыми полями в переменных, создаваемых самой системой. Программист должен только указать, сколько памяти выделить под бинарные семафоры, задав в файле OSAcfg.h константу OS_BSEMS. Поэтому память под бинарные семафоры резервируется на этапе компиляции и их нельзя создавать или удалять в ходе работы программы.

Идентификация

При обращении к системным сервисам, управляющим бинарными семафорами, нужно указывать номер используемого семафора от 0 до (OS_BSEMS-1), т.е. его идентификатор. Идентефикаторы семафорам удобно присваивать в виде enum, тогда есть гарантия, что они не будут пересекаться:

enum OSA_BINSEMS_ENUM
{
    BS_BUTTON_PRESSED,
    BS_USART_FREE,
    BS_WRITE_COMPLETE,
    . . .
};

Такой подход не очень удобен, особенно, если предполагается использование отдельно написанных модулей, но является очень экономным к ресурсам ПИКа (и ROM, и RAM, и скорость): на 8 бинарных семафоров требуется всего один байт ОЗУ. Если же требуются независимые семафоры, то можно использовать счетные семафоры с сервисом установки семафора OS_Csem_Set.

Работа с бинарными семафорами

После начальной инициализации сервисом OS_Init все бинарные семафры сброшены. Задача, которая ожидает бинарный семафор, будет поставлена в состояние ожидания до тех пор, пока семафор не будет установлен. Как только он установится, задача переходит в состояние готовности и при получении управления сбрасывает семафор.

Ниже приведен небольшой пример использования бинарного семафора для разделения доступа к общему ресурсу - внешенй EEPROM:

#include <osa.h>
 
enum OSA_BINSEMS_ENUM {
    BS_EEPROM_FREE
};
 
void Task1 (void)
{
    for (;;) {
        ...
        OS_Bsem_Wait(BS_EEPROM_FREE);     // Ждем, когда остальные задачи отпустят eeprom
 
        // Когда попадаем сюда, eeprom свободен, а семафор сброшен, что не позволит другим
        // задачам начать работу с eeprom
        eeprom_read(1);
        eeprom_read(2);
        OS_Bsem_Set(BS_EEPROM_FREE);      // После выполнения операций с EEPROM освобождаем ресурс
        ...
    }
}
 
void Task2 (void)
{
    for (;;) {
        ...
        OS_Bsem_Wait(BS_EEPROM_FREE);     // Ждем, когда остальные задачи отпустят eeprom
 
        // Когда попадаем сюда, eeprom свободен, а семафор сброшен, что не позволит другим
        // задачам начать работу с eeprom
        eeprom_write(5, 10);
        OS_Delay(5);                     // Ждем окончания записи. При ожидании задержки
                                         // управление передается планировщику, который может
                                         // в свою очередь передать управление задаче Task1. И чтобы
                                         // Task1 не полезла в EEPROM, ресурс заблокирован бинарынм
                                         // семафором
        eeprom_write(6, 20);
        OS_Delay(5);
        OS_Bsem_Set(BS_EEPROM_FREE);      // После выполнения операций с EEPROM освобождаем ресурс
        ...
    }
}

Размещение в памяти

Для PIC16 программист может выбрать, в каком банке RAM будут храниться бинарные семафоры. Для этого есть константа OS_BANK_BSEMS, которая может принимать значения от 0 до 3. Все бинарные семафоры размещаются в одном банке; нельзя половину опрелелить,например, в bank0, а оставшиеся - в bank2. В памяти бинарные семафоры представлены как массив unsigned char, поэтому эта структура неделима.

Сервисы для работы с двоичными семафорами.

Сервис Аргументы Описание Свойства
Управление
OS_Bsem_Set (bsem) Устанавливает семафор Есть расширенный сервис с суффиксом _I для работы в прерывании
OS_Bsem_Reset (bsem) Сбрасывает семафор Есть расширенный сервис с суффиксом _I для работы в прерывании
OS_Bsem_Switch (bsem) Переключает семафор в противоположное состояние Есть расширенный сервис с суффиксом _I для работы в прерывании
Проверка
OST_WORD
OS_Bsem_Check
(bsem) Смотрим, установлен ли конкретный семафор Есть расширенный сервис с суффиксом _I для работы в прерывании
Ожидание
OS_Bsem_Wait (bsem) Ожидаем установку семафора. Разрешен вызов только в контексте задачиПереключает контекст
OS_Bsem_Wait_TO (bsem, timeout) Ожидаем установку семафора с таймаутом. Разрешен вызов только в контексте задачиПереключает контекстИспользует системный таймер