Аппаратное прерывание с двоичным семафором FreeRTOS

Я в основном пытаюсь заставить светодиод загореться после нажатия кнопки. Ниже приведен фрагмент кода, который должен справиться с этим:

void task_player1(void *pvParameters)
{   
    while (1)
    {
        if (xSemaphoreTake(player1_signal, portMAX_DELAY))
        {
            printf(">>>Semaphore taken\n<<<");
            ioport_set_pin_level(L1, HIGH);
            xSemaphoreGive(player1_signal);
        }
        else
        {
            ioport_set_pin_level(L1, LOW);
        }
    }
}

void task_ctrl(void *pvParameters)
{
    bool button1 = 0;       
    
    while (1)
    {
        button1 = ioport_get_pin_level(B1);
        if (button1)
        {
            xSemaphoreGive(player1_signal);
            printf("Semaphore given\n");
        }
    }
}

Я предполагаю, что task_ctrl выдает семафор при нажатии кнопки. Task_player1 блокируется до тех пор, пока не займет семафор, после чего должен включиться светодиод.

Проблема в том, что он никогда не принимает семафор. Я использую операторы printf, чтобы показать мне, насколько далеко программа заходит и никогда не попадает в ту часть, где горит светодиод. Но когда я запускаю xSemaphoreGive без нажатия кнопки task_ctrl, семафор берется.

Странная часть заключается в том, что оператор "Semaphore given\n" распечатывается при нажатии кнопки, что должно означать, что семафор также передается, но никогда не используется.

Задачи работают сами по себе, мне даже удалось передать семафор без if-оператора нажатия кнопки, как я сказал выше.

Я предполагаю, что это что-то с кодом нажатия кнопки, который также работает сам по себе вне задач. Так что я делаю не так? Я неправильно использую FreeRTOS?

Изменить: включая код создания задачи

#define TASK_STACK_SIZE (2048/ sizeof(portSTACK_TYPE))

xTaskCreate(task_ctrl, (const signed char * const) "Control", TASK_STACK_SIZE, NULL, 1, NULL);
    
xTaskCreate(task_player1, (const signed char * const) "Player1", TASK_STACK_SIZE, NULL, 1, NULL);

Изменить 2: Вероятно, я должен был упомянуть, что я использую FreeRTOS 7.3, поскольку у Atmel Studio нет более новых версий. Так что, насколько я могу судить, никаких функций доходности нет.


person Tisa    schedule 25.12.2017    source источник
comment
Каковы приоритеты задач? Если task_ctrl имеет более высокий или равный приоритет и поскольку он никогда не возвращает состояние выполнения, состояние task_player1 никогда не запускается.   -  person seleciii44    schedule 25.12.2017
comment
Не могли бы вы показать код нажатия кнопки и создания задачи?   -  person Ed King    schedule 25.12.2017
comment
В заголовке упоминается аппаратное прерывание, но в этом коде аппаратные прерывания не используются.   -  person Clifford    schedule 25.12.2017
comment
@ seleciii44 Да, у task_ctrl был более высокий приоритет, из-за чего task_player1 никогда не запускался. Если я отменим априори, task_ctrl никогда не запустится, и если они равны, task_player1 никогда не будет заблокирован в ожидании семафора, как я думал.   -  person Tisa    schedule 25.12.2017
comment
Это описано в первых главах бесплатной книги FreeRTOS - если вы хотите изучить FreeRTOS, это хорошая отправная точка: freertos.org/Documentation/RTOS_book.html   -  person Richard    schedule 28.12.2017


Ответы (1)


task_ctrl никогда не блокируется - это предотвратит выполнение любой задачи с таким же или более низким приоритетом когда-либо. Таким образом, если task_player имеет равный или более низкий приоритет, задача никогда не будет запланирована, даже если задан семафор.

Кажется, что он работает без опроса кнопок, который сложнее объяснить, но вы не показали этот код, поэтому я не могу комментировать.

Вам следует сделать две вещи:

  1. Убедитесь, что task_ctrl имеет более низкий приоритет, чем по крайней мере task_player1 (и ниже, чем у любой задачи, если она не блокируется - в этом случае неактивная задача никогда не будет запущена).
  2. Убедитесь, что task_ctrl блокируется - даже если это всего лишь задержка опроса, чтобы не поглотить все доступные циклы ЦП.

while (1)
{
    button1 = ioport_get_pin_level(B1);
    if (button1)
    {
        xSemaphoreGive(player1_signal);
        printf("Semaphore given\n");

        vtaskDelay( 1 ) ; // at least 1 tick
    }
}

Одна из возможных проблем с task_ctrl заключается в том, что он будет выдавать семафор непрерывно и многократно, пока кнопка удерживается. Может быть предпочтительнее какое-то обнаружение изменения состояния и устранение дребезга переключателя, а не опрос уровня.

Альтернативным решением задачи опроса является использование аппаратного прерывания для кнопки и либо блок задачи опроса для события из ISR, либо ISR напрямую передает семафор - в любом случае вам придется иметь дело с отладкой.

person Clifford    schedule 25.12.2017
comment
Вы были правы насчет приоритета задачи, я изменил его так, что task_player1 имеет более высокий приоритет, чем task_ctrl, но теперь есть другая проблема. Task_player1 никогда не блокируется, то есть светодиод всегда горит без нажатия кнопки, а task_ctrl даже не запускается. Когда я меняю их на равный приоритет, обе задачи запускаются одновременно, и task_player1 все еще не заблокирован, как должен быть. - person Tisa; 25.12.2017
comment
@Tisa: Вам лучше задать новый вопрос с новой проблемой и ее кодом. - person Clifford; 25.12.2017