Исправлено время выполнения задачи в RTE KEIL RTX

Я использую KEIL RTX RTOS, в которой использовался упреждающий циклический планировщик. У меня есть ЖК-дисплей для отображения данных, и некоторые задачи имеют доступ к этому ЖК-дисплею (есть и другие задачи), Эти задачи требуют фиксированного времени для обработки ЖК-дисплея (например, первый дескриптор задачи отображает данные в течение 50 секунд и через 50 секунд, второй дескриптор задачи и отображает данные в течение 10 секунд). Я знаю, что должен использовать мьютекс для управления доступом к LCD. Но я не знаю, как мне управлять им в течение фиксированного времени? Задачи LCD имеют самый низкий приоритет, и если нет других задач для выполнения, эти задачи будут выполняться для отображения сообщений.,

3 ответа

Решение

Сначала я постараюсь ответить на ваш вопрос, но затем я собираюсь предложить вам альтернативный вариант.

Вы должны использовать Таймер, чтобы основывать что-либо в реальном времени, особенно относительно длительный период, подобный тому, который измеряется в секундах. Создайте два объекта Timer, один с периодом 50 секунд и один с периодом 10 секунд. Оба таймера должны быть однократного типа. Также создайте два объекта Signal, один для указания того, что 50-секундный период истек, а другой для указания того, что 10-секундный период истек. Каждый из двух объектов Timer вызывает разные функции обратного вызова по истечении срока действия. Функция обратного вызова в 50 секунд должна установить сигнал истечения 50 секунд, а затем запустить таймер на 10 секунд. Функция обратного вызова в течение 10 секунд должна установить сигнал истечения 10 секунд, а затем перезапустить 50-секундный таймер. Таймеры будут пинг-понг взад и вперед, попеременно устанавливая два сигнала.

Теперь ваш ресурс, использующий задачи, должен периодически проверять соответствующий сигнал истечения срока действия. Когда задача наблюдает, что Сигнал установлен, он может отказаться от ресурса и очистить Сигнал. Другая задача делает то же самое с другим сигналом. Таким образом, две задачи знают, когда следует отказаться от ресурса, и разрешить другой задаче его получить.

Что меня беспокоит в вашем дизайне, так это то, что у вас есть два механизма синхронизации, защищающих ваш ресурс. Мьютекс - это механизм синхронизации. Когда задачи связаны с асинхронным использованием ресурса (т. Е. В случайное время), можно использовать мьютекс для синхронизации этих использований и гарантировать, что только одна задача использует ресурс в любой момент времени. Если у вас уже есть другой механизм синхронизации, возможно, вам не нужен мьютекс. Другими словами, если у ваших задач есть разные временные интервалы, в которых они используют ресурс, то они уже синхронны. Если они не будут пытаться использовать ресурс в случайное время, вам может не понадобиться мьютекс.

Ваш дизайн также кажется сложным, и мне интересно, может ли этот альтернативный дизайн быть проще.

Попробуйте создать одну задачу, отвечающую за интерфейс ЖК-дисплея. Эта задача НРС является единственной задачей, которая будет взаимодействовать с дисплеем. Ваши задачи данных будут отправлять сообщения на ЖК-задачу, когда они производят данные для отображения. Задача LCD будет просто ждать этих сообщений и отображать данные соответствующим образом, когда они поступят. Вы можете использовать либо Очередь сообщений, либо Очередь почты для этой службы сообщений, в зависимости от сложности и разнообразия данных. Теперь вам не нужен мьютекс для ЖК-дисплея, потому что есть только одна задача, которая его использует. И вам все еще нужен 50/10 второй раз с этим дизайном? Я не уверен, потому что я не знаю, что было источником этого требования.

Вместо того, чтобы иметь несколько потоков, обращающихся к одному ресурсу, арбитражируемым мьютексами, было бы проще иметь один поток, обрабатывающий ресурс.

В этом случае я предлагаю поток диспетчера отображения, другие потоки могут зарегистрироваться в диспетчере отображения, предоставляя, возможно, указатель на буфер отображения и требуемый период отображения. Диспетчер отображения затем просто циклически просматривает каждый зарегистрированный поток, отображающий его буфер на требуемый период, прежде чем переключиться на следующий.

Например (псевдокод):

static struct 
{
    const char* frame_buffer ;
    int display_seconds ;
    OS_MUTEX mutex ;

} display_registry[MAX_DISPLAY_THREADS] = {0,0} ;

void displayLock( int handle )
{
    if( handle >= 0 && handle < MAX_DISPLAY_THREADS )
    {
        os_mutex_lock( display_registry[handle].mutex ) ;
    }
}

void displayUnock( int handle )
{
    if( handle >= 0 && handle < MAX_DISPLAY_THREADS )
    {
        os_mutex_unlock( display_registry[handle].mutex ) ;
    }
}

void lcd_thread
{
    int display = 0 ;

    for(;;)
    {
        int t = 0 ;
        while( t < display_registry[display].display_seconds &&
               display_registry[display].frame_buffer != 0 )
        {
            displayLock( display ) ;
            render_display( display_registry[display].frame_buffer ) ;
            displayUnlock( display ) ;

            delay( ONE_SECOND ) ;
        }

        display = (display + 1) % MAX_DISPLAY_THREADS ;
    }
}

int displayRegister( const char* frame_buffer, int display_seconds )
{
    for( int i = MAX_DISPLAY_THREADS - 1; 
         frame_buffer[i] != 0 && 
         i >= 0; i-- )
    {
        // do nothing
    }

    if( i >= 0 )
    {
        display_registry[i].display_seconds = display_seconds ;
        display_registry[i].frame_buffer = frame_buffer ;
    }

    return i ; // handle for de-registering/locking
}

void displayDeregister( int handle )
{
    if( handle >= 0 && handle < MAX_DISPLAY_THREADS )
    {
        display_registry[handle].frame_buffer = 0 ;
    }
}

Обратите внимание, что мьютексы предназначены не для блокировки ресурса LCD, а для блокировки ресурсов буфера фрейма общей памяти.

Затем другие потоки просто помещают данные для отображения в свои собственные буферы кадров, полностью асинхронно с отображением этих данных, например, следующим образом:

displayLock( my_display_handle ) ;
update_display_buffer() ;
displayUnlock( my_display_handle ) ;

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

Наконец, выдайте задачу в обработчике события таймера (вызывается после временного интервала).

Если вы не знаете о yield, yield - это способ отказаться от выполнения задачи, чтобы планировщик мог перейти к следующей задаче.

Другие вопросы по тегам